@open-mercato/core 0.5.1-develop.2663.2c29774b5b → 0.5.1-develop.2681.c559bb2bc3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (687) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/action_log/index.js +8 -0
  3. package/dist/generated/entities/action_log/index.js.map +2 -2
  4. package/dist/generated/entities/customer_company_billing/index.js +23 -0
  5. package/dist/generated/entities/customer_company_billing/index.js.map +7 -0
  6. package/dist/generated/entities/customer_deal/index.js +8 -0
  7. package/dist/generated/entities/customer_deal/index.js.map +2 -2
  8. package/dist/generated/entities/customer_deal_stage_transition/index.js +31 -0
  9. package/dist/generated/entities/customer_deal_stage_transition/index.js.map +7 -0
  10. package/dist/generated/entities/customer_dictionary_kind_setting/index.js +21 -0
  11. package/dist/generated/entities/customer_dictionary_kind_setting/index.js.map +7 -0
  12. package/dist/generated/entities/customer_entity/index.js +8 -0
  13. package/dist/generated/entities/customer_entity/index.js.map +2 -2
  14. package/dist/generated/entities/customer_entity_role/index.js +23 -0
  15. package/dist/generated/entities/customer_entity_role/index.js.map +7 -0
  16. package/dist/generated/entities/customer_interaction/index.js +23 -1
  17. package/dist/generated/entities/customer_interaction/index.js.map +2 -2
  18. package/dist/generated/entities/customer_label/index.js +19 -0
  19. package/dist/generated/entities/customer_label/index.js.map +7 -0
  20. package/dist/generated/entities/customer_label_assignment/index.js +17 -0
  21. package/dist/generated/entities/customer_label_assignment/index.js.map +7 -0
  22. package/dist/generated/entities/customer_person_company_link/index.js +21 -0
  23. package/dist/generated/entities/customer_person_company_link/index.js.map +7 -0
  24. package/dist/generated/entities/customer_person_company_role/index.js +17 -0
  25. package/dist/generated/entities/customer_person_company_role/index.js.map +7 -0
  26. package/dist/generated/entities/dictionary_entry/index.js +4 -0
  27. package/dist/generated/entities/dictionary_entry/index.js.map +2 -2
  28. package/dist/generated/entities.ids.generated.js +9 -1
  29. package/dist/generated/entities.ids.generated.js.map +2 -2
  30. package/dist/generated/entity-fields-registry.js +116 -1
  31. package/dist/generated/entity-fields-registry.js.map +2 -2
  32. package/dist/modules/attachments/api/route.js +46 -8
  33. package/dist/modules/attachments/api/route.js.map +2 -2
  34. package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js +208 -0
  35. package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js.map +7 -0
  36. package/dist/modules/audit_logs/api/audit-logs/actions/route.js +52 -6
  37. package/dist/modules/audit_logs/api/audit-logs/actions/route.js.map +2 -2
  38. package/dist/modules/audit_logs/cli.js +62 -0
  39. package/dist/modules/audit_logs/cli.js.map +7 -0
  40. package/dist/modules/audit_logs/data/entities.js +21 -1
  41. package/dist/modules/audit_logs/data/entities.js.map +2 -2
  42. package/dist/modules/audit_logs/data/validators.js +9 -1
  43. package/dist/modules/audit_logs/data/validators.js.map +2 -2
  44. package/dist/modules/audit_logs/lib/changeRows.js +34 -0
  45. package/dist/modules/audit_logs/lib/changeRows.js.map +7 -0
  46. package/dist/modules/audit_logs/lib/display-helpers.js +2 -20
  47. package/dist/modules/audit_logs/lib/display-helpers.js.map +3 -3
  48. package/dist/modules/audit_logs/lib/projections.js +58 -0
  49. package/dist/modules/audit_logs/lib/projections.js.map +7 -0
  50. package/dist/modules/audit_logs/migrations/Migration20260412160533.js +21 -0
  51. package/dist/modules/audit_logs/migrations/Migration20260412160533.js.map +7 -0
  52. package/dist/modules/audit_logs/services/actionLogService.js +313 -79
  53. package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
  54. package/dist/modules/customers/acl.js +3 -1
  55. package/dist/modules/customers/acl.js.map +2 -2
  56. package/dist/modules/customers/api/activities/route.js +4 -0
  57. package/dist/modules/customers/api/activities/route.js.map +2 -2
  58. package/dist/modules/customers/api/assignable-staff/route.js +208 -0
  59. package/dist/modules/customers/api/assignable-staff/route.js.map +7 -0
  60. package/dist/modules/customers/api/companies/[id]/people/route.js +205 -0
  61. package/dist/modules/customers/api/companies/[id]/people/route.js.map +7 -0
  62. package/dist/modules/customers/api/companies/[id]/roles/route.js +22 -0
  63. package/dist/modules/customers/api/companies/[id]/roles/route.js.map +7 -0
  64. package/dist/modules/customers/api/companies/[id]/route.js +374 -32
  65. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  66. package/dist/modules/customers/api/companies/route.js +82 -7
  67. package/dist/modules/customers/api/companies/route.js.map +2 -2
  68. package/dist/modules/customers/api/deals/[id]/companies/route.js +172 -0
  69. package/dist/modules/customers/api/deals/[id]/companies/route.js.map +7 -0
  70. package/dist/modules/customers/api/deals/[id]/people/route.js +156 -0
  71. package/dist/modules/customers/api/deals/[id]/people/route.js.map +7 -0
  72. package/dist/modules/customers/api/deals/[id]/route.js +459 -53
  73. package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
  74. package/dist/modules/customers/api/deals/[id]/stats/route.js +195 -0
  75. package/dist/modules/customers/api/deals/[id]/stats/route.js.map +7 -0
  76. package/dist/modules/customers/api/deals/route.js +20 -10
  77. package/dist/modules/customers/api/deals/route.js.map +3 -3
  78. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +105 -4
  79. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
  80. package/dist/modules/customers/api/dictionaries/[kind]/route.js +118 -42
  81. package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
  82. package/dist/modules/customers/api/dictionaries/context.js +30 -6
  83. package/dist/modules/customers/api/dictionaries/context.js.map +2 -2
  84. package/dist/modules/customers/api/dictionaries/kind-settings/route.js +207 -0
  85. package/dist/modules/customers/api/dictionaries/kind-settings/route.js.map +7 -0
  86. package/dist/modules/customers/api/entity-roles-factory.js +471 -0
  87. package/dist/modules/customers/api/entity-roles-factory.js.map +7 -0
  88. package/dist/modules/customers/api/interactions/conflicts/route.js +158 -0
  89. package/dist/modules/customers/api/interactions/conflicts/route.js.map +7 -0
  90. package/dist/modules/customers/api/interactions/counts/route.js +92 -0
  91. package/dist/modules/customers/api/interactions/counts/route.js.map +7 -0
  92. package/dist/modules/customers/api/interactions/route.js +83 -4
  93. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  94. package/dist/modules/customers/api/labels/assign/route.js +189 -0
  95. package/dist/modules/customers/api/labels/assign/route.js.map +7 -0
  96. package/dist/modules/customers/api/labels/auth.js +17 -0
  97. package/dist/modules/customers/api/labels/auth.js.map +7 -0
  98. package/dist/modules/customers/api/labels/route.js +281 -0
  99. package/dist/modules/customers/api/labels/route.js.map +7 -0
  100. package/dist/modules/customers/api/labels/table-errors.js +38 -0
  101. package/dist/modules/customers/api/labels/table-errors.js.map +7 -0
  102. package/dist/modules/customers/api/labels/unassign/route.js +184 -0
  103. package/dist/modules/customers/api/labels/unassign/route.js.map +7 -0
  104. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +292 -0
  105. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +7 -0
  106. package/dist/modules/customers/api/people/[id]/companies/context.js +66 -0
  107. package/dist/modules/customers/api/people/[id]/companies/context.js.map +7 -0
  108. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +334 -0
  109. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +7 -0
  110. package/dist/modules/customers/api/people/[id]/companies/route.js +205 -0
  111. package/dist/modules/customers/api/people/[id]/companies/route.js.map +7 -0
  112. package/dist/modules/customers/api/people/[id]/roles/route.js +22 -0
  113. package/dist/modules/customers/api/people/[id]/roles/route.js.map +7 -0
  114. package/dist/modules/customers/api/people/[id]/route.js +134 -21
  115. package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
  116. package/dist/modules/customers/api/people/route.js +122 -23
  117. package/dist/modules/customers/api/people/route.js.map +2 -2
  118. package/dist/modules/customers/api/todos/route.js +4 -0
  119. package/dist/modules/customers/api/todos/route.js.map +2 -2
  120. package/dist/modules/customers/api/utils.js +22 -0
  121. package/dist/modules/customers/api/utils.js.map +2 -2
  122. package/dist/modules/customers/backend/config/customers/page.js +2 -6
  123. package/dist/modules/customers/backend/config/customers/page.js.map +2 -2
  124. package/dist/modules/customers/backend/customers/companies/page.js +37 -26
  125. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  126. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +265 -262
  127. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +3 -3
  128. package/dist/modules/customers/backend/customers/deals/[id]/hooks/formatters.js +23 -0
  129. package/dist/modules/customers/backend/customers/deals/[id]/hooks/formatters.js.map +7 -0
  130. package/dist/modules/customers/backend/customers/deals/[id]/hooks/types.js +1 -0
  131. package/dist/modules/customers/backend/customers/deals/[id]/hooks/types.js.map +7 -0
  132. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js +43 -0
  133. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js.map +7 -0
  134. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +264 -0
  135. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +7 -0
  136. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +88 -0
  137. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +7 -0
  138. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealData.js +41 -0
  139. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealData.js.map +7 -0
  140. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js +66 -0
  141. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js.map +7 -0
  142. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.js +39 -0
  143. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.js.map +7 -0
  144. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealMutationContext.js +49 -0
  145. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealMutationContext.js.map +7 -0
  146. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js +43 -0
  147. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js.map +7 -0
  148. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useScheduleDialog.js +28 -0
  149. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useScheduleDialog.js.map +7 -0
  150. package/dist/modules/customers/backend/customers/deals/[id]/page.js +556 -503
  151. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +3 -3
  152. package/dist/modules/customers/backend/customers/deals/page.js +66 -21
  153. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  154. package/dist/modules/customers/backend/customers/people/page.js +36 -28
  155. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  156. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +318 -203
  157. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +3 -3
  158. package/dist/modules/customers/cli.js +105 -13
  159. package/dist/modules/customers/cli.js.map +2 -2
  160. package/dist/modules/customers/commands/activities.js +6 -0
  161. package/dist/modules/customers/commands/activities.js.map +2 -2
  162. package/dist/modules/customers/commands/deals.js +315 -107
  163. package/dist/modules/customers/commands/deals.js.map +2 -2
  164. package/dist/modules/customers/commands/dictionaries.js +166 -32
  165. package/dist/modules/customers/commands/dictionaries.js.map +2 -2
  166. package/dist/modules/customers/commands/dictionaryKindSettings.js +208 -0
  167. package/dist/modules/customers/commands/dictionaryKindSettings.js.map +7 -0
  168. package/dist/modules/customers/commands/entity-roles.js +415 -0
  169. package/dist/modules/customers/commands/entity-roles.js.map +7 -0
  170. package/dist/modules/customers/commands/index.js +4 -0
  171. package/dist/modules/customers/commands/index.js.map +2 -2
  172. package/dist/modules/customers/commands/interactions.js +108 -21
  173. package/dist/modules/customers/commands/interactions.js.map +2 -2
  174. package/dist/modules/customers/commands/labels.js +539 -0
  175. package/dist/modules/customers/commands/labels.js.map +7 -0
  176. package/dist/modules/customers/commands/people.js +560 -463
  177. package/dist/modules/customers/commands/people.js.map +3 -3
  178. package/dist/modules/customers/commands/personCompanyLinks.js +568 -0
  179. package/dist/modules/customers/commands/personCompanyLinks.js.map +7 -0
  180. package/dist/modules/customers/commands/shared.js +12 -4
  181. package/dist/modules/customers/commands/shared.js.map +2 -2
  182. package/dist/modules/customers/commands/todos.js +10 -1
  183. package/dist/modules/customers/commands/todos.js.map +2 -2
  184. package/dist/modules/customers/components/AddressEditor.js +1 -1
  185. package/dist/modules/customers/components/AddressEditor.js.map +2 -2
  186. package/dist/modules/customers/components/CustomersConfigurationSections.js +31 -0
  187. package/dist/modules/customers/components/CustomersConfigurationSections.js.map +7 -0
  188. package/dist/modules/customers/components/DictionarySettings.js +37 -2
  189. package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
  190. package/dist/modules/customers/components/detail/ActiveDealCard.js +121 -0
  191. package/dist/modules/customers/components/detail/ActiveDealCard.js.map +7 -0
  192. package/dist/modules/customers/components/detail/ActivitiesSection.js +222 -331
  193. package/dist/modules/customers/components/detail/ActivitiesSection.js.map +3 -3
  194. package/dist/modules/customers/components/detail/ActivityAiActions.js +36 -0
  195. package/dist/modules/customers/components/detail/ActivityAiActions.js.map +7 -0
  196. package/dist/modules/customers/components/detail/ActivityCard.js +126 -0
  197. package/dist/modules/customers/components/detail/ActivityCard.js.map +7 -0
  198. package/dist/modules/customers/components/detail/ActivityHistorySection.js +340 -0
  199. package/dist/modules/customers/components/detail/ActivityHistorySection.js.map +7 -0
  200. package/dist/modules/customers/components/detail/ActivityLogTab.js +56 -0
  201. package/dist/modules/customers/components/detail/ActivityLogTab.js.map +7 -0
  202. package/dist/modules/customers/components/detail/ActivityTimeline.js +108 -0
  203. package/dist/modules/customers/components/detail/ActivityTimeline.js.map +7 -0
  204. package/dist/modules/customers/components/detail/ActivityTimelineFilters.js +139 -0
  205. package/dist/modules/customers/components/detail/ActivityTimelineFilters.js.map +7 -0
  206. package/dist/modules/customers/components/detail/ActivityTypeSelector.js +42 -0
  207. package/dist/modules/customers/components/detail/ActivityTypeSelector.js.map +7 -0
  208. package/dist/modules/customers/components/detail/AiActionChips.js +38 -0
  209. package/dist/modules/customers/components/detail/AiActionChips.js.map +7 -0
  210. package/dist/modules/customers/components/detail/AssignRoleDialog.js +534 -0
  211. package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +7 -0
  212. package/dist/modules/customers/components/detail/ChangelogEntryRow.js +79 -0
  213. package/dist/modules/customers/components/detail/ChangelogEntryRow.js.map +7 -0
  214. package/dist/modules/customers/components/detail/ChangelogFilters.js +176 -0
  215. package/dist/modules/customers/components/detail/ChangelogFilters.js.map +7 -0
  216. package/dist/modules/customers/components/detail/ChangelogKpiCards.js +88 -0
  217. package/dist/modules/customers/components/detail/ChangelogKpiCards.js.map +7 -0
  218. package/dist/modules/customers/components/detail/ChangelogTab.js +470 -0
  219. package/dist/modules/customers/components/detail/ChangelogTab.js.map +7 -0
  220. package/dist/modules/customers/components/detail/ComingSoonPlaceholder.js +16 -0
  221. package/dist/modules/customers/components/detail/ComingSoonPlaceholder.js.map +7 -0
  222. package/dist/modules/customers/components/detail/CompanyCard.js +283 -0
  223. package/dist/modules/customers/components/detail/CompanyCard.js.map +7 -0
  224. package/dist/modules/customers/components/detail/CompanyDashboardTab.js +133 -0
  225. package/dist/modules/customers/components/detail/CompanyDashboardTab.js.map +7 -0
  226. package/dist/modules/customers/components/detail/CompanyDetailHeader.js +191 -0
  227. package/dist/modules/customers/components/detail/CompanyDetailHeader.js.map +7 -0
  228. package/dist/modules/customers/components/detail/CompanyDetailTabs.js +123 -0
  229. package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +7 -0
  230. package/dist/modules/customers/components/detail/CompanyKpiBar.js +174 -0
  231. package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +7 -0
  232. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +514 -230
  233. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  234. package/dist/modules/customers/components/detail/CompanyTagsDialog.js +22 -0
  235. package/dist/modules/customers/components/detail/CompanyTagsDialog.js.map +7 -0
  236. package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js +159 -0
  237. package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js.map +7 -0
  238. package/dist/modules/customers/components/detail/CreatePersonDialog.js +135 -0
  239. package/dist/modules/customers/components/detail/CreatePersonDialog.js.map +7 -0
  240. package/dist/modules/customers/components/detail/DealClosureActionBar.js +59 -0
  241. package/dist/modules/customers/components/detail/DealClosureActionBar.js.map +7 -0
  242. package/dist/modules/customers/components/detail/DealDetailHeader.js +237 -0
  243. package/dist/modules/customers/components/detail/DealDetailHeader.js.map +7 -0
  244. package/dist/modules/customers/components/detail/DealDetailTabs.js +109 -0
  245. package/dist/modules/customers/components/detail/DealDetailTabs.js.map +7 -0
  246. package/dist/modules/customers/components/detail/DealForm.js +219 -92
  247. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  248. package/dist/modules/customers/components/detail/DealLinkedEntitiesTab.js +295 -0
  249. package/dist/modules/customers/components/detail/DealLinkedEntitiesTab.js.map +7 -0
  250. package/dist/modules/customers/components/detail/DealLostSummaryDialog.js +107 -0
  251. package/dist/modules/customers/components/detail/DealLostSummaryDialog.js.map +7 -0
  252. package/dist/modules/customers/components/detail/DealWonPopup.js +113 -0
  253. package/dist/modules/customers/components/detail/DealWonPopup.js.map +7 -0
  254. package/dist/modules/customers/components/detail/DealsSection.js +206 -193
  255. package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
  256. package/dist/modules/customers/components/detail/DecisionMakersFooter.js +39 -0
  257. package/dist/modules/customers/components/detail/DecisionMakersFooter.js.map +7 -0
  258. package/dist/modules/customers/components/detail/EntityTagsDialog.js +1096 -0
  259. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +7 -0
  260. package/dist/modules/customers/components/detail/InlineActivityComposer.js +197 -0
  261. package/dist/modules/customers/components/detail/InlineActivityComposer.js.map +7 -0
  262. package/dist/modules/customers/components/detail/ManageTagsDialog.js +1091 -0
  263. package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +7 -0
  264. package/dist/modules/customers/components/detail/MiniWeekCalendar.js +272 -0
  265. package/dist/modules/customers/components/detail/MiniWeekCalendar.js.map +7 -0
  266. package/dist/modules/customers/components/detail/MobilePersonDetail.js +106 -0
  267. package/dist/modules/customers/components/detail/MobilePersonDetail.js.map +7 -0
  268. package/dist/modules/customers/components/detail/NextStepCard.js +72 -0
  269. package/dist/modules/customers/components/detail/NextStepCard.js.map +7 -0
  270. package/dist/modules/customers/components/detail/PersonCard.js +192 -0
  271. package/dist/modules/customers/components/detail/PersonCard.js.map +7 -0
  272. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +345 -0
  273. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +7 -0
  274. package/dist/modules/customers/components/detail/PersonDetailHeader.js +220 -0
  275. package/dist/modules/customers/components/detail/PersonDetailHeader.js.map +7 -0
  276. package/dist/modules/customers/components/detail/PersonDetailTabs.js +122 -0
  277. package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +7 -0
  278. package/dist/modules/customers/components/detail/PersonTagsDialog.js +24 -0
  279. package/dist/modules/customers/components/detail/PersonTagsDialog.js.map +7 -0
  280. package/dist/modules/customers/components/detail/PipelineStepper.js +191 -0
  281. package/dist/modules/customers/components/detail/PipelineStepper.js.map +7 -0
  282. package/dist/modules/customers/components/detail/PlannedActivitiesSection.js +222 -0
  283. package/dist/modules/customers/components/detail/PlannedActivitiesSection.js.map +7 -0
  284. package/dist/modules/customers/components/detail/RelationshipHealthCard.js +49 -0
  285. package/dist/modules/customers/components/detail/RelationshipHealthCard.js.map +7 -0
  286. package/dist/modules/customers/components/detail/RoleAssignmentRow.js +189 -0
  287. package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +7 -0
  288. package/dist/modules/customers/components/detail/RolesSection.js +234 -0
  289. package/dist/modules/customers/components/detail/RolesSection.js.map +7 -0
  290. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +410 -0
  291. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +7 -0
  292. package/dist/modules/customers/components/detail/aiActionCatalog.js +41 -0
  293. package/dist/modules/customers/components/detail/aiActionCatalog.js.map +7 -0
  294. package/dist/modules/customers/components/detail/assignableStaff.js +48 -0
  295. package/dist/modules/customers/components/detail/assignableStaff.js.map +7 -0
  296. package/dist/modules/customers/components/detail/dashboard/ActiveDealWidget.js +48 -0
  297. package/dist/modules/customers/components/detail/dashboard/ActiveDealWidget.js.map +7 -0
  298. package/dist/modules/customers/components/detail/dashboard/OpenTasksWidget.js +86 -0
  299. package/dist/modules/customers/components/detail/dashboard/OpenTasksWidget.js.map +7 -0
  300. package/dist/modules/customers/components/detail/dashboard/RecentActivityWidget.js +53 -0
  301. package/dist/modules/customers/components/detail/dashboard/RecentActivityWidget.js.map +7 -0
  302. package/dist/modules/customers/components/detail/dashboard/RelationshipHealthWidget.js +30 -0
  303. package/dist/modules/customers/components/detail/dashboard/RelationshipHealthWidget.js.map +7 -0
  304. package/dist/modules/customers/components/detail/dashboard/UpcomingMeetingsWidget.js +43 -0
  305. package/dist/modules/customers/components/detail/dashboard/UpcomingMeetingsWidget.js.map +7 -0
  306. package/dist/modules/customers/components/detail/dashboard/helpers.js +71 -0
  307. package/dist/modules/customers/components/detail/dashboard/helpers.js.map +7 -0
  308. package/dist/modules/customers/components/detail/healthScoreUtils.js +69 -0
  309. package/dist/modules/customers/components/detail/healthScoreUtils.js.map +7 -0
  310. package/dist/modules/customers/components/detail/hooks/useCurrencyDictionary.js +5 -5
  311. package/dist/modules/customers/components/detail/hooks/useCurrencyDictionary.js.map +2 -2
  312. package/dist/modules/customers/components/detail/hooks/useCustomerDictionary.js +9 -8
  313. package/dist/modules/customers/components/detail/hooks/useCustomerDictionary.js.map +3 -3
  314. package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +65 -0
  315. package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +7 -0
  316. package/dist/modules/customers/components/detail/notesAdapter.js +70 -30
  317. package/dist/modules/customers/components/detail/notesAdapter.js.map +2 -2
  318. package/dist/modules/customers/components/detail/pipelineStageUtils.js +26 -0
  319. package/dist/modules/customers/components/detail/pipelineStageUtils.js.map +7 -0
  320. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +144 -0
  321. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +7 -0
  322. package/dist/modules/customers/components/detail/schedule/FooterFields.js +60 -0
  323. package/dist/modules/customers/components/detail/schedule/FooterFields.js.map +7 -0
  324. package/dist/modules/customers/components/detail/schedule/LinkedEntitiesField.js +216 -0
  325. package/dist/modules/customers/components/detail/schedule/LinkedEntitiesField.js.map +7 -0
  326. package/dist/modules/customers/components/detail/schedule/LocationField.js +34 -0
  327. package/dist/modules/customers/components/detail/schedule/LocationField.js.map +7 -0
  328. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +226 -0
  329. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +7 -0
  330. package/dist/modules/customers/components/detail/schedule/fieldConfig.js +69 -0
  331. package/dist/modules/customers/components/detail/schedule/fieldConfig.js.map +7 -0
  332. package/dist/modules/customers/components/detail/schedule/index.js +21 -0
  333. package/dist/modules/customers/components/detail/schedule/index.js.map +7 -0
  334. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +172 -0
  335. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +7 -0
  336. package/dist/modules/customers/components/detail/utils.js +23 -0
  337. package/dist/modules/customers/components/detail/utils.js.map +2 -2
  338. package/dist/modules/customers/components/formConfig.js +144 -22
  339. package/dist/modules/customers/components/formConfig.js.map +2 -2
  340. package/dist/modules/customers/components/linking/LinkEntityDialog.js +661 -0
  341. package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +7 -0
  342. package/dist/modules/customers/components/linking/adapters/companyAdapter.js +252 -0
  343. package/dist/modules/customers/components/linking/adapters/companyAdapter.js.map +7 -0
  344. package/dist/modules/customers/components/linking/adapters/dealAdapter.js +384 -0
  345. package/dist/modules/customers/components/linking/adapters/dealAdapter.js.map +7 -0
  346. package/dist/modules/customers/components/linking/adapters/personAdapter.js +324 -0
  347. package/dist/modules/customers/components/linking/adapters/personAdapter.js.map +7 -0
  348. package/dist/modules/customers/components/list/CollectionPreviewCell.js +53 -0
  349. package/dist/modules/customers/components/list/CollectionPreviewCell.js.map +7 -0
  350. package/dist/modules/customers/data/entities.js +407 -1
  351. package/dist/modules/customers/data/entities.js.map +2 -2
  352. package/dist/modules/customers/data/validators.js +139 -21
  353. package/dist/modules/customers/data/validators.js.map +2 -2
  354. package/dist/modules/customers/events.js +19 -1
  355. package/dist/modules/customers/events.js.map +2 -2
  356. package/dist/modules/customers/lib/customerRoleTypes.js +19 -0
  357. package/dist/modules/customers/lib/customerRoleTypes.js.map +7 -0
  358. package/dist/modules/customers/lib/dealClosureNotification.js +39 -0
  359. package/dist/modules/customers/lib/dealClosureNotification.js.map +7 -0
  360. package/dist/modules/customers/lib/dealStageTransitionTable.js +29 -0
  361. package/dist/modules/customers/lib/dealStageTransitionTable.js.map +7 -0
  362. package/dist/modules/customers/lib/dictionaries.js +25 -0
  363. package/dist/modules/customers/lib/dictionaries.js.map +2 -2
  364. package/dist/modules/customers/lib/interactionReadModel.js +10 -0
  365. package/dist/modules/customers/lib/interactionReadModel.js.map +2 -2
  366. package/dist/modules/customers/lib/personCompanies.js +235 -0
  367. package/dist/modules/customers/lib/personCompanies.js.map +7 -0
  368. package/dist/modules/customers/lib/personCompanyLinkTable.js +42 -0
  369. package/dist/modules/customers/lib/personCompanyLinkTable.js.map +7 -0
  370. package/dist/modules/customers/lib/roleTypeUsage.js +104 -0
  371. package/dist/modules/customers/lib/roleTypeUsage.js.map +7 -0
  372. package/dist/modules/customers/migrations/Migration20260406214502.js +18 -0
  373. package/dist/modules/customers/migrations/Migration20260406214502.js.map +7 -0
  374. package/dist/modules/customers/migrations/Migration20260408135736.js +17 -0
  375. package/dist/modules/customers/migrations/Migration20260408135736.js.map +7 -0
  376. package/dist/modules/customers/migrations/Migration20260408225345.js +21 -0
  377. package/dist/modules/customers/migrations/Migration20260408225345.js.map +7 -0
  378. package/dist/modules/customers/migrations/Migration20260411075533.js +27 -0
  379. package/dist/modules/customers/migrations/Migration20260411075533.js.map +7 -0
  380. package/dist/modules/customers/migrations/Migration20260411103551.js +13 -0
  381. package/dist/modules/customers/migrations/Migration20260411103551.js.map +7 -0
  382. package/dist/modules/customers/migrations/Migration20260411130944.js +26 -0
  383. package/dist/modules/customers/migrations/Migration20260411130944.js.map +7 -0
  384. package/dist/modules/customers/migrations/Migration20260415095203.js +13 -0
  385. package/dist/modules/customers/migrations/Migration20260415095203.js.map +7 -0
  386. package/dist/modules/customers/migrations/Migration20260415135056.js +20 -0
  387. package/dist/modules/customers/migrations/Migration20260415135056.js.map +7 -0
  388. package/dist/modules/customers/migrations/Migration20260417140000.js +15 -0
  389. package/dist/modules/customers/migrations/Migration20260417140000.js.map +7 -0
  390. package/dist/modules/customers/migrations/Migration20260417160000.js +17 -0
  391. package/dist/modules/customers/migrations/Migration20260417160000.js.map +7 -0
  392. package/dist/modules/customers/migrations/Migration20260417235407.js +13 -0
  393. package/dist/modules/customers/migrations/Migration20260417235407.js.map +7 -0
  394. package/dist/modules/customers/setup.js +16 -1
  395. package/dist/modules/customers/setup.js.map +2 -2
  396. package/dist/modules/customers/subscribers/deal-closure-notification.js +16 -0
  397. package/dist/modules/customers/subscribers/deal-closure-notification.js.map +7 -0
  398. package/dist/modules/customers/subscribers/deal-lost-notification.js +16 -0
  399. package/dist/modules/customers/subscribers/deal-lost-notification.js.map +7 -0
  400. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +2 -0
  401. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  402. package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js +154 -0
  403. package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js.map +7 -0
  404. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +6 -2
  405. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
  406. package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js +154 -0
  407. package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js.map +7 -0
  408. package/dist/modules/dictionaries/api/context.js +8 -1
  409. package/dist/modules/dictionaries/api/context.js.map +2 -2
  410. package/dist/modules/dictionaries/api/openapi.js +18 -1
  411. package/dist/modules/dictionaries/api/openapi.js.map +2 -2
  412. package/dist/modules/dictionaries/commands/entry-operations.js +388 -0
  413. package/dist/modules/dictionaries/commands/entry-operations.js.map +7 -0
  414. package/dist/modules/dictionaries/commands/factory.js +24 -3
  415. package/dist/modules/dictionaries/commands/factory.js.map +2 -2
  416. package/dist/modules/dictionaries/commands/index.js +1 -0
  417. package/dist/modules/dictionaries/commands/index.js.map +2 -2
  418. package/dist/modules/dictionaries/components/DictionaryTable.js +6 -3
  419. package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
  420. package/dist/modules/dictionaries/data/entities.js +11 -1
  421. package/dist/modules/dictionaries/data/entities.js.map +2 -2
  422. package/dist/modules/dictionaries/data/validators.js +28 -2
  423. package/dist/modules/dictionaries/data/validators.js.map +2 -2
  424. package/dist/modules/dictionaries/events.js +18 -0
  425. package/dist/modules/dictionaries/events.js.map +7 -0
  426. package/dist/modules/dictionaries/lib/clientEntries.js +43 -0
  427. package/dist/modules/dictionaries/lib/clientEntries.js.map +7 -0
  428. package/dist/modules/dictionaries/migrations/Migration20260410171544.js +45 -0
  429. package/dist/modules/dictionaries/migrations/Migration20260410171544.js.map +7 -0
  430. package/dist/modules/inbox_ops/api/proposals/[id]/route.js +4 -1
  431. package/dist/modules/inbox_ops/api/proposals/[id]/route.js.map +2 -2
  432. package/dist/modules/query_index/lib/engine.js +1 -1
  433. package/dist/modules/query_index/lib/engine.js.map +2 -2
  434. package/dist/modules/sales/components/documents/AddressesSection.js +82 -42
  435. package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
  436. package/dist/modules/sales/lib/dictionaries.js +16 -0
  437. package/dist/modules/sales/lib/dictionaries.js.map +2 -2
  438. package/dist/modules/sales/widgets/injection-table.js +5 -1
  439. package/dist/modules/sales/widgets/injection-table.js.map +2 -2
  440. package/generated/entities/action_log/index.ts +4 -0
  441. package/generated/entities/customer_company_billing/index.ts +10 -0
  442. package/generated/entities/customer_deal/index.ts +4 -0
  443. package/generated/entities/customer_deal_stage_transition/index.ts +14 -0
  444. package/generated/entities/customer_dictionary_kind_setting/index.ts +9 -0
  445. package/generated/entities/customer_entity/index.ts +4 -0
  446. package/generated/entities/customer_entity_role/index.ts +10 -0
  447. package/generated/entities/customer_interaction/index.ts +11 -0
  448. package/generated/entities/customer_label/index.ts +8 -0
  449. package/generated/entities/customer_label_assignment/index.ts +7 -0
  450. package/generated/entities/customer_person_company_link/index.ts +9 -0
  451. package/generated/entities/customer_person_company_role/index.ts +7 -0
  452. package/generated/entities/dictionary_entry/index.ts +2 -0
  453. package/generated/entities.ids.generated.ts +9 -1
  454. package/generated/entity-fields-registry.ts +116 -1
  455. package/package.json +3 -3
  456. package/src/modules/attachments/api/route.ts +48 -6
  457. package/src/modules/attachments/i18n/de.json +4 -0
  458. package/src/modules/attachments/i18n/en.json +4 -0
  459. package/src/modules/attachments/i18n/es.json +4 -0
  460. package/src/modules/attachments/i18n/pl.json +4 -0
  461. package/src/modules/audit_logs/api/audit-logs/actions/export/route.ts +260 -0
  462. package/src/modules/audit_logs/api/audit-logs/actions/route.ts +81 -6
  463. package/src/modules/audit_logs/cli.ts +79 -0
  464. package/src/modules/audit_logs/data/entities.ts +17 -0
  465. package/src/modules/audit_logs/data/validators.ts +9 -1
  466. package/src/modules/audit_logs/lib/changeRows.ts +47 -0
  467. package/src/modules/audit_logs/lib/display-helpers.tsx +4 -30
  468. package/src/modules/audit_logs/lib/projections.ts +110 -0
  469. package/src/modules/audit_logs/migrations/.snapshot-open-mercato.json +325 -2
  470. package/src/modules/audit_logs/migrations/Migration20260412160533.ts +21 -0
  471. package/src/modules/audit_logs/services/actionLogService.ts +455 -85
  472. package/src/modules/catalog/i18n/de.json +1 -0
  473. package/src/modules/catalog/i18n/en.json +1 -0
  474. package/src/modules/catalog/i18n/es.json +1 -0
  475. package/src/modules/catalog/i18n/pl.json +1 -0
  476. package/src/modules/customer_accounts/i18n/de.json +2 -0
  477. package/src/modules/customer_accounts/i18n/en.json +2 -0
  478. package/src/modules/customer_accounts/i18n/es.json +2 -0
  479. package/src/modules/customer_accounts/i18n/pl.json +2 -0
  480. package/src/modules/customers/acl.ts +2 -0
  481. package/src/modules/customers/api/activities/route.ts +4 -0
  482. package/src/modules/customers/api/assignable-staff/route.ts +250 -0
  483. package/src/modules/customers/api/companies/[id]/people/route.ts +244 -0
  484. package/src/modules/customers/api/companies/[id]/roles/route.ts +15 -0
  485. package/src/modules/customers/api/companies/[id]/route.ts +458 -40
  486. package/src/modules/customers/api/companies/route.ts +93 -15
  487. package/src/modules/customers/api/deals/[id]/companies/route.ts +203 -0
  488. package/src/modules/customers/api/deals/[id]/people/route.ts +182 -0
  489. package/src/modules/customers/api/deals/[id]/route.ts +554 -57
  490. package/src/modules/customers/api/deals/[id]/stats/route.ts +221 -0
  491. package/src/modules/customers/api/deals/route.ts +35 -46
  492. package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +105 -3
  493. package/src/modules/customers/api/dictionaries/[kind]/route.ts +143 -44
  494. package/src/modules/customers/api/dictionaries/context.ts +45 -16
  495. package/src/modules/customers/api/dictionaries/kind-settings/route.ts +232 -0
  496. package/src/modules/customers/api/entity-roles-factory.ts +520 -0
  497. package/src/modules/customers/api/interactions/conflicts/route.ts +196 -0
  498. package/src/modules/customers/api/interactions/counts/route.ts +112 -0
  499. package/src/modules/customers/api/interactions/route.ts +95 -2
  500. package/src/modules/customers/api/labels/assign/route.ts +202 -0
  501. package/src/modules/customers/api/labels/auth.ts +19 -0
  502. package/src/modules/customers/api/labels/route.ts +310 -0
  503. package/src/modules/customers/api/labels/table-errors.ts +36 -0
  504. package/src/modules/customers/api/labels/unassign/route.ts +197 -0
  505. package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +331 -0
  506. package/src/modules/customers/api/people/[id]/companies/context.ts +70 -0
  507. package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +384 -0
  508. package/src/modules/customers/api/people/[id]/companies/route.ts +215 -0
  509. package/src/modules/customers/api/people/[id]/roles/route.ts +15 -0
  510. package/src/modules/customers/api/people/[id]/route.ts +153 -26
  511. package/src/modules/customers/api/people/route.ts +134 -31
  512. package/src/modules/customers/api/todos/route.ts +4 -0
  513. package/src/modules/customers/api/utils.ts +36 -0
  514. package/src/modules/customers/backend/config/customers/page.tsx +2 -6
  515. package/src/modules/customers/backend/customers/companies/page.tsx +36 -26
  516. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +277 -262
  517. package/src/modules/customers/backend/customers/deals/[id]/hooks/formatters.ts +19 -0
  518. package/src/modules/customers/backend/customers/deals/[id]/hooks/types.ts +104 -0
  519. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.ts +60 -0
  520. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +362 -0
  521. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +113 -0
  522. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealData.ts +52 -0
  523. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.ts +86 -0
  524. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.tsx +60 -0
  525. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealMutationContext.ts +76 -0
  526. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.ts +56 -0
  527. package/src/modules/customers/backend/customers/deals/[id]/hooks/useScheduleDialog.ts +38 -0
  528. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +587 -624
  529. package/src/modules/customers/backend/customers/deals/page.tsx +71 -28
  530. package/src/modules/customers/backend/customers/people/page.tsx +35 -29
  531. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +343 -209
  532. package/src/modules/customers/cli.ts +107 -12
  533. package/src/modules/customers/commands/activities.ts +13 -0
  534. package/src/modules/customers/commands/deals.ts +386 -114
  535. package/src/modules/customers/commands/dictionaries.ts +175 -32
  536. package/src/modules/customers/commands/dictionaryKindSettings.ts +268 -0
  537. package/src/modules/customers/commands/entity-roles.ts +494 -0
  538. package/src/modules/customers/commands/index.ts +4 -0
  539. package/src/modules/customers/commands/interactions.ts +125 -21
  540. package/src/modules/customers/commands/labels.ts +626 -0
  541. package/src/modules/customers/commands/people.ts +373 -259
  542. package/src/modules/customers/commands/personCompanyLinks.ts +654 -0
  543. package/src/modules/customers/commands/shared.ts +16 -15
  544. package/src/modules/customers/commands/todos.ts +17 -1
  545. package/src/modules/customers/components/AddressEditor.tsx +1 -1
  546. package/src/modules/customers/components/CustomersConfigurationSections.tsx +36 -0
  547. package/src/modules/customers/components/DictionarySettings.tsx +43 -2
  548. package/src/modules/customers/components/detail/ActiveDealCard.tsx +175 -0
  549. package/src/modules/customers/components/detail/ActivitiesSection.tsx +267 -361
  550. package/src/modules/customers/components/detail/ActivityAiActions.tsx +49 -0
  551. package/src/modules/customers/components/detail/ActivityCard.tsx +154 -0
  552. package/src/modules/customers/components/detail/ActivityHistorySection.tsx +412 -0
  553. package/src/modules/customers/components/detail/ActivityLogTab.tsx +67 -0
  554. package/src/modules/customers/components/detail/ActivityTimeline.tsx +158 -0
  555. package/src/modules/customers/components/detail/ActivityTimelineFilters.tsx +163 -0
  556. package/src/modules/customers/components/detail/ActivityTypeSelector.tsx +53 -0
  557. package/src/modules/customers/components/detail/AiActionChips.tsx +48 -0
  558. package/src/modules/customers/components/detail/AssignRoleDialog.tsx +672 -0
  559. package/src/modules/customers/components/detail/ChangelogEntryRow.tsx +132 -0
  560. package/src/modules/customers/components/detail/ChangelogFilters.tsx +193 -0
  561. package/src/modules/customers/components/detail/ChangelogKpiCards.tsx +107 -0
  562. package/src/modules/customers/components/detail/ChangelogTab.tsx +629 -0
  563. package/src/modules/customers/components/detail/ComingSoonPlaceholder.tsx +21 -0
  564. package/src/modules/customers/components/detail/CompanyCard.tsx +419 -0
  565. package/src/modules/customers/components/detail/CompanyDashboardTab.tsx +161 -0
  566. package/src/modules/customers/components/detail/CompanyDetailHeader.tsx +243 -0
  567. package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +172 -0
  568. package/src/modules/customers/components/detail/CompanyKpiBar.tsx +206 -0
  569. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +582 -288
  570. package/src/modules/customers/components/detail/CompanyTagsDialog.tsx +23 -0
  571. package/src/modules/customers/components/detail/ConfirmDealLostDialog.tsx +210 -0
  572. package/src/modules/customers/components/detail/CreatePersonDialog.tsx +178 -0
  573. package/src/modules/customers/components/detail/DealClosureActionBar.tsx +63 -0
  574. package/src/modules/customers/components/detail/DealDetailHeader.tsx +335 -0
  575. package/src/modules/customers/components/detail/DealDetailTabs.tsx +154 -0
  576. package/src/modules/customers/components/detail/DealForm.tsx +253 -101
  577. package/src/modules/customers/components/detail/DealLinkedEntitiesTab.tsx +349 -0
  578. package/src/modules/customers/components/detail/DealLostSummaryDialog.tsx +156 -0
  579. package/src/modules/customers/components/detail/DealWonPopup.tsx +164 -0
  580. package/src/modules/customers/components/detail/DealsSection.tsx +276 -221
  581. package/src/modules/customers/components/detail/DecisionMakersFooter.tsx +56 -0
  582. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +1372 -0
  583. package/src/modules/customers/components/detail/InlineActivityComposer.tsx +239 -0
  584. package/src/modules/customers/components/detail/ManageTagsDialog.tsx +1331 -0
  585. package/src/modules/customers/components/detail/MiniWeekCalendar.tsx +338 -0
  586. package/src/modules/customers/components/detail/MobilePersonDetail.tsx +124 -0
  587. package/src/modules/customers/components/detail/NextStepCard.tsx +104 -0
  588. package/src/modules/customers/components/detail/PersonCard.tsx +238 -0
  589. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +426 -0
  590. package/src/modules/customers/components/detail/PersonDetailHeader.tsx +294 -0
  591. package/src/modules/customers/components/detail/PersonDetailTabs.tsx +172 -0
  592. package/src/modules/customers/components/detail/PersonTagsDialog.tsx +26 -0
  593. package/src/modules/customers/components/detail/PipelineStepper.tsx +245 -0
  594. package/src/modules/customers/components/detail/PlannedActivitiesSection.tsx +255 -0
  595. package/src/modules/customers/components/detail/RelationshipHealthCard.tsx +63 -0
  596. package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +248 -0
  597. package/src/modules/customers/components/detail/RolesSection.tsx +311 -0
  598. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +481 -0
  599. package/src/modules/customers/components/detail/aiActionCatalog.ts +77 -0
  600. package/src/modules/customers/components/detail/assignableStaff.ts +124 -0
  601. package/src/modules/customers/components/detail/dashboard/ActiveDealWidget.tsx +63 -0
  602. package/src/modules/customers/components/detail/dashboard/OpenTasksWidget.tsx +114 -0
  603. package/src/modules/customers/components/detail/dashboard/RecentActivityWidget.tsx +69 -0
  604. package/src/modules/customers/components/detail/dashboard/RelationshipHealthWidget.tsx +40 -0
  605. package/src/modules/customers/components/detail/dashboard/UpcomingMeetingsWidget.tsx +64 -0
  606. package/src/modules/customers/components/detail/dashboard/helpers.ts +78 -0
  607. package/src/modules/customers/components/detail/healthScoreUtils.ts +91 -0
  608. package/src/modules/customers/components/detail/hooks/useCurrencyDictionary.ts +8 -8
  609. package/src/modules/customers/components/detail/hooks/useCustomerDictionary.ts +10 -6
  610. package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +91 -0
  611. package/src/modules/customers/components/detail/notesAdapter.ts +91 -30
  612. package/src/modules/customers/components/detail/pipelineStageUtils.ts +29 -0
  613. package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +187 -0
  614. package/src/modules/customers/components/detail/schedule/FooterFields.tsx +79 -0
  615. package/src/modules/customers/components/detail/schedule/LinkedEntitiesField.tsx +277 -0
  616. package/src/modules/customers/components/detail/schedule/LocationField.tsx +42 -0
  617. package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +255 -0
  618. package/src/modules/customers/components/detail/schedule/fieldConfig.ts +70 -0
  619. package/src/modules/customers/components/detail/schedule/index.ts +9 -0
  620. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +221 -0
  621. package/src/modules/customers/components/detail/types.ts +16 -0
  622. package/src/modules/customers/components/detail/utils.ts +25 -0
  623. package/src/modules/customers/components/formConfig.tsx +223 -28
  624. package/src/modules/customers/components/linking/LinkEntityDialog.tsx +920 -0
  625. package/src/modules/customers/components/linking/adapters/companyAdapter.tsx +398 -0
  626. package/src/modules/customers/components/linking/adapters/dealAdapter.tsx +578 -0
  627. package/src/modules/customers/components/linking/adapters/personAdapter.tsx +512 -0
  628. package/src/modules/customers/components/list/CollectionPreviewCell.tsx +66 -0
  629. package/src/modules/customers/data/entities.ts +353 -1
  630. package/src/modules/customers/data/validators.ts +170 -19
  631. package/src/modules/customers/events.ts +22 -0
  632. package/src/modules/customers/i18n/de.json +841 -2
  633. package/src/modules/customers/i18n/en.json +841 -2
  634. package/src/modules/customers/i18n/es.json +840 -1
  635. package/src/modules/customers/i18n/pl.json +841 -2
  636. package/src/modules/customers/lib/customerRoleTypes.ts +24 -0
  637. package/src/modules/customers/lib/dealClosureNotification.ts +64 -0
  638. package/src/modules/customers/lib/dealStageTransitionTable.ts +32 -0
  639. package/src/modules/customers/lib/dictionaries.ts +26 -10
  640. package/src/modules/customers/lib/interactionReadModel.ts +10 -0
  641. package/src/modules/customers/lib/personCompanies.ts +317 -0
  642. package/src/modules/customers/lib/personCompanyLinkTable.ts +58 -0
  643. package/src/modules/customers/lib/roleTypeUsage.ts +146 -0
  644. package/src/modules/customers/migrations/.snapshot-open-mercato.json +2747 -798
  645. package/src/modules/customers/migrations/Migration20260406214502.ts +19 -0
  646. package/src/modules/customers/migrations/Migration20260408135736.ts +15 -0
  647. package/src/modules/customers/migrations/Migration20260408225345.ts +23 -0
  648. package/src/modules/customers/migrations/Migration20260411075533.ts +30 -0
  649. package/src/modules/customers/migrations/Migration20260411103551.ts +13 -0
  650. package/src/modules/customers/migrations/Migration20260411130944.ts +30 -0
  651. package/src/modules/customers/migrations/Migration20260415095203.ts +13 -0
  652. package/src/modules/customers/migrations/Migration20260415135056.ts +22 -0
  653. package/src/modules/customers/migrations/Migration20260417140000.ts +15 -0
  654. package/src/modules/customers/migrations/Migration20260417160000.ts +17 -0
  655. package/src/modules/customers/migrations/Migration20260417235407.ts +13 -0
  656. package/src/modules/customers/setup.ts +15 -0
  657. package/src/modules/customers/subscribers/deal-closure-notification.ts +22 -0
  658. package/src/modules/customers/subscribers/deal-lost-notification.ts +22 -0
  659. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +2 -0
  660. package/src/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.ts +162 -0
  661. package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +6 -2
  662. package/src/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.ts +162 -0
  663. package/src/modules/dictionaries/api/context.ts +9 -0
  664. package/src/modules/dictionaries/api/openapi.ts +17 -0
  665. package/src/modules/dictionaries/commands/entry-operations.ts +457 -0
  666. package/src/modules/dictionaries/commands/factory.ts +31 -3
  667. package/src/modules/dictionaries/commands/index.ts +1 -0
  668. package/src/modules/dictionaries/components/DictionaryTable.tsx +15 -6
  669. package/src/modules/dictionaries/data/entities.ts +9 -0
  670. package/src/modules/dictionaries/data/validators.ts +34 -0
  671. package/src/modules/dictionaries/events.ts +20 -0
  672. package/src/modules/dictionaries/i18n/de.json +2 -0
  673. package/src/modules/dictionaries/i18n/en.json +2 -0
  674. package/src/modules/dictionaries/i18n/es.json +2 -0
  675. package/src/modules/dictionaries/i18n/pl.json +2 -0
  676. package/src/modules/dictionaries/lib/clientEntries.ts +66 -0
  677. package/src/modules/dictionaries/migrations/.snapshot-open-mercato.json +185 -3
  678. package/src/modules/dictionaries/migrations/Migration20260410171544.ts +49 -0
  679. package/src/modules/inbox_ops/api/proposals/[id]/route.ts +4 -1
  680. package/src/modules/query_index/lib/engine.ts +9 -1
  681. package/src/modules/sales/components/documents/AddressesSection.tsx +92 -42
  682. package/src/modules/sales/i18n/de.json +28 -0
  683. package/src/modules/sales/i18n/en.json +28 -0
  684. package/src/modules/sales/i18n/es.json +28 -0
  685. package/src/modules/sales/i18n/pl.json +28 -0
  686. package/src/modules/sales/lib/dictionaries.ts +18 -0
  687. package/src/modules/sales/widgets/injection-table.ts +4 -0
@@ -18,6 +18,7 @@ import {
18
18
  CustomerInteraction,
19
19
  CustomerDeal,
20
20
  CustomerDealPersonLink,
21
+ CustomerPersonCompanyLink,
21
22
  CustomerTodoLink,
22
23
  CustomerEntity,
23
24
  CustomerPersonProfile,
@@ -43,6 +44,7 @@ import {
43
44
  emitQueryIndexUpsertEvents,
44
45
  type QueryIndexEventEntry,
45
46
  } from './shared'
47
+ import { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'
46
48
  import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
47
49
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
48
50
  import {
@@ -52,6 +54,11 @@ import {
52
54
  import type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'
53
55
  import { E } from '#generated/entities.ids.generated'
54
56
  import { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
57
+ import {
58
+ loadPersonCompanyLinks,
59
+ summarizePersonCompanies,
60
+ syncLegacyPrimaryCompanyLink,
61
+ } from '../lib/personCompanies'
55
62
 
56
63
  const INTERACTION_ENTITY_ID = 'customers:customer_interaction'
57
64
 
@@ -158,6 +165,12 @@ type PersonSnapshot = {
158
165
  twitterUrl: string | null
159
166
  companyEntityId: string | null
160
167
  }
168
+ companies: Array<{
169
+ linkId: string | null
170
+ companyId: string
171
+ displayName: string
172
+ isPrimary: boolean
173
+ }>
161
174
  tagIds: string[]
162
175
  addresses: PersonAddressSnapshot[]
163
176
  comments: PersonCommentSnapshot[]
@@ -232,6 +245,7 @@ function serializePersonSnapshot(
232
245
  interactions: Array<PersonInteractionSnapshot>,
233
246
  custom?: Record<string, unknown>
234
247
  ): PersonSnapshot {
248
+ const companies = summarizePersonCompanies(profile, [])
235
249
  return {
236
250
  entity: {
237
251
  id: entity.id,
@@ -269,6 +283,7 @@ function serializePersonSnapshot(
269
283
  : profile.company.id
270
284
  : null,
271
285
  },
286
+ companies,
272
287
  tagIds,
273
288
  addresses: addresses.map((address) => ({
274
289
  id: address.id,
@@ -347,6 +362,7 @@ async function loadPersonSnapshot(em: EntityManager, entityId: string): Promise<
347
362
  { tenantId: entity.tenantId, organizationId: entity.organizationId },
348
363
  )
349
364
  if (!profile) return null
365
+ const companyLinks = await loadPersonCompanyLinks(em, entity)
350
366
  const tagIds = await loadEntityTagIds(em, entity)
351
367
  const addresses = await em.find(CustomerAddress, { entity }, { orderBy: { createdAt: 'asc' } })
352
368
  const comments = await findWithDecryption(
@@ -418,7 +434,9 @@ async function loadPersonSnapshot(em: EntityManager, entityId: string): Promise<
418
434
  }),
419
435
  })),
420
436
  )
421
- return serializePersonSnapshot(entity, profile, tagIds, addresses, comments, deals, activities, todoLinks, interactionSnapshots, custom)
437
+ const snapshot = serializePersonSnapshot(entity, profile, tagIds, addresses, comments, deals, activities, todoLinks, interactionSnapshots, custom)
438
+ snapshot.companies = summarizePersonCompanies(profile, companyLinks)
439
+ return snapshot
422
440
  }
423
441
 
424
442
  async function resolveCompanyReference(
@@ -517,76 +535,81 @@ const createPersonCommand: CommandHandler<PersonCreateInput, { entityId: string;
517
535
  throw new CrudHttpError(400, { error: 'Display name is required' })
518
536
  }
519
537
 
520
- const entity = em.create(CustomerEntity, {
521
- organizationId: parsed.organizationId,
522
- tenantId: parsed.tenantId,
523
- kind: 'person',
524
- displayName,
525
- description,
526
- ownerUserId: parsed.ownerUserId ?? null,
527
- primaryEmail,
528
- primaryPhone,
529
- status,
530
- lifecycleStage,
531
- source,
532
- nextInteractionAt: parsed.nextInteraction?.at ?? null,
533
- nextInteractionName,
534
- nextInteractionRefId,
535
- nextInteractionIcon,
536
- nextInteractionColor,
537
- isActive: parsed.isActive ?? true,
538
- })
539
-
540
- const company = await resolveCompanyReference(em, parsed.companyEntityId ?? null, parsed.organizationId, parsed.tenantId)
538
+ let entity!: CustomerEntity
539
+ let profile!: CustomerPersonProfile
540
+ await withAtomicFlush(em, [
541
+ () => {
542
+ entity = em.create(CustomerEntity, {
543
+ organizationId: parsed.organizationId,
544
+ tenantId: parsed.tenantId,
545
+ kind: 'person',
546
+ displayName,
547
+ description,
548
+ ownerUserId: parsed.ownerUserId ?? null,
549
+ primaryEmail,
550
+ primaryPhone,
551
+ status,
552
+ lifecycleStage,
553
+ source,
554
+ nextInteractionAt: parsed.nextInteraction?.at ?? null,
555
+ nextInteractionName,
556
+ nextInteractionRefId,
557
+ nextInteractionIcon,
558
+ nextInteractionColor,
559
+ isActive: parsed.isActive ?? true,
560
+ })
541
561
 
542
- const profile = em.create(CustomerPersonProfile, {
543
- organizationId: parsed.organizationId,
544
- tenantId: parsed.tenantId,
545
- entity,
546
- firstName,
547
- lastName,
548
- preferredName,
549
- jobTitle,
550
- department,
551
- seniority,
552
- timezone,
553
- linkedInUrl,
554
- twitterUrl,
555
- company,
556
- })
562
+ profile = em.create(CustomerPersonProfile, {
563
+ organizationId: parsed.organizationId,
564
+ tenantId: parsed.tenantId,
565
+ entity,
566
+ firstName,
567
+ lastName,
568
+ preferredName,
569
+ jobTitle,
570
+ department,
571
+ seniority,
572
+ timezone,
573
+ linkedInUrl,
574
+ twitterUrl,
575
+ company: null,
576
+ })
557
577
 
558
- em.persist(entity)
559
- em.persist(profile)
560
- if (status) {
561
- await ensureDictionaryEntry(em, {
562
- tenantId: parsed.tenantId,
563
- organizationId: parsed.organizationId,
564
- kind: 'status',
565
- value: status,
566
- })
567
- }
568
- if (jobTitle) {
569
- await ensureDictionaryEntry(em, {
570
- tenantId: parsed.tenantId,
571
- organizationId: parsed.organizationId,
572
- kind: 'job_title',
573
- value: jobTitle,
574
- })
575
- }
576
- if (source) {
577
- await ensureDictionaryEntry(em, {
578
- tenantId: parsed.tenantId,
579
- organizationId: parsed.organizationId,
580
- kind: 'source',
581
- value: source,
582
- })
583
- }
584
- await em.flush()
578
+ em.persist(entity)
579
+ em.persist(profile)
580
+ },
581
+ async () => {
582
+ if (status) {
583
+ await ensureDictionaryEntry(em, {
584
+ tenantId: parsed.tenantId,
585
+ organizationId: parsed.organizationId,
586
+ kind: 'status',
587
+ value: status,
588
+ })
589
+ }
590
+ if (jobTitle) {
591
+ await ensureDictionaryEntry(em, {
592
+ tenantId: parsed.tenantId,
593
+ organizationId: parsed.organizationId,
594
+ kind: 'job_title',
595
+ value: jobTitle,
596
+ })
597
+ }
598
+ if (source) {
599
+ await ensureDictionaryEntry(em, {
600
+ tenantId: parsed.tenantId,
601
+ organizationId: parsed.organizationId,
602
+ kind: 'source',
603
+ value: source,
604
+ })
605
+ }
606
+ },
607
+ () => syncLegacyPrimaryCompanyLink(em, entity, profile, parsed.companyEntityId ?? null),
608
+ () => syncEntityTags(em, entity, parsed.tags),
609
+ ], { transaction: true })
585
610
 
586
611
  const tenantId = entity.tenantId
587
612
  const organizationId = entity.organizationId
588
- await syncEntityTags(em, entity, parsed.tags)
589
- await em.flush()
590
613
  await setCustomFieldsForPerson(ctx, entity.id, profile.id, organizationId, tenantId, custom)
591
614
 
592
615
  const de = (ctx.container.resolve('dataEngine') as DataEngine)
@@ -634,17 +657,25 @@ const createPersonCommand: CommandHandler<PersonCreateInput, { entityId: string;
634
657
  const em = (ctx.container.resolve('em') as EntityManager).fork()
635
658
  const entity = await em.findOne(CustomerEntity, { id: entityId })
636
659
  if (!entity) return
637
- const profile = await em.findOne(CustomerPersonProfile, { entity })
660
+ const profile = await findOneWithDecryption(
661
+ em,
662
+ CustomerPersonProfile,
663
+ { entity },
664
+ undefined,
665
+ { tenantId: entity.tenantId, organizationId: entity.organizationId },
666
+ )
638
667
  const identifiers = {
639
668
  id: payload?.after?.profile.id ?? profile?.id ?? entity.id,
640
669
  organizationId: entity.organizationId,
641
670
  tenantId: entity.tenantId,
642
671
  }
643
- await em.nativeDelete(CustomerTagAssignment, { entity, organizationId: entity.organizationId, tenantId: entity.tenantId })
644
- if (profile) {
645
- await em.remove(profile).flush()
646
- }
647
- await em.remove(entity).flush()
672
+ await withAtomicFlush(em, [
673
+ () => em.nativeDelete(CustomerTagAssignment, { entity, organizationId: entity.organizationId, tenantId: entity.tenantId }),
674
+ () => {
675
+ if (profile) em.remove(profile)
676
+ },
677
+ () => em.remove(entity),
678
+ ], { transaction: true })
648
679
 
649
680
  const de = (ctx.container.resolve('dataEngine') as DataEngine)
650
681
  await emitCrudUndoSideEffects({
@@ -663,7 +694,7 @@ const updatePersonCommand: CommandHandler<PersonUpdateInput, { entityId: string
663
694
  id: 'customers.people.update',
664
695
  async prepare(rawInput, ctx) {
665
696
  const { parsed } = parseWithCustomFields(personUpdateSchema, rawInput)
666
- const em = (ctx.container.resolve('em') as EntityManager)
697
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
667
698
  const snapshot = await loadPersonSnapshot(em, parsed.id)
668
699
  return snapshot ? { before: snapshot } : {}
669
700
  },
@@ -677,95 +708,108 @@ const updatePersonCommand: CommandHandler<PersonUpdateInput, { entityId: string
677
708
  const profile = await em.findOne(CustomerPersonProfile, { entity: record })
678
709
  if (!profile) throw new CrudHttpError(404, { error: 'Person profile not found' })
679
710
 
680
- if (parsed.description !== undefined) record.description = normalizeOptionalString(parsed.description)
681
- if (parsed.ownerUserId !== undefined) record.ownerUserId = parsed.ownerUserId ?? null
682
- if (parsed.primaryEmail !== undefined) record.primaryEmail = normalizeEmail(parsed.primaryEmail)
683
- if (parsed.primaryPhone !== undefined) record.primaryPhone = normalizeOptionalString(parsed.primaryPhone)
684
- if (parsed.status !== undefined) {
685
- const normalizedStatus = normalizeOptionalString(parsed.status)
686
- record.status = normalizedStatus
687
- if (normalizedStatus) {
688
- await ensureDictionaryEntry(em, {
689
- tenantId: record.tenantId,
690
- organizationId: record.organizationId,
691
- kind: 'status',
692
- value: normalizedStatus,
693
- })
694
- }
695
- }
696
- if (parsed.lifecycleStage !== undefined) record.lifecycleStage = normalizeOptionalString(parsed.lifecycleStage)
697
- if (parsed.source !== undefined) {
698
- const normalizedSource = normalizeOptionalString(parsed.source)
699
- record.source = normalizedSource
700
- if (normalizedSource) {
701
- await ensureDictionaryEntry(em, {
702
- tenantId: record.tenantId,
703
- organizationId: record.organizationId,
704
- kind: 'source',
705
- value: normalizedSource,
706
- })
707
- }
708
- }
709
- if (parsed.isActive !== undefined) record.isActive = parsed.isActive
710
- if (parsed.nextInteraction) {
711
- record.nextInteractionAt = parsed.nextInteraction.at
712
- record.nextInteractionName = parsed.nextInteraction.name.trim()
713
- record.nextInteractionRefId = normalizeOptionalString(parsed.nextInteraction.refId) ?? null
714
- record.nextInteractionIcon = normalizeOptionalString(parsed.nextInteraction.icon)
715
- record.nextInteractionColor = normalizeHexColor(parsed.nextInteraction.color)
716
- } else if (parsed.nextInteraction === null) {
717
- record.nextInteractionAt = null
718
- record.nextInteractionName = null
719
- record.nextInteractionRefId = null
720
- record.nextInteractionIcon = null
721
- record.nextInteractionColor = null
722
- }
723
-
724
- if (parsed.firstName !== undefined) profile.firstName = normalizeOptionalString(parsed.firstName)
725
- if (parsed.lastName !== undefined) profile.lastName = normalizeOptionalString(parsed.lastName)
726
- if (parsed.preferredName !== undefined) profile.preferredName = normalizeOptionalString(parsed.preferredName)
727
- if (parsed.jobTitle !== undefined) {
728
- const normalizedJobTitle = normalizeOptionalString(parsed.jobTitle)
729
- profile.jobTitle = normalizedJobTitle
730
- if (normalizedJobTitle) {
731
- await ensureDictionaryEntry(em, {
732
- tenantId: record.tenantId,
733
- organizationId: record.organizationId,
734
- kind: 'job_title',
735
- value: normalizedJobTitle,
736
- })
737
- }
738
- }
739
- if (parsed.department !== undefined) profile.department = normalizeOptionalString(parsed.department)
740
- if (parsed.seniority !== undefined) profile.seniority = normalizeOptionalString(parsed.seniority)
741
- if (parsed.timezone !== undefined) profile.timezone = normalizeOptionalString(parsed.timezone)
742
- if (parsed.linkedInUrl !== undefined) profile.linkedInUrl = normalizeOptionalString(parsed.linkedInUrl)
743
- if (parsed.twitterUrl !== undefined) profile.twitterUrl = normalizeOptionalString(parsed.twitterUrl)
744
-
745
- if (parsed.companyEntityId !== undefined) {
746
- profile.company = await resolveCompanyReference(em, parsed.companyEntityId, record.organizationId, record.tenantId)
747
- }
748
-
749
- const profileFieldsUpdated = [
750
- parsed.firstName, parsed.lastName, parsed.preferredName, parsed.jobTitle,
751
- parsed.department, parsed.seniority, parsed.timezone, parsed.linkedInUrl,
752
- parsed.twitterUrl, parsed.companyEntityId,
753
- ].some((v) => v !== undefined)
754
- if (profileFieldsUpdated) {
755
- record.updatedAt = new Date()
756
- }
757
-
758
711
  if (parsed.displayName !== undefined) {
759
712
  const nextDisplayName = parsed.displayName.trim()
760
713
  if (!nextDisplayName) {
761
714
  throw new CrudHttpError(400, { error: 'Display name is required' })
762
715
  }
763
- record.displayName = nextDisplayName
764
716
  }
765
717
 
766
- await em.flush()
767
- await syncEntityTags(em, record, parsed.tags)
768
- await em.flush()
718
+ await withAtomicFlush(em, [
719
+ () => {
720
+ if (parsed.description !== undefined) record.description = normalizeOptionalString(parsed.description)
721
+ if (parsed.ownerUserId !== undefined) record.ownerUserId = parsed.ownerUserId ?? null
722
+ if (parsed.primaryEmail !== undefined) record.primaryEmail = normalizeEmail(parsed.primaryEmail)
723
+ if (parsed.primaryPhone !== undefined) record.primaryPhone = normalizeOptionalString(parsed.primaryPhone)
724
+ if (parsed.status !== undefined) {
725
+ record.status = normalizeOptionalString(parsed.status)
726
+ }
727
+ if (parsed.lifecycleStage !== undefined) record.lifecycleStage = normalizeOptionalString(parsed.lifecycleStage)
728
+ if (parsed.source !== undefined) {
729
+ record.source = normalizeOptionalString(parsed.source)
730
+ }
731
+ if (parsed.isActive !== undefined) record.isActive = parsed.isActive
732
+ if (parsed.nextInteraction) {
733
+ record.nextInteractionAt = parsed.nextInteraction.at
734
+ record.nextInteractionName = parsed.nextInteraction.name.trim()
735
+ record.nextInteractionRefId = normalizeOptionalString(parsed.nextInteraction.refId) ?? null
736
+ record.nextInteractionIcon = normalizeOptionalString(parsed.nextInteraction.icon)
737
+ record.nextInteractionColor = normalizeHexColor(parsed.nextInteraction.color)
738
+ } else if (parsed.nextInteraction === null) {
739
+ record.nextInteractionAt = null
740
+ record.nextInteractionName = null
741
+ record.nextInteractionRefId = null
742
+ record.nextInteractionIcon = null
743
+ record.nextInteractionColor = null
744
+ }
745
+
746
+ if (parsed.firstName !== undefined) profile.firstName = normalizeOptionalString(parsed.firstName)
747
+ if (parsed.lastName !== undefined) profile.lastName = normalizeOptionalString(parsed.lastName)
748
+ if (parsed.preferredName !== undefined) profile.preferredName = normalizeOptionalString(parsed.preferredName)
749
+ if (parsed.jobTitle !== undefined) {
750
+ profile.jobTitle = normalizeOptionalString(parsed.jobTitle)
751
+ }
752
+ if (parsed.department !== undefined) profile.department = normalizeOptionalString(parsed.department)
753
+ if (parsed.seniority !== undefined) profile.seniority = normalizeOptionalString(parsed.seniority)
754
+ if (parsed.timezone !== undefined) profile.timezone = normalizeOptionalString(parsed.timezone)
755
+ if (parsed.linkedInUrl !== undefined) profile.linkedInUrl = normalizeOptionalString(parsed.linkedInUrl)
756
+ if (parsed.twitterUrl !== undefined) profile.twitterUrl = normalizeOptionalString(parsed.twitterUrl)
757
+
758
+ const profileFieldsUpdated = [
759
+ parsed.firstName, parsed.lastName, parsed.preferredName, parsed.jobTitle,
760
+ parsed.department, parsed.seniority, parsed.timezone, parsed.linkedInUrl,
761
+ parsed.twitterUrl, parsed.companyEntityId,
762
+ ].some((v) => v !== undefined)
763
+ if (profileFieldsUpdated) {
764
+ record.updatedAt = new Date()
765
+ }
766
+
767
+ if (parsed.displayName !== undefined) {
768
+ record.displayName = parsed.displayName.trim()
769
+ }
770
+ },
771
+ async () => {
772
+ if (parsed.status !== undefined) {
773
+ const normalizedStatus = normalizeOptionalString(parsed.status)
774
+ if (normalizedStatus) {
775
+ await ensureDictionaryEntry(em, {
776
+ tenantId: record.tenantId,
777
+ organizationId: record.organizationId,
778
+ kind: 'status',
779
+ value: normalizedStatus,
780
+ })
781
+ }
782
+ }
783
+ if (parsed.source !== undefined) {
784
+ const normalizedSource = normalizeOptionalString(parsed.source)
785
+ if (normalizedSource) {
786
+ await ensureDictionaryEntry(em, {
787
+ tenantId: record.tenantId,
788
+ organizationId: record.organizationId,
789
+ kind: 'source',
790
+ value: normalizedSource,
791
+ })
792
+ }
793
+ }
794
+ if (parsed.jobTitle !== undefined) {
795
+ const normalizedJobTitle = normalizeOptionalString(parsed.jobTitle)
796
+ if (normalizedJobTitle) {
797
+ await ensureDictionaryEntry(em, {
798
+ tenantId: record.tenantId,
799
+ organizationId: record.organizationId,
800
+ kind: 'job_title',
801
+ value: normalizedJobTitle,
802
+ })
803
+ }
804
+ }
805
+ },
806
+ async () => {
807
+ if (parsed.companyEntityId !== undefined) {
808
+ await syncLegacyPrimaryCompanyLink(em, record, profile, parsed.companyEntityId)
809
+ }
810
+ },
811
+ () => syncEntityTags(em, record, parsed.tags),
812
+ ], { transaction: true })
769
813
 
770
814
  await setCustomFieldsForPerson(ctx, record.id, profile.id, record.organizationId, record.tenantId, custom)
771
815
 
@@ -821,92 +865,92 @@ const updatePersonCommand: CommandHandler<PersonUpdateInput, { entityId: string
821
865
  const em = (ctx.container.resolve('em') as EntityManager).fork()
822
866
  const entity = await em.findOne(CustomerEntity, { id: before.entity.id })
823
867
  if (!entity) {
824
- const newEntity = em.create(CustomerEntity, {
825
- id: before.entity.id,
826
- organizationId: before.entity.organizationId,
827
- tenantId: before.entity.tenantId,
828
- kind: 'person',
829
- displayName: before.entity.displayName,
830
- description: before.entity.description,
831
- ownerUserId: before.entity.ownerUserId,
832
- primaryEmail: before.entity.primaryEmail,
833
- primaryPhone: before.entity.primaryPhone,
834
- status: before.entity.status,
835
- lifecycleStage: before.entity.lifecycleStage,
836
- source: before.entity.source,
837
- nextInteractionAt: before.entity.nextInteractionAt,
838
- nextInteractionName: before.entity.nextInteractionName,
839
- nextInteractionRefId: before.entity.nextInteractionRefId,
840
- nextInteractionIcon: before.entity.nextInteractionIcon,
841
- nextInteractionColor: before.entity.nextInteractionColor,
842
- isActive: before.entity.isActive,
843
- })
844
- em.persist(newEntity)
845
- const profile = em.create(CustomerPersonProfile, {
846
- id: before.profile.id,
847
- organizationId: before.entity.organizationId,
848
- tenantId: before.entity.tenantId,
849
- entity: newEntity,
850
- firstName: before.profile.firstName,
851
- lastName: before.profile.lastName,
852
- preferredName: before.profile.preferredName,
853
- jobTitle: before.profile.jobTitle,
854
- department: before.profile.department,
855
- seniority: before.profile.seniority,
856
- timezone: before.profile.timezone,
857
- linkedInUrl: before.profile.linkedInUrl,
858
- twitterUrl: before.profile.twitterUrl,
859
- })
860
- em.persist(profile)
861
- if (before.profile.companyEntityId) {
862
- profile.company = await resolveCompanyReference(
863
- em,
864
- before.profile.companyEntityId,
865
- before.entity.organizationId,
866
- before.entity.tenantId
867
- )
868
- }
869
- await em.flush()
870
- await syncEntityTags(em, newEntity, before.tagIds)
871
- await em.flush()
868
+ let newEntity!: CustomerEntity
869
+ let newProfile!: CustomerPersonProfile
870
+ await withAtomicFlush(em, [
871
+ () => {
872
+ newEntity = em.create(CustomerEntity, {
873
+ id: before.entity.id,
874
+ organizationId: before.entity.organizationId,
875
+ tenantId: before.entity.tenantId,
876
+ kind: 'person',
877
+ displayName: before.entity.displayName,
878
+ description: before.entity.description,
879
+ ownerUserId: before.entity.ownerUserId,
880
+ primaryEmail: before.entity.primaryEmail,
881
+ primaryPhone: before.entity.primaryPhone,
882
+ status: before.entity.status,
883
+ lifecycleStage: before.entity.lifecycleStage,
884
+ source: before.entity.source,
885
+ nextInteractionAt: before.entity.nextInteractionAt,
886
+ nextInteractionName: before.entity.nextInteractionName,
887
+ nextInteractionRefId: before.entity.nextInteractionRefId,
888
+ nextInteractionIcon: before.entity.nextInteractionIcon,
889
+ nextInteractionColor: before.entity.nextInteractionColor,
890
+ isActive: before.entity.isActive,
891
+ })
892
+ em.persist(newEntity)
893
+ newProfile = em.create(CustomerPersonProfile, {
894
+ id: before.profile.id,
895
+ organizationId: before.entity.organizationId,
896
+ tenantId: before.entity.tenantId,
897
+ entity: newEntity,
898
+ firstName: before.profile.firstName,
899
+ lastName: before.profile.lastName,
900
+ preferredName: before.profile.preferredName,
901
+ jobTitle: before.profile.jobTitle,
902
+ department: before.profile.department,
903
+ seniority: before.profile.seniority,
904
+ timezone: before.profile.timezone,
905
+ linkedInUrl: before.profile.linkedInUrl,
906
+ twitterUrl: before.profile.twitterUrl,
907
+ })
908
+ em.persist(newProfile)
909
+ },
910
+ () => syncLegacyPrimaryCompanyLink(em, newEntity, newProfile, before.profile.companyEntityId),
911
+ () => syncEntityTags(em, newEntity, before.tagIds),
912
+ ], { transaction: true })
872
913
  } else {
873
- entity.displayName = before.entity.displayName
874
- entity.description = before.entity.description
875
- entity.ownerUserId = before.entity.ownerUserId
876
- entity.primaryEmail = before.entity.primaryEmail
877
- entity.primaryPhone = before.entity.primaryPhone
878
- entity.status = before.entity.status
879
- entity.lifecycleStage = before.entity.lifecycleStage
880
- entity.source = before.entity.source
881
- entity.nextInteractionAt = before.entity.nextInteractionAt
882
- entity.nextInteractionName = before.entity.nextInteractionName
883
- entity.nextInteractionRefId = before.entity.nextInteractionRefId
884
- entity.nextInteractionIcon = before.entity.nextInteractionIcon
885
- entity.nextInteractionColor = before.entity.nextInteractionColor
886
- entity.isActive = before.entity.isActive
887
- await em.flush()
888
- const profile = await em.findOne(CustomerPersonProfile, { entity })
889
- if (profile) {
890
- profile.firstName = before.profile.firstName
891
- profile.lastName = before.profile.lastName
892
- profile.preferredName = before.profile.preferredName
893
- profile.jobTitle = before.profile.jobTitle
894
- profile.department = before.profile.department
895
- profile.seniority = before.profile.seniority
896
- profile.timezone = before.profile.timezone
897
- profile.linkedInUrl = before.profile.linkedInUrl
898
- profile.twitterUrl = before.profile.twitterUrl
899
- profile.company = before.profile.companyEntityId
900
- ? await resolveCompanyReference(
901
- em,
902
- before.profile.companyEntityId,
903
- before.entity.organizationId,
904
- before.entity.tenantId
905
- )
906
- : null
907
- }
908
- await syncEntityTags(em, entity, before.tagIds)
909
- await em.flush()
914
+ await withAtomicFlush(em, [
915
+ () => {
916
+ entity.displayName = before.entity.displayName
917
+ entity.description = before.entity.description
918
+ entity.ownerUserId = before.entity.ownerUserId
919
+ entity.primaryEmail = before.entity.primaryEmail
920
+ entity.primaryPhone = before.entity.primaryPhone
921
+ entity.status = before.entity.status
922
+ entity.lifecycleStage = before.entity.lifecycleStage
923
+ entity.source = before.entity.source
924
+ entity.nextInteractionAt = before.entity.nextInteractionAt
925
+ entity.nextInteractionName = before.entity.nextInteractionName
926
+ entity.nextInteractionRefId = before.entity.nextInteractionRefId
927
+ entity.nextInteractionIcon = before.entity.nextInteractionIcon
928
+ entity.nextInteractionColor = before.entity.nextInteractionColor
929
+ entity.isActive = before.entity.isActive
930
+ },
931
+ async () => {
932
+ const profile = await findOneWithDecryption(
933
+ em,
934
+ CustomerPersonProfile,
935
+ { entity },
936
+ undefined,
937
+ { tenantId: before.entity.tenantId, organizationId: before.entity.organizationId },
938
+ )
939
+ if (profile) {
940
+ profile.firstName = before.profile.firstName
941
+ profile.lastName = before.profile.lastName
942
+ profile.preferredName = before.profile.preferredName
943
+ profile.jobTitle = before.profile.jobTitle
944
+ profile.department = before.profile.department
945
+ profile.seniority = before.profile.seniority
946
+ profile.timezone = before.profile.timezone
947
+ profile.linkedInUrl = before.profile.linkedInUrl
948
+ profile.twitterUrl = before.profile.twitterUrl
949
+ await syncLegacyPrimaryCompanyLink(em, entity, profile, before.profile.companyEntityId)
950
+ }
951
+ },
952
+ () => syncEntityTags(em, entity, before.tagIds),
953
+ ], { transaction: true })
910
954
  }
911
955
 
912
956
  const indexedEntity = await em.findOne(CustomerEntity, { id: before.entity.id })
@@ -939,7 +983,7 @@ const deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; quer
939
983
  id: 'customers.people.delete',
940
984
  async prepare(input, ctx) {
941
985
  const id = requireId(input, 'Person id required')
942
- const em = (ctx.container.resolve('em') as EntityManager)
986
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
943
987
  const snapshot = await loadPersonSnapshot(em, id)
944
988
  return snapshot ? { before: snapshot } : {}
945
989
  },
@@ -960,6 +1004,7 @@ const deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; quer
960
1004
  await em.nativeDelete(CustomerTodoLink, { entity: record, organizationId: record.organizationId, tenantId: record.tenantId })
961
1005
  await em.nativeDelete(CustomerTagAssignment, { entity: record, organizationId: record.organizationId, tenantId: record.tenantId })
962
1006
  await em.nativeDelete(CustomerDealPersonLink, { person: record })
1007
+ await em.nativeDelete(CustomerPersonCompanyLink, { person: record })
963
1008
  if (profile) {
964
1009
  await em.nativeDelete(CustomFieldValue, { entityId: PERSON_ENTITY_ID, recordId: profile.id })
965
1010
  }
@@ -1064,7 +1109,37 @@ const deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; quer
1064
1109
  const before = payload?.before
1065
1110
  if (!before) return
1066
1111
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1067
- let entity = await em.findOne(CustomerEntity, { id: before.entity.id })
1112
+ const de = (ctx.container.resolve('dataEngine') as DataEngine)
1113
+
1114
+ const decryptionScope = {
1115
+ tenantId: before.entity.tenantId ?? null,
1116
+ organizationId: before.entity.organizationId ?? null,
1117
+ }
1118
+ // Bind the outer EntityManager to an explicit transaction so every
1119
+ // `em.flush()` below participates in the same unit of work. Using
1120
+ // `em.transactional(cb)` would pass a forked em into `cb` and the
1121
+ // surrounding closures would mutate the unwrapped em, escaping the
1122
+ // transaction (see SPEC-018 and H8 in the CRM details screens review).
1123
+ await em.begin()
1124
+ let txResult: {
1125
+ entity: CustomerEntity
1126
+ profile: CustomerPersonProfile
1127
+ beforeInteractions: PersonInteractionSnapshot[]
1128
+ beforeTodos: PersonTodoSnapshot[]
1129
+ }
1130
+ try {
1131
+ txResult = await (async () => {
1132
+ let entity = await findOneWithDecryption(
1133
+ em,
1134
+ CustomerEntity,
1135
+ {
1136
+ id: before.entity.id,
1137
+ tenantId: before.entity.tenantId,
1138
+ organizationId: before.entity.organizationId,
1139
+ },
1140
+ {},
1141
+ decryptionScope,
1142
+ )
1068
1143
  if (!entity) {
1069
1144
  entity = em.create(CustomerEntity, {
1070
1145
  id: before.entity.id,
@@ -1105,7 +1180,17 @@ const deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; quer
1105
1180
  entity.isActive = before.entity.isActive
1106
1181
  entity.deletedAt = null
1107
1182
 
1108
- let profile = await em.findOne(CustomerPersonProfile, { entity })
1183
+ let profile = await findOneWithDecryption(
1184
+ em,
1185
+ CustomerPersonProfile,
1186
+ {
1187
+ entity,
1188
+ tenantId: before.entity.tenantId,
1189
+ organizationId: before.entity.organizationId,
1190
+ },
1191
+ {},
1192
+ decryptionScope,
1193
+ )
1109
1194
  if (!profile) {
1110
1195
  profile = em.create(CustomerPersonProfile, {
1111
1196
  id: before.profile.id,
@@ -1134,20 +1219,34 @@ const deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; quer
1134
1219
  profile.twitterUrl = before.profile.twitterUrl
1135
1220
  }
1136
1221
 
1137
- if (before.profile.companyEntityId) {
1138
- profile.company = await resolveCompanyReference(
1222
+ await syncLegacyPrimaryCompanyLink(em, entity, profile, before.profile.companyEntityId)
1223
+
1224
+ await em.flush()
1225
+ await em.nativeDelete(CustomerPersonCompanyLink, { person: entity })
1226
+ for (const companyLink of before.companies ?? []) {
1227
+ const company = await resolveCompanyReference(
1139
1228
  em,
1140
- before.profile.companyEntityId,
1229
+ companyLink.companyId,
1141
1230
  before.entity.organizationId,
1142
- before.entity.tenantId
1231
+ before.entity.tenantId,
1143
1232
  )
1144
- } else {
1145
- profile.company = null
1233
+ if (!company) continue
1234
+ const restoredLink = em.create(CustomerPersonCompanyLink, {
1235
+ id: companyLink.linkId ?? undefined,
1236
+ organizationId: before.entity.organizationId,
1237
+ tenantId: before.entity.tenantId,
1238
+ person: entity,
1239
+ company,
1240
+ isPrimary: companyLink.isPrimary,
1241
+ })
1242
+ em.persist(restoredLink)
1243
+ if (companyLink.isPrimary) {
1244
+ profile.company = company
1245
+ }
1146
1246
  }
1147
-
1148
- await em.flush()
1149
- await syncEntityTags(em, entity, before.tagIds)
1150
- await em.flush()
1247
+ await withAtomicFlush(em, [
1248
+ () => syncEntityTags(em, entity, before.tagIds),
1249
+ ])
1151
1250
 
1152
1251
  const beforeActivities = (before as { activities?: PersonActivitySnapshot[] }).activities ?? []
1153
1252
  const beforeTodos = (before as { todos?: PersonTodoSnapshot[] }).todos ?? []
@@ -1267,7 +1366,6 @@ const deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; quer
1267
1366
  }
1268
1367
  await em.flush()
1269
1368
 
1270
- const de = (ctx.container.resolve('dataEngine') as DataEngine)
1271
1369
  await em.nativeDelete(CustomerInteraction, { entity, organizationId: entity.organizationId, tenantId: entity.tenantId })
1272
1370
  for (const interaction of beforeInteractions) {
1273
1371
  const restoredInteraction = em.create(CustomerInteraction, {
@@ -1295,19 +1393,35 @@ const deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; quer
1295
1393
  em.persist(restoredInteraction)
1296
1394
  }
1297
1395
  await em.flush()
1298
- for (const interaction of beforeInteractions) {
1396
+
1397
+ return { entity, profile, beforeInteractions, beforeTodos }
1398
+ })()
1399
+ await em.commit()
1400
+ } catch (err) {
1401
+ try {
1402
+ await em.rollback()
1403
+ } catch {
1404
+ // rollback failure should not mask the original error
1405
+ }
1406
+ throw err
1407
+ }
1408
+
1409
+ for (const interaction of txResult.beforeInteractions) {
1299
1410
  if (!interaction.custom || !Object.keys(interaction.custom).length) continue
1300
1411
  await setCustomFieldsIfAny({
1301
1412
  dataEngine: de,
1302
1413
  entityId: INTERACTION_ENTITY_ID,
1303
1414
  recordId: interaction.id,
1304
- organizationId: entity.organizationId,
1305
- tenantId: entity.tenantId,
1415
+ organizationId: txResult.entity.organizationId,
1416
+ tenantId: txResult.entity.tenantId,
1306
1417
  values: interaction.custom,
1307
1418
  notify: false,
1308
1419
  })
1309
1420
  }
1310
1421
 
1422
+ const entity = txResult.entity
1423
+ const profile = txResult.profile
1424
+
1311
1425
  await emitCrudUndoSideEffects({
1312
1426
  dataEngine: de,
1313
1427
  action: 'created',
@@ -1346,7 +1460,7 @@ const deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; quer
1346
1460
  organizationId: entity.organizationId,
1347
1461
  })
1348
1462
  }
1349
- for (const todo of beforeTodos ?? []) {
1463
+ for (const todo of txResult.beforeTodos ?? []) {
1350
1464
  upsertEntries.push({
1351
1465
  entityType: E.customers.customer_todo_link,
1352
1466
  recordId: todo.id,
@@ -1354,7 +1468,7 @@ const deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; quer
1354
1468
  organizationId: entity.organizationId,
1355
1469
  })
1356
1470
  }
1357
- for (const interaction of beforeInteractions ?? []) {
1471
+ for (const interaction of txResult.beforeInteractions ?? []) {
1358
1472
  upsertEntries.push({
1359
1473
  entityType: E.customers.customer_interaction,
1360
1474
  recordId: interaction.id,