@open-mercato/core 0.4.5-develop-2e9903a57a → 0.4.5-develop-eeccf7adf4

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 (473) hide show
  1. package/package.json +2 -2
  2. package/dist/modules/auth/__integration__/TC-AUTH-001.spec.js +0 -9
  3. package/dist/modules/auth/__integration__/TC-AUTH-001.spec.js.map +0 -7
  4. package/dist/modules/auth/__integration__/TC-AUTH-002.spec.js +0 -22
  5. package/dist/modules/auth/__integration__/TC-AUTH-002.spec.js.map +0 -7
  6. package/dist/modules/auth/__integration__/TC-AUTH-003.spec.js +0 -21
  7. package/dist/modules/auth/__integration__/TC-AUTH-003.spec.js.map +0 -7
  8. package/dist/modules/auth/__integration__/TC-AUTH-004.spec.js +0 -15
  9. package/dist/modules/auth/__integration__/TC-AUTH-004.spec.js.map +0 -7
  10. package/dist/modules/auth/__integration__/TC-AUTH-005.spec.js +0 -11
  11. package/dist/modules/auth/__integration__/TC-AUTH-005.spec.js.map +0 -7
  12. package/dist/modules/auth/__integration__/TC-AUTH-006.spec.js +0 -11
  13. package/dist/modules/auth/__integration__/TC-AUTH-006.spec.js.map +0 -7
  14. package/dist/modules/auth/__integration__/TC-AUTH-007.spec.js +0 -14
  15. package/dist/modules/auth/__integration__/TC-AUTH-007.spec.js.map +0 -7
  16. package/dist/modules/auth/__integration__/TC-AUTH-008.spec.js +0 -26
  17. package/dist/modules/auth/__integration__/TC-AUTH-008.spec.js.map +0 -7
  18. package/dist/modules/auth/__integration__/TC-AUTH-009.spec.js +0 -16
  19. package/dist/modules/auth/__integration__/TC-AUTH-009.spec.js.map +0 -7
  20. package/dist/modules/auth/__integration__/TC-AUTH-010.spec.js +0 -32
  21. package/dist/modules/auth/__integration__/TC-AUTH-010.spec.js.map +0 -7
  22. package/dist/modules/auth/__integration__/TC-AUTH-011.spec.js +0 -26
  23. package/dist/modules/auth/__integration__/TC-AUTH-011.spec.js.map +0 -7
  24. package/dist/modules/auth/__integration__/TC-AUTH-012.spec.js +0 -30
  25. package/dist/modules/auth/__integration__/TC-AUTH-012.spec.js.map +0 -7
  26. package/dist/modules/auth/__integration__/TC-AUTH-013.spec.js +0 -41
  27. package/dist/modules/auth/__integration__/TC-AUTH-013.spec.js.map +0 -7
  28. package/dist/modules/auth/__integration__/TC-AUTH-014.spec.js +0 -25
  29. package/dist/modules/auth/__integration__/TC-AUTH-014.spec.js.map +0 -7
  30. package/dist/modules/auth/__integration__/TC-AUTH-015.spec.js +0 -20
  31. package/dist/modules/auth/__integration__/TC-AUTH-015.spec.js.map +0 -7
  32. package/dist/modules/auth/__integration__/TC-AUTH-016.spec.js +0 -76
  33. package/dist/modules/auth/__integration__/TC-AUTH-016.spec.js.map +0 -7
  34. package/dist/modules/catalog/__integration__/TC-CAT-001.spec.js +0 -20
  35. package/dist/modules/catalog/__integration__/TC-CAT-001.spec.js.map +0 -7
  36. package/dist/modules/catalog/__integration__/TC-CAT-002.spec.js +0 -12
  37. package/dist/modules/catalog/__integration__/TC-CAT-002.spec.js.map +0 -7
  38. package/dist/modules/catalog/__integration__/TC-CAT-003.spec.js +0 -28
  39. package/dist/modules/catalog/__integration__/TC-CAT-003.spec.js.map +0 -7
  40. package/dist/modules/catalog/__integration__/TC-CAT-004.spec.js +0 -33
  41. package/dist/modules/catalog/__integration__/TC-CAT-004.spec.js.map +0 -7
  42. package/dist/modules/catalog/__integration__/TC-CAT-005.spec.js +0 -30
  43. package/dist/modules/catalog/__integration__/TC-CAT-005.spec.js.map +0 -7
  44. package/dist/modules/catalog/__integration__/TC-CAT-006.spec.js +0 -31
  45. package/dist/modules/catalog/__integration__/TC-CAT-006.spec.js.map +0 -7
  46. package/dist/modules/catalog/__integration__/TC-CAT-007.spec.js +0 -31
  47. package/dist/modules/catalog/__integration__/TC-CAT-007.spec.js.map +0 -7
  48. package/dist/modules/catalog/__integration__/TC-CAT-008.spec.js +0 -65
  49. package/dist/modules/catalog/__integration__/TC-CAT-008.spec.js.map +0 -7
  50. package/dist/modules/catalog/__integration__/TC-CAT-009.spec.js +0 -31
  51. package/dist/modules/catalog/__integration__/TC-CAT-009.spec.js.map +0 -7
  52. package/dist/modules/catalog/__integration__/TC-CAT-010.spec.js +0 -28
  53. package/dist/modules/catalog/__integration__/TC-CAT-010.spec.js.map +0 -7
  54. package/dist/modules/catalog/__integration__/TC-CAT-011.spec.js +0 -34
  55. package/dist/modules/catalog/__integration__/TC-CAT-011.spec.js.map +0 -7
  56. package/dist/modules/catalog/__integration__/TC-CAT-012.spec.js +0 -27
  57. package/dist/modules/catalog/__integration__/TC-CAT-012.spec.js.map +0 -7
  58. package/dist/modules/core/__integration__/admin/TC-ADMIN-001.spec.js +0 -44
  59. package/dist/modules/core/__integration__/admin/TC-ADMIN-001.spec.js.map +0 -7
  60. package/dist/modules/core/__integration__/admin/TC-ADMIN-002.spec.js +0 -53
  61. package/dist/modules/core/__integration__/admin/TC-ADMIN-002.spec.js.map +0 -7
  62. package/dist/modules/core/__integration__/admin/TC-ADMIN-003.spec.js +0 -26
  63. package/dist/modules/core/__integration__/admin/TC-ADMIN-003.spec.js.map +0 -7
  64. package/dist/modules/core/__integration__/admin/TC-ADMIN-004.spec.js +0 -47
  65. package/dist/modules/core/__integration__/admin/TC-ADMIN-004.spec.js.map +0 -7
  66. package/dist/modules/core/__integration__/admin/TC-ADMIN-005.spec.js +0 -33
  67. package/dist/modules/core/__integration__/admin/TC-ADMIN-005.spec.js.map +0 -7
  68. package/dist/modules/core/__integration__/admin/TC-ADMIN-006.spec.js +0 -30
  69. package/dist/modules/core/__integration__/admin/TC-ADMIN-006.spec.js.map +0 -7
  70. package/dist/modules/core/__integration__/admin/TC-ADMIN-007.spec.js +0 -36
  71. package/dist/modules/core/__integration__/admin/TC-ADMIN-007.spec.js.map +0 -7
  72. package/dist/modules/core/__integration__/admin/TC-ADMIN-008.spec.js +0 -113
  73. package/dist/modules/core/__integration__/admin/TC-ADMIN-008.spec.js.map +0 -7
  74. package/dist/modules/core/__integration__/admin/TC-ADMIN-009.spec.js +0 -25
  75. package/dist/modules/core/__integration__/admin/TC-ADMIN-009.spec.js.map +0 -7
  76. package/dist/modules/core/__integration__/admin/TC-ADMIN-010.spec.js +0 -35
  77. package/dist/modules/core/__integration__/admin/TC-ADMIN-010.spec.js.map +0 -7
  78. package/dist/modules/core/__integration__/helpers/api.js +0 -64
  79. package/dist/modules/core/__integration__/helpers/api.js.map +0 -7
  80. package/dist/modules/core/__integration__/helpers/auth.js +0 -98
  81. package/dist/modules/core/__integration__/helpers/auth.js.map +0 -7
  82. package/dist/modules/core/__integration__/helpers/authUi.js +0 -31
  83. package/dist/modules/core/__integration__/helpers/authUi.js.map +0 -7
  84. package/dist/modules/core/__integration__/helpers/catalogFixtures.js +0 -49
  85. package/dist/modules/core/__integration__/helpers/catalogFixtures.js.map +0 -7
  86. package/dist/modules/core/__integration__/helpers/crmFixtures.js +0 -73
  87. package/dist/modules/core/__integration__/helpers/crmFixtures.js.map +0 -7
  88. package/dist/modules/core/__integration__/helpers/salesFixtures.js +0 -63
  89. package/dist/modules/core/__integration__/helpers/salesFixtures.js.map +0 -7
  90. package/dist/modules/core/__integration__/helpers/salesUi.js +0 -464
  91. package/dist/modules/core/__integration__/helpers/salesUi.js.map +0 -7
  92. package/dist/modules/core/__integration__/integration/TC-INT-001.spec.js +0 -26
  93. package/dist/modules/core/__integration__/integration/TC-INT-001.spec.js.map +0 -7
  94. package/dist/modules/core/__integration__/integration/TC-INT-002.spec.js +0 -60
  95. package/dist/modules/core/__integration__/integration/TC-INT-002.spec.js.map +0 -7
  96. package/dist/modules/core/__integration__/integration/TC-INT-003.spec.js +0 -36
  97. package/dist/modules/core/__integration__/integration/TC-INT-003.spec.js.map +0 -7
  98. package/dist/modules/core/__integration__/integration/TC-INT-004.spec.js +0 -74
  99. package/dist/modules/core/__integration__/integration/TC-INT-004.spec.js.map +0 -7
  100. package/dist/modules/core/__integration__/integration/TC-INT-005.spec.js +0 -21
  101. package/dist/modules/core/__integration__/integration/TC-INT-005.spec.js.map +0 -7
  102. package/dist/modules/customers/__integration__/TC-CRM-001.spec.js +0 -32
  103. package/dist/modules/customers/__integration__/TC-CRM-001.spec.js.map +0 -7
  104. package/dist/modules/customers/__integration__/TC-CRM-002.spec.js +0 -35
  105. package/dist/modules/customers/__integration__/TC-CRM-002.spec.js.map +0 -7
  106. package/dist/modules/customers/__integration__/TC-CRM-003.spec.js +0 -40
  107. package/dist/modules/customers/__integration__/TC-CRM-003.spec.js.map +0 -7
  108. package/dist/modules/customers/__integration__/TC-CRM-004.spec.js +0 -40
  109. package/dist/modules/customers/__integration__/TC-CRM-004.spec.js.map +0 -7
  110. package/dist/modules/customers/__integration__/TC-CRM-005.spec.js +0 -37
  111. package/dist/modules/customers/__integration__/TC-CRM-005.spec.js.map +0 -7
  112. package/dist/modules/customers/__integration__/TC-CRM-006.spec.js +0 -42
  113. package/dist/modules/customers/__integration__/TC-CRM-006.spec.js.map +0 -7
  114. package/dist/modules/customers/__integration__/TC-CRM-007.spec.js +0 -44
  115. package/dist/modules/customers/__integration__/TC-CRM-007.spec.js.map +0 -7
  116. package/dist/modules/customers/__integration__/TC-CRM-008.spec.js +0 -50
  117. package/dist/modules/customers/__integration__/TC-CRM-008.spec.js.map +0 -7
  118. package/dist/modules/customers/__integration__/TC-CRM-009.spec.js +0 -33
  119. package/dist/modules/customers/__integration__/TC-CRM-009.spec.js.map +0 -7
  120. package/dist/modules/customers/__integration__/TC-CRM-010.spec.js +0 -39
  121. package/dist/modules/customers/__integration__/TC-CRM-010.spec.js.map +0 -7
  122. package/dist/modules/customers/__integration__/TC-CRM-011.spec.js +0 -37
  123. package/dist/modules/customers/__integration__/TC-CRM-011.spec.js.map +0 -7
  124. package/dist/modules/customers/__integration__/TC-CRM-012.spec.js +0 -38
  125. package/dist/modules/customers/__integration__/TC-CRM-012.spec.js.map +0 -7
  126. package/dist/modules/customers/__integration__/TC-CRM-013.spec.js +0 -43
  127. package/dist/modules/customers/__integration__/TC-CRM-013.spec.js.map +0 -7
  128. package/dist/modules/customers/__integration__/TC-CRM-014.spec.js +0 -23
  129. package/dist/modules/customers/__integration__/TC-CRM-014.spec.js.map +0 -7
  130. package/dist/modules/customers/__integration__/TC-CRM-015.spec.js +0 -63
  131. package/dist/modules/customers/__integration__/TC-CRM-015.spec.js.map +0 -7
  132. package/dist/modules/customers/__integration__/TC-CRM-016.spec.js +0 -46
  133. package/dist/modules/customers/__integration__/TC-CRM-016.spec.js.map +0 -7
  134. package/dist/modules/customers/__integration__/TC-CRM-017.spec.js +0 -29
  135. package/dist/modules/customers/__integration__/TC-CRM-017.spec.js.map +0 -7
  136. package/dist/modules/customers/__integration__/TC-CRM-018.spec.js +0 -52
  137. package/dist/modules/customers/__integration__/TC-CRM-018.spec.js.map +0 -7
  138. package/dist/modules/customers/__integration__/TC-CRM-019.spec.js +0 -37
  139. package/dist/modules/customers/__integration__/TC-CRM-019.spec.js.map +0 -7
  140. package/dist/modules/customers/__integration__/TC-CRM-020.spec.js +0 -65
  141. package/dist/modules/customers/__integration__/TC-CRM-020.spec.js.map +0 -7
  142. package/dist/modules/progress/__integration__/TC-PROG-001.spec.js +0 -51
  143. package/dist/modules/progress/__integration__/TC-PROG-001.spec.js.map +0 -7
  144. package/dist/modules/resources/__integration__/TC-INT-007.spec.js +0 -88
  145. package/dist/modules/resources/__integration__/TC-INT-007.spec.js.map +0 -7
  146. package/dist/modules/resources/__integration__/helpers/resourcesFixtures.js +0 -45
  147. package/dist/modules/resources/__integration__/helpers/resourcesFixtures.js.map +0 -7
  148. package/dist/modules/sales/__integration__/TC-SALES-001.spec.js +0 -20
  149. package/dist/modules/sales/__integration__/TC-SALES-001.spec.js.map +0 -7
  150. package/dist/modules/sales/__integration__/TC-SALES-002.spec.js +0 -31
  151. package/dist/modules/sales/__integration__/TC-SALES-002.spec.js.map +0 -7
  152. package/dist/modules/sales/__integration__/TC-SALES-003.spec.js +0 -13
  153. package/dist/modules/sales/__integration__/TC-SALES-003.spec.js.map +0 -7
  154. package/dist/modules/sales/__integration__/TC-SALES-004.spec.js +0 -14
  155. package/dist/modules/sales/__integration__/TC-SALES-004.spec.js.map +0 -7
  156. package/dist/modules/sales/__integration__/TC-SALES-005.spec.js +0 -15
  157. package/dist/modules/sales/__integration__/TC-SALES-005.spec.js.map +0 -7
  158. package/dist/modules/sales/__integration__/TC-SALES-006.spec.js +0 -20
  159. package/dist/modules/sales/__integration__/TC-SALES-006.spec.js.map +0 -7
  160. package/dist/modules/sales/__integration__/TC-SALES-007.spec.js +0 -19
  161. package/dist/modules/sales/__integration__/TC-SALES-007.spec.js.map +0 -7
  162. package/dist/modules/sales/__integration__/TC-SALES-008.spec.js +0 -7
  163. package/dist/modules/sales/__integration__/TC-SALES-008.spec.js.map +0 -7
  164. package/dist/modules/sales/__integration__/TC-SALES-009.spec.js +0 -7
  165. package/dist/modules/sales/__integration__/TC-SALES-009.spec.js.map +0 -7
  166. package/dist/modules/sales/__integration__/TC-SALES-010.spec.js +0 -16
  167. package/dist/modules/sales/__integration__/TC-SALES-010.spec.js.map +0 -7
  168. package/dist/modules/sales/__integration__/TC-SALES-011.spec.js +0 -20
  169. package/dist/modules/sales/__integration__/TC-SALES-011.spec.js.map +0 -7
  170. package/dist/modules/sales/__integration__/TC-SALES-012.spec.js +0 -7
  171. package/dist/modules/sales/__integration__/TC-SALES-012.spec.js.map +0 -7
  172. package/dist/modules/sales/__integration__/TC-SALES-013.spec.js +0 -66
  173. package/dist/modules/sales/__integration__/TC-SALES-013.spec.js.map +0 -7
  174. package/dist/modules/sales/__integration__/TC-SALES-014.spec.js +0 -13
  175. package/dist/modules/sales/__integration__/TC-SALES-014.spec.js.map +0 -7
  176. package/dist/modules/sales/__integration__/TC-SALES-015.spec.js +0 -13
  177. package/dist/modules/sales/__integration__/TC-SALES-015.spec.js.map +0 -7
  178. package/dist/modules/sales/__integration__/TC-SALES-016.spec.js +0 -13
  179. package/dist/modules/sales/__integration__/TC-SALES-016.spec.js.map +0 -7
  180. package/dist/modules/sales/__integration__/TC-SALES-017.spec.js +0 -44
  181. package/dist/modules/sales/__integration__/TC-SALES-017.spec.js.map +0 -7
  182. package/dist/modules/sales/__integration__/TC-SALES-018.spec.js +0 -18
  183. package/dist/modules/sales/__integration__/TC-SALES-018.spec.js.map +0 -7
  184. package/dist/modules/sales/__integration__/TC-SALES-019.spec.js +0 -16
  185. package/dist/modules/sales/__integration__/TC-SALES-019.spec.js.map +0 -7
  186. package/dist/modules/sales/__integration__/TC-SALES-020.spec.js +0 -75
  187. package/dist/modules/sales/__integration__/TC-SALES-020.spec.js.map +0 -7
  188. package/dist/modules/staff/__integration__/TC-INT-006.spec.js +0 -64
  189. package/dist/modules/staff/__integration__/TC-INT-006.spec.js.map +0 -7
  190. package/dist/modules/translations/__integration__/TC-TRANS-001.spec.js +0 -48
  191. package/dist/modules/translations/__integration__/TC-TRANS-001.spec.js.map +0 -7
  192. package/dist/modules/translations/__integration__/TC-TRANS-002.spec.js +0 -94
  193. package/dist/modules/translations/__integration__/TC-TRANS-002.spec.js.map +0 -7
  194. package/dist/modules/translations/__integration__/TC-TRANS-003.spec.js +0 -61
  195. package/dist/modules/translations/__integration__/TC-TRANS-003.spec.js.map +0 -7
  196. package/dist/modules/translations/__integration__/TC-TRANS-004.spec.js +0 -52
  197. package/dist/modules/translations/__integration__/TC-TRANS-004.spec.js.map +0 -7
  198. package/dist/modules/translations/__integration__/TC-TRANS-005.spec.js +0 -106
  199. package/dist/modules/translations/__integration__/TC-TRANS-005.spec.js.map +0 -7
  200. package/dist/modules/translations/__integration__/TC-TRANS-006.spec.js +0 -94
  201. package/dist/modules/translations/__integration__/TC-TRANS-006.spec.js.map +0 -7
  202. package/dist/modules/translations/__integration__/TC-TRANS-007.spec.js +0 -62
  203. package/dist/modules/translations/__integration__/TC-TRANS-007.spec.js.map +0 -7
  204. package/dist/modules/translations/__integration__/TC-TRANS-008.spec.js +0 -168
  205. package/dist/modules/translations/__integration__/TC-TRANS-008.spec.js.map +0 -7
  206. package/dist/modules/translations/__integration__/helpers/translationFixtures.js +0 -63
  207. package/dist/modules/translations/__integration__/helpers/translationFixtures.js.map +0 -7
  208. package/dist/modules/workflows/__integration__/TC-WF-001.spec.js +0 -73
  209. package/dist/modules/workflows/__integration__/TC-WF-001.spec.js.map +0 -7
  210. package/src/__tests__/module-decoupling.test.ts +0 -356
  211. package/src/modules/api_keys/api/__tests__/keys.route.test.ts +0 -244
  212. package/src/modules/attachments/api/__tests__/attachments.api.test.ts +0 -240
  213. package/src/modules/attachments/components/__tests__/AttachmentContentPreview.test.tsx +0 -45
  214. package/src/modules/attachments/data/__tests__/entities-ocr.test.ts +0 -15
  215. package/src/modules/attachments/lib/__tests__/ocr-config.test.ts +0 -27
  216. package/src/modules/attachments/lib/__tests__/textExtraction.test.ts +0 -64
  217. package/src/modules/audit_logs/api/__tests__/access.route.test.ts +0 -118
  218. package/src/modules/audit_logs/api/__tests__/redo.route.test.ts +0 -131
  219. package/src/modules/audit_logs/api/__tests__/undo.route.test.ts +0 -103
  220. package/src/modules/audit_logs/services/__tests__/actionLogService.test.ts +0 -26
  221. package/src/modules/auth/__integration__/TC-AUTH-001.spec.ts +0 -13
  222. package/src/modules/auth/__integration__/TC-AUTH-002.spec.ts +0 -30
  223. package/src/modules/auth/__integration__/TC-AUTH-003.spec.ts +0 -28
  224. package/src/modules/auth/__integration__/TC-AUTH-004.spec.ts +0 -21
  225. package/src/modules/auth/__integration__/TC-AUTH-005.spec.ts +0 -17
  226. package/src/modules/auth/__integration__/TC-AUTH-006.spec.ts +0 -17
  227. package/src/modules/auth/__integration__/TC-AUTH-007.spec.ts +0 -19
  228. package/src/modules/auth/__integration__/TC-AUTH-008.spec.ts +0 -31
  229. package/src/modules/auth/__integration__/TC-AUTH-009.spec.ts +0 -22
  230. package/src/modules/auth/__integration__/TC-AUTH-010.spec.ts +0 -39
  231. package/src/modules/auth/__integration__/TC-AUTH-011.spec.ts +0 -35
  232. package/src/modules/auth/__integration__/TC-AUTH-012.spec.ts +0 -36
  233. package/src/modules/auth/__integration__/TC-AUTH-013.spec.ts +0 -48
  234. package/src/modules/auth/__integration__/TC-AUTH-014.spec.ts +0 -31
  235. package/src/modules/auth/__integration__/TC-AUTH-015.spec.ts +0 -28
  236. package/src/modules/auth/__integration__/TC-AUTH-016.spec.ts +0 -109
  237. package/src/modules/auth/__tests__/cli-rotate-encryption.test.ts +0 -97
  238. package/src/modules/auth/__tests__/cli-setup-acl.test.ts +0 -148
  239. package/src/modules/auth/api/__tests__/feature-check.test.ts +0 -65
  240. package/src/modules/auth/api/__tests__/login.test.ts +0 -47
  241. package/src/modules/auth/commands/__tests__/roles.custom-fields.test.ts +0 -126
  242. package/src/modules/auth/commands/__tests__/users.custom-fields.test.ts +0 -147
  243. package/src/modules/auth/lib/__tests__/rateLimitCheck.test.ts +0 -224
  244. package/src/modules/auth/services/__tests__/authService.test.ts +0 -32
  245. package/src/modules/auth/services/__tests__/rbacService.test.ts +0 -814
  246. package/src/modules/business_rules/api/__tests__/execute.route.test.ts +0 -311
  247. package/src/modules/business_rules/api/__tests__/logs-detail.route.test.ts +0 -181
  248. package/src/modules/business_rules/api/__tests__/logs.route.test.ts +0 -261
  249. package/src/modules/business_rules/api/__tests__/rules-detail.route.test.ts +0 -115
  250. package/src/modules/business_rules/api/__tests__/rules.route.test.ts +0 -746
  251. package/src/modules/business_rules/api/__tests__/sets-detail.route.test.ts +0 -169
  252. package/src/modules/business_rules/api/__tests__/sets-members.route.test.ts +0 -367
  253. package/src/modules/business_rules/api/__tests__/sets.route.test.ts +0 -361
  254. package/src/modules/business_rules/api/__tests__/test-helpers.ts +0 -42
  255. package/src/modules/business_rules/components/utils/__tests__/formHelpers.test.ts +0 -69
  256. package/src/modules/business_rules/data/__tests__/validators.test.ts +0 -637
  257. package/src/modules/business_rules/lib/__tests__/action-executor.test.ts +0 -728
  258. package/src/modules/business_rules/lib/__tests__/expression-evaluator.test.ts +0 -592
  259. package/src/modules/business_rules/lib/__tests__/rule-engine.test.ts +0 -805
  260. package/src/modules/business_rules/lib/__tests__/rule-evaluator.test.ts +0 -436
  261. package/src/modules/catalog/__integration__/TC-CAT-001.spec.ts +0 -32
  262. package/src/modules/catalog/__integration__/TC-CAT-002.spec.ts +0 -19
  263. package/src/modules/catalog/__integration__/TC-CAT-003.spec.ts +0 -39
  264. package/src/modules/catalog/__integration__/TC-CAT-004.spec.ts +0 -41
  265. package/src/modules/catalog/__integration__/TC-CAT-005.spec.ts +0 -37
  266. package/src/modules/catalog/__integration__/TC-CAT-006.spec.ts +0 -40
  267. package/src/modules/catalog/__integration__/TC-CAT-007.spec.ts +0 -37
  268. package/src/modules/catalog/__integration__/TC-CAT-008.spec.ts +0 -76
  269. package/src/modules/catalog/__integration__/TC-CAT-009.spec.ts +0 -39
  270. package/src/modules/catalog/__integration__/TC-CAT-010.spec.ts +0 -36
  271. package/src/modules/catalog/__integration__/TC-CAT-011.spec.ts +0 -44
  272. package/src/modules/catalog/__integration__/TC-CAT-012.spec.ts +0 -35
  273. package/src/modules/catalog/api/__tests__/offers.route.test.ts +0 -161
  274. package/src/modules/catalog/api/__tests__/prices.route.test.ts +0 -39
  275. package/src/modules/catalog/api/__tests__/products.route.test.ts +0 -91
  276. package/src/modules/catalog/api/__tests__/utils.test.ts +0 -36
  277. package/src/modules/catalog/api/__tests__/variants.route.test.ts +0 -44
  278. package/src/modules/catalog/backend/catalog/products/__tests__/ProductsDataTable.test.tsx +0 -172
  279. package/src/modules/catalog/commands/__tests__/products.delete.test.ts +0 -146
  280. package/src/modules/catalog/commands/__tests__/products.update.test.ts +0 -142
  281. package/src/modules/catalog/commands/__tests__/registration.test.ts +0 -54
  282. package/src/modules/catalog/commands/__tests__/shared.test.ts +0 -129
  283. package/src/modules/catalog/components/__tests__/catalogComponentsRender.test.tsx +0 -373
  284. package/src/modules/catalog/components/products/__tests__/ProductImageCell.test.tsx +0 -51
  285. package/src/modules/catalog/components/products/__tests__/productForm.test.ts +0 -32
  286. package/src/modules/catalog/lib/__tests__/pricing.test.ts +0 -150
  287. package/src/modules/catalog/services/__tests__/catalogPricingService.test.ts +0 -21
  288. package/src/modules/configs/components/__tests__/CachePanel.test.tsx +0 -134
  289. package/src/modules/configs/components/__tests__/SystemStatusPanel.test.tsx +0 -93
  290. package/src/modules/configs/lib/__tests__/system-status.test.ts +0 -55
  291. package/src/modules/configs/lib/__tests__/upgrade-actions.test.ts +0 -135
  292. package/src/modules/core/__integration__/admin/TC-ADMIN-001.spec.ts +0 -70
  293. package/src/modules/core/__integration__/admin/TC-ADMIN-002.spec.ts +0 -83
  294. package/src/modules/core/__integration__/admin/TC-ADMIN-003.spec.ts +0 -50
  295. package/src/modules/core/__integration__/admin/TC-ADMIN-004.spec.ts +0 -77
  296. package/src/modules/core/__integration__/admin/TC-ADMIN-005.spec.ts +0 -49
  297. package/src/modules/core/__integration__/admin/TC-ADMIN-006.spec.ts +0 -59
  298. package/src/modules/core/__integration__/admin/TC-ADMIN-007.spec.ts +0 -68
  299. package/src/modules/core/__integration__/admin/TC-ADMIN-008.spec.ts +0 -127
  300. package/src/modules/core/__integration__/admin/TC-ADMIN-009.spec.ts +0 -48
  301. package/src/modules/core/__integration__/admin/TC-ADMIN-010.spec.ts +0 -57
  302. package/src/modules/core/__integration__/helpers/api.ts +0 -84
  303. package/src/modules/core/__integration__/helpers/auth.ts +0 -110
  304. package/src/modules/core/__integration__/helpers/authUi.ts +0 -33
  305. package/src/modules/core/__integration__/helpers/catalogFixtures.ts +0 -73
  306. package/src/modules/core/__integration__/helpers/crmFixtures.ts +0 -101
  307. package/src/modules/core/__integration__/helpers/salesFixtures.ts +0 -89
  308. package/src/modules/core/__integration__/helpers/salesUi.ts +0 -528
  309. package/src/modules/core/__integration__/integration/TC-INT-001.spec.ts +0 -34
  310. package/src/modules/core/__integration__/integration/TC-INT-002.spec.ts +0 -74
  311. package/src/modules/core/__integration__/integration/TC-INT-003.spec.ts +0 -43
  312. package/src/modules/core/__integration__/integration/TC-INT-004.spec.ts +0 -82
  313. package/src/modules/core/__integration__/integration/TC-INT-005.spec.ts +0 -29
  314. package/src/modules/currencies/backend/exchange-rates/__tests__/formatDateTimeLocal.test.ts +0 -78
  315. package/src/modules/currencies/data/__tests__/validators.test.ts +0 -100
  316. package/src/modules/currencies/services/__tests__/exchangeRateService.test.ts +0 -666
  317. package/src/modules/currencies/services/__tests__/rateFetchingService.basic.test.ts +0 -398
  318. package/src/modules/currencies/services/__tests__/rateFetchingService.errors.test.ts +0 -296
  319. package/src/modules/currencies/services/__tests__/rateFetchingService.providers.test.ts +0 -350
  320. package/src/modules/currencies/services/__tests__/rateFetchingService.setup.ts +0 -188
  321. package/src/modules/customers/__integration__/TC-CRM-001.spec.ts +0 -42
  322. package/src/modules/customers/__integration__/TC-CRM-002.spec.ts +0 -47
  323. package/src/modules/customers/__integration__/TC-CRM-003.spec.ts +0 -55
  324. package/src/modules/customers/__integration__/TC-CRM-004.spec.ts +0 -57
  325. package/src/modules/customers/__integration__/TC-CRM-005.spec.ts +0 -50
  326. package/src/modules/customers/__integration__/TC-CRM-006.spec.ts +0 -60
  327. package/src/modules/customers/__integration__/TC-CRM-007.spec.ts +0 -57
  328. package/src/modules/customers/__integration__/TC-CRM-008.spec.ts +0 -62
  329. package/src/modules/customers/__integration__/TC-CRM-009.spec.ts +0 -46
  330. package/src/modules/customers/__integration__/TC-CRM-010.spec.ts +0 -49
  331. package/src/modules/customers/__integration__/TC-CRM-011.spec.ts +0 -47
  332. package/src/modules/customers/__integration__/TC-CRM-012.spec.ts +0 -49
  333. package/src/modules/customers/__integration__/TC-CRM-013.spec.ts +0 -61
  334. package/src/modules/customers/__integration__/TC-CRM-014.spec.ts +0 -31
  335. package/src/modules/customers/__integration__/TC-CRM-015.spec.ts +0 -89
  336. package/src/modules/customers/__integration__/TC-CRM-016.spec.ts +0 -55
  337. package/src/modules/customers/__integration__/TC-CRM-017.spec.ts +0 -37
  338. package/src/modules/customers/__integration__/TC-CRM-018.spec.ts +0 -62
  339. package/src/modules/customers/__integration__/TC-CRM-019.spec.ts +0 -44
  340. package/src/modules/customers/__integration__/TC-CRM-020.spec.ts +0 -73
  341. package/src/modules/customers/api/__tests__/utils.test.ts +0 -61
  342. package/src/modules/customers/api/dashboard/widgets/new-deals/__tests__/route.test.ts +0 -54
  343. package/src/modules/customers/commands/__tests__/shared.test.ts +0 -263
  344. package/src/modules/customers/commands/__tests__/undo.custom-fields.test.ts +0 -1184
  345. package/src/modules/customers/components/detail/__tests__/ActivityForm.validation.test.ts +0 -37
  346. package/src/modules/customers/components/detail/__tests__/DealForm.validation.test.ts +0 -45
  347. package/src/modules/customers/components/detail/__tests__/InlineEditors.test.tsx +0 -166
  348. package/src/modules/customers/components/detail/__tests__/TaskForm.submit.test.ts +0 -21
  349. package/src/modules/customers/components/detail/hooks/__tests__/useCustomerDictionary.test.ts +0 -97
  350. package/src/modules/customers/lib/__tests__/customFieldRouting.test.ts +0 -107
  351. package/src/modules/customers/utils/__tests__/addressFormat.test.ts +0 -105
  352. package/src/modules/customers/utils/__tests__/phoneDuplicates.test.ts +0 -98
  353. package/src/modules/dashboards/__tests__/widgets.test.ts +0 -70
  354. package/src/modules/dashboards/lib/__tests__/aggregations.test.ts +0 -328
  355. package/src/modules/dashboards/lib/__tests__/formatters.test.ts +0 -128
  356. package/src/modules/directory/backend/directory/organizations/__tests__/create-submit.test.ts +0 -46
  357. package/src/modules/directory/backend/directory/organizations/__tests__/edit-submit.test.ts +0 -49
  358. package/src/modules/directory/components/__tests__/OrganizationSelect.test.tsx +0 -71
  359. package/src/modules/directory/components/__tests__/TenantSelect.test.tsx +0 -75
  360. package/src/modules/entities/__tests__/cli-decrypt-database.test.ts +0 -534
  361. package/src/modules/entities/__tests__/cli-rotate-encryption.test.ts +0 -123
  362. package/src/modules/entities/api/__tests__/encryption.api.test.ts +0 -57
  363. package/src/modules/entities/api/__tests__/records.get.custom-entity.test.ts +0 -43
  364. package/src/modules/entities/api/__tests__/records.validation.test.ts +0 -53
  365. package/src/modules/entities/backend/entities/user/__tests__/create-entity-submit.test.ts +0 -47
  366. package/src/modules/entities/backend/entities/user/__tests__/records-submit.test.ts +0 -104
  367. package/src/modules/feature_toggles/commands/__tests__/global.test.ts +0 -325
  368. package/src/modules/feature_toggles/commands/__tests__/overrides.test.ts +0 -186
  369. package/src/modules/feature_toggles/lib/__tests__/feature-flag-check.test.ts +0 -365
  370. package/src/modules/feature_toggles/lib/__tests__/queries.test.ts +0 -130
  371. package/src/modules/inbox_ops/api/emails/[id]/reprocess/__tests__/route.test.ts +0 -194
  372. package/src/modules/inbox_ops/api/proposals/[id]/__tests__/route.test.ts +0 -124
  373. package/src/modules/inbox_ops/api/proposals/[id]/accept-all/__tests__/route.test.ts +0 -154
  374. package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/__tests__/route.test.ts +0 -200
  375. package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/accept/__tests__/route.test.ts +0 -261
  376. package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/reject/__tests__/route.test.ts +0 -201
  377. package/src/modules/inbox_ops/api/proposals/[id]/reject/__tests__/route.test.ts +0 -123
  378. package/src/modules/inbox_ops/api/proposals/[id]/replies/[replyId]/send/__tests__/route.test.ts +0 -232
  379. package/src/modules/inbox_ops/api/proposals/[id]/translate/__tests__/route.test.ts +0 -173
  380. package/src/modules/inbox_ops/api/proposals/__tests__/route.test.ts +0 -185
  381. package/src/modules/inbox_ops/api/webhook/__tests__/inbound.test.ts +0 -317
  382. package/src/modules/inbox_ops/data/__tests__/validators.test.ts +0 -463
  383. package/src/modules/inbox_ops/lib/__tests__/catalogLookup.test.ts +0 -143
  384. package/src/modules/inbox_ops/lib/__tests__/contactMatcher.test.ts +0 -158
  385. package/src/modules/inbox_ops/lib/__tests__/emailParser.test.ts +0 -191
  386. package/src/modules/inbox_ops/lib/__tests__/executionEngine.test.ts +0 -1419
  387. package/src/modules/inbox_ops/lib/__tests__/extractionPrompt.test.ts +0 -151
  388. package/src/modules/inbox_ops/lib/__tests__/priceValidator.test.ts +0 -259
  389. package/src/modules/inbox_ops/lib/__tests__/translationProvider.test.ts +0 -99
  390. package/src/modules/inbox_ops/subscribers/__tests__/extractionWorker.test.ts +0 -803
  391. package/src/modules/notifications/__tests__/deliver-notification.test.ts +0 -285
  392. package/src/modules/notifications/__tests__/deliveryStrategies.test.ts +0 -19
  393. package/src/modules/notifications/__tests__/notificationService.test.ts +0 -248
  394. package/src/modules/planner/__tests__/availabilityMerge.test.ts +0 -99
  395. package/src/modules/planner/__tests__/plannerAvailabilityService.test.ts +0 -89
  396. package/src/modules/planner/data/__tests__/validators.test.ts +0 -78
  397. package/src/modules/progress/__integration__/TC-PROG-001.spec.ts +0 -67
  398. package/src/modules/progress/__tests__/progressService.test.ts +0 -377
  399. package/src/modules/query_index/__tests__/hybrid-engine.test.ts +0 -365
  400. package/src/modules/query_index/__tests__/indexer.test.ts +0 -175
  401. package/src/modules/resources/__integration__/TC-INT-007.spec.ts +0 -110
  402. package/src/modules/resources/__integration__/helpers/resourcesFixtures.ts +0 -50
  403. package/src/modules/resources/data/__tests__/validators.test.ts +0 -65
  404. package/src/modules/sales/__integration__/TC-SALES-001.spec.ts +0 -26
  405. package/src/modules/sales/__integration__/TC-SALES-002.spec.ts +0 -38
  406. package/src/modules/sales/__integration__/TC-SALES-003.spec.ts +0 -18
  407. package/src/modules/sales/__integration__/TC-SALES-004.spec.ts +0 -19
  408. package/src/modules/sales/__integration__/TC-SALES-005.spec.ts +0 -21
  409. package/src/modules/sales/__integration__/TC-SALES-006.spec.ts +0 -26
  410. package/src/modules/sales/__integration__/TC-SALES-007.spec.ts +0 -23
  411. package/src/modules/sales/__integration__/TC-SALES-008.spec.ts +0 -11
  412. package/src/modules/sales/__integration__/TC-SALES-009.spec.ts +0 -12
  413. package/src/modules/sales/__integration__/TC-SALES-010.spec.ts +0 -20
  414. package/src/modules/sales/__integration__/TC-SALES-011.spec.ts +0 -26
  415. package/src/modules/sales/__integration__/TC-SALES-012.spec.ts +0 -12
  416. package/src/modules/sales/__integration__/TC-SALES-013.spec.ts +0 -73
  417. package/src/modules/sales/__integration__/TC-SALES-014.spec.ts +0 -17
  418. package/src/modules/sales/__integration__/TC-SALES-015.spec.ts +0 -17
  419. package/src/modules/sales/__integration__/TC-SALES-016.spec.ts +0 -17
  420. package/src/modules/sales/__integration__/TC-SALES-017.spec.ts +0 -60
  421. package/src/modules/sales/__integration__/TC-SALES-018.spec.ts +0 -25
  422. package/src/modules/sales/__integration__/TC-SALES-019.spec.ts +0 -22
  423. package/src/modules/sales/__integration__/TC-SALES-020.spec.ts +0 -107
  424. package/src/modules/sales/api/__tests__/channels.route.test.ts +0 -50
  425. package/src/modules/sales/api/__tests__/document-history.test.ts +0 -146
  426. package/src/modules/sales/api/__tests__/documents.factory.test.ts +0 -98
  427. package/src/modules/sales/api/__tests__/documents.routes.test.ts +0 -149
  428. package/src/modules/sales/api/__tests__/quotes.acceptance.test.ts +0 -209
  429. package/src/modules/sales/api/__tests__/timeline.test.tsx +0 -165
  430. package/src/modules/sales/api/dashboard/widgets/new-orders/__tests__/route.test.ts +0 -112
  431. package/src/modules/sales/api/dashboard/widgets/new-quotes/__tests__/route.test.ts +0 -116
  432. package/src/modules/sales/commands/__tests__/documents.cache.test.ts +0 -126
  433. package/src/modules/sales/commands/__tests__/documents.undo.test.ts +0 -170
  434. package/src/modules/sales/commands/__tests__/registration.test.ts +0 -141
  435. package/src/modules/sales/components/__tests__/salesComponentsRender.test.tsx +0 -456
  436. package/src/modules/sales/lib/__tests__/calculations.test.ts +0 -210
  437. package/src/modules/sales/services/__tests__/salesCalculationService.test.ts +0 -181
  438. package/src/modules/sales/services/__tests__/taxCalculationService.test.ts +0 -79
  439. package/src/modules/sales/widgets/dashboard/new-orders/__tests__/config.test.ts +0 -47
  440. package/src/modules/sales/widgets/dashboard/new-quotes/__tests__/config.test.ts +0 -47
  441. package/src/modules/staff/__integration__/TC-INT-006.spec.ts +0 -71
  442. package/src/modules/staff/data/__tests__/validators.test.ts +0 -60
  443. package/src/modules/translations/__integration__/TC-TRANS-001.spec.ts +0 -57
  444. package/src/modules/translations/__integration__/TC-TRANS-002.spec.ts +0 -114
  445. package/src/modules/translations/__integration__/TC-TRANS-003.spec.ts +0 -71
  446. package/src/modules/translations/__integration__/TC-TRANS-004.spec.ts +0 -66
  447. package/src/modules/translations/__integration__/TC-TRANS-005.spec.ts +0 -135
  448. package/src/modules/translations/__integration__/TC-TRANS-006.spec.ts +0 -113
  449. package/src/modules/translations/__integration__/TC-TRANS-007.spec.ts +0 -80
  450. package/src/modules/translations/__integration__/TC-TRANS-008.spec.ts +0 -209
  451. package/src/modules/translations/__integration__/helpers/translationFixtures.ts +0 -95
  452. package/src/modules/translations/api/__tests__/locales.test.ts +0 -67
  453. package/src/modules/translations/data/__tests__/validators.test.ts +0 -143
  454. package/src/modules/translations/lib/__tests__/extract-record-id.test.ts +0 -75
  455. package/src/modules/translations/lib/__tests__/helpers.test.ts +0 -215
  456. package/src/modules/translations/lib/__tests__/locale.test.ts +0 -115
  457. package/src/modules/translations/lib/__tests__/resolve-field-list.test.ts +0 -176
  458. package/src/modules/translations/lib/__tests__/translatable-fields.test.ts +0 -79
  459. package/src/modules/translations/widgets/__tests__/injection-table.test.ts +0 -83
  460. package/src/modules/workflows/__integration__/TC-WF-001.spec.ts +0 -114
  461. package/src/modules/workflows/api/__tests__/definitions.route.test.ts +0 -762
  462. package/src/modules/workflows/api/__tests__/instances.route.test.ts +0 -869
  463. package/src/modules/workflows/data/__tests__/validators.test.ts +0 -707
  464. package/src/modules/workflows/lib/__tests__/activity-executor.test.ts +0 -1230
  465. package/src/modules/workflows/lib/__tests__/call-api.test.ts +0 -421
  466. package/src/modules/workflows/lib/__tests__/compensation.test.ts +0 -713
  467. package/src/modules/workflows/lib/__tests__/event-logger.test.ts +0 -615
  468. package/src/modules/workflows/lib/__tests__/integration.test.ts +0 -693
  469. package/src/modules/workflows/lib/__tests__/signals.test.ts +0 -566
  470. package/src/modules/workflows/lib/__tests__/step-handler.test.ts +0 -670
  471. package/src/modules/workflows/lib/__tests__/sub-workflow.test.ts +0 -934
  472. package/src/modules/workflows/lib/__tests__/transition-handler.test.ts +0 -925
  473. package/src/modules/workflows/lib/__tests__/workflow-executor.test.ts +0 -684
@@ -1,1419 +0,0 @@
1
- /** @jest-environment node */
2
-
3
- import {
4
- executeAction,
5
- rejectAction,
6
- rejectProposal,
7
- recalculateProposalStatus,
8
- acceptAllActions,
9
- getRequiredFeature,
10
- } from '../executionEngine'
11
- import type { InboxProposalAction } from '../../data/entities'
12
-
13
- const mockFindOneWithDecryption = jest.fn()
14
- const mockFindWithDecryption = jest.fn()
15
-
16
- jest.mock('@open-mercato/shared/lib/encryption/find', () => ({
17
- findOneWithDecryption: (...args: unknown[]) => mockFindOneWithDecryption(...args),
18
- findWithDecryption: (...args: unknown[]) => mockFindWithDecryption(...args),
19
- }))
20
-
21
- function createMockEm() {
22
- const em: Record<string, jest.Mock> = {
23
- fork: jest.fn(),
24
- findOne: jest.fn(),
25
- find: jest.fn(),
26
- nativeUpdate: jest.fn(),
27
- flush: jest.fn(),
28
- }
29
- em.fork.mockReturnValue(em)
30
- em.flush.mockResolvedValue(undefined)
31
- return em
32
- }
33
-
34
- const mockRbacService = {
35
- userHasAllFeatures: jest.fn(),
36
- }
37
-
38
- const mockCommandBus = {
39
- execute: jest.fn(),
40
- }
41
-
42
- const mockEventBus = {
43
- emit: jest.fn(),
44
- }
45
-
46
- const mockContainer = {
47
- resolve: jest.fn((token: string) => {
48
- if (token === 'rbacService') return mockRbacService
49
- if (token === 'commandBus') return mockCommandBus
50
- return null
51
- }),
52
- }
53
-
54
- const MockCustomerEntity = class {} as unknown
55
- const MockSalesOrder = class {} as unknown
56
- const MockSalesShipment = class {} as unknown
57
- const MockSalesChannel = class {} as unknown
58
- const MockDictionary = class {} as unknown
59
- const MockDictionaryEntry = class {} as unknown
60
-
61
- function makeCtx(em: ReturnType<typeof createMockEm>, overrides?: Record<string, unknown>) {
62
- return {
63
- em,
64
- userId: 'user-1',
65
- tenantId: 'tenant-1',
66
- organizationId: 'org-1',
67
- eventBus: mockEventBus,
68
- container: mockContainer,
69
- entities: {
70
- CustomerEntity: MockCustomerEntity,
71
- SalesOrder: MockSalesOrder,
72
- SalesShipment: MockSalesShipment,
73
- SalesChannel: MockSalesChannel,
74
- Dictionary: MockDictionary,
75
- DictionaryEntry: MockDictionaryEntry,
76
- },
77
- ...overrides,
78
- } as any
79
- }
80
-
81
- const VALID_UUID = '123e4567-e89b-4d56-a456-426614174000'
82
- const VALID_UUID_2 = '123e4567-e89b-4d56-a456-426614174001'
83
-
84
- function makeAction(overrides?: Partial<InboxProposalAction>): InboxProposalAction {
85
- return {
86
- id: 'action-1',
87
- proposalId: 'proposal-1',
88
- actionType: 'create_order',
89
- status: 'pending',
90
- payload: {
91
- customerName: 'Test Customer',
92
- channelId: VALID_UUID,
93
- currencyCode: 'EUR',
94
- lineItems: [{ productName: 'Widget', quantity: '10' }],
95
- },
96
- tenantId: 'tenant-1',
97
- organizationId: 'org-1',
98
- sortOrder: 0,
99
- deletedAt: null,
100
- ...overrides,
101
- } as unknown as InboxProposalAction
102
- }
103
-
104
- describe('executionEngine', () => {
105
- beforeEach(() => {
106
- jest.clearAllMocks()
107
- mockRbacService.userHasAllFeatures.mockResolvedValue(true)
108
- mockEventBus.emit.mockResolvedValue(undefined)
109
- mockCommandBus.execute.mockResolvedValue({ result: {} })
110
- mockFindOneWithDecryption.mockResolvedValue(null)
111
- mockFindWithDecryption.mockResolvedValue([])
112
- mockContainer.resolve.mockImplementation((token: string) => {
113
- if (token === 'rbacService') return mockRbacService
114
- if (token === 'commandBus') return mockCommandBus
115
- return null
116
- })
117
- })
118
-
119
- describe('executeAction', () => {
120
- it('returns 403 when user lacks required feature', async () => {
121
- mockRbacService.userHasAllFeatures.mockResolvedValue(false)
122
- const em = createMockEm()
123
- const action = makeAction()
124
-
125
- const result = await executeAction(action, makeCtx(em))
126
-
127
- expect(result.success).toBe(false)
128
- expect(result.statusCode).toBe(403)
129
- expect(result.error).toContain('Insufficient permissions')
130
- expect(em.nativeUpdate).not.toHaveBeenCalled()
131
- })
132
-
133
- it('returns 409 when optimistic lock fails (action already processed)', async () => {
134
- const em = createMockEm()
135
- em.nativeUpdate.mockResolvedValue(0)
136
- const action = makeAction()
137
-
138
- const result = await executeAction(action, makeCtx(em))
139
-
140
- expect(result.success).toBe(false)
141
- expect(result.statusCode).toBe(409)
142
- expect(result.error).toContain('already processed')
143
- })
144
-
145
- it('executes action successfully and creates entity', async () => {
146
- const em = createMockEm()
147
- em.nativeUpdate.mockResolvedValue(1)
148
-
149
- const freshAction = makeAction({ status: 'processing' })
150
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
151
-
152
- mockCommandBus.execute.mockResolvedValue({ result: { orderId: 'order-1' } })
153
-
154
- const action = makeAction()
155
- const result = await executeAction(action, makeCtx(em))
156
-
157
- expect(result.success).toBe(true)
158
- expect(result.createdEntityId).toBe('order-1')
159
- expect(result.createdEntityType).toBe('sales_order')
160
- expect(freshAction.status).toBe('executed')
161
- expect(freshAction.executedByUserId).toBe('user-1')
162
- expect(freshAction.createdEntityId).toBe('order-1')
163
- })
164
-
165
- it('marks action as failed and emits failure event on error', async () => {
166
- const em = createMockEm()
167
- em.nativeUpdate.mockResolvedValue(1)
168
-
169
- const freshAction = makeAction({ status: 'processing' })
170
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
171
-
172
- mockCommandBus.execute.mockRejectedValue(new Error('Command failed'))
173
-
174
- const action = makeAction()
175
- const result = await executeAction(action, makeCtx(em))
176
-
177
- expect(result.success).toBe(false)
178
- expect(result.error).toBe('Command failed')
179
- expect(freshAction.status).toBe('failed')
180
- expect(freshAction.executionError).toBe('Command failed')
181
- expect(mockEventBus.emit).toHaveBeenCalledWith(
182
- 'inbox_ops.action.failed',
183
- expect.objectContaining({ actionId: freshAction.id }),
184
- )
185
- })
186
-
187
- it('emits action.executed event on success', async () => {
188
- const em = createMockEm()
189
- em.nativeUpdate.mockResolvedValue(1)
190
-
191
- const freshAction = makeAction({ status: 'processing' })
192
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
193
-
194
- mockCommandBus.execute.mockResolvedValue({ result: { orderId: 'order-1' } })
195
-
196
- const action = makeAction()
197
- await executeAction(action, makeCtx(em))
198
-
199
- expect(mockEventBus.emit).toHaveBeenCalledWith(
200
- 'inbox_ops.action.executed',
201
- expect.objectContaining({
202
- actionId: freshAction.id,
203
- actionType: 'create_order',
204
- createdEntityId: 'order-1',
205
- createdEntityType: 'sales_order',
206
- }),
207
- )
208
- })
209
- })
210
-
211
- describe('rejectAction', () => {
212
- it('rejects and recalculates proposal status', async () => {
213
- const em = createMockEm()
214
- em.nativeUpdate.mockResolvedValue(1)
215
-
216
- const action = makeAction()
217
- mockFindOneWithDecryption.mockResolvedValueOnce(action)
218
-
219
- await rejectAction(action, makeCtx(em))
220
-
221
- expect(em.nativeUpdate).toHaveBeenCalledWith(
222
- expect.anything(),
223
- expect.objectContaining({ id: 'action-1', status: { $in: ['pending', 'failed'] } }),
224
- expect.objectContaining({ status: 'rejected' }),
225
- )
226
- expect(mockEventBus.emit).toHaveBeenCalledWith(
227
- 'inbox_ops.action.rejected',
228
- expect.objectContaining({ actionId: 'action-1' }),
229
- )
230
- })
231
-
232
- it('is a no-op when action was already processed (claimed=0)', async () => {
233
- const em = createMockEm()
234
- em.nativeUpdate.mockResolvedValue(0)
235
- const action = makeAction({ status: 'executed' } as any)
236
-
237
- await rejectAction(action, makeCtx(em))
238
-
239
- expect(mockFindOneWithDecryption).not.toHaveBeenCalled()
240
- expect(mockEventBus.emit).not.toHaveBeenCalled()
241
- })
242
- })
243
-
244
- describe('rejectProposal', () => {
245
- it('bulk rejects all pending actions and resolves discrepancies', async () => {
246
- const em = createMockEm()
247
- em.nativeUpdate.mockResolvedValue(1)
248
-
249
- await rejectProposal('proposal-1', makeCtx(em))
250
-
251
- expect(em.nativeUpdate).toHaveBeenCalledWith(
252
- expect.anything(),
253
- expect.objectContaining({ proposalId: 'proposal-1', status: { $in: ['pending', 'failed'] } }),
254
- expect.objectContaining({ status: 'rejected' }),
255
- )
256
- expect(em.nativeUpdate).toHaveBeenCalledWith(
257
- expect.anything(),
258
- expect.objectContaining({ proposalId: 'proposal-1', resolved: false }),
259
- { resolved: true },
260
- )
261
- expect(mockEventBus.emit).toHaveBeenCalledWith(
262
- 'inbox_ops.proposal.rejected',
263
- expect.objectContaining({ proposalId: 'proposal-1' }),
264
- )
265
- })
266
- })
267
-
268
- describe('recalculateProposalStatus', () => {
269
- it('sets status to accepted when all actions are accepted/executed', async () => {
270
- const em = createMockEm()
271
- const proposal = { id: 'p-1', status: 'pending' }
272
- mockFindOneWithDecryption.mockResolvedValueOnce(proposal)
273
- mockFindWithDecryption.mockResolvedValueOnce([
274
- { status: 'executed' },
275
- { status: 'accepted' },
276
- ])
277
-
278
- await recalculateProposalStatus(em as any, 'p-1')
279
-
280
- expect(proposal.status).toBe('accepted')
281
- expect(em.flush).toHaveBeenCalled()
282
- })
283
-
284
- it('sets status to rejected when all actions are rejected', async () => {
285
- const em = createMockEm()
286
- const proposal = { id: 'p-1', status: 'pending' }
287
- mockFindOneWithDecryption.mockResolvedValueOnce(proposal)
288
- mockFindWithDecryption.mockResolvedValueOnce([
289
- { status: 'rejected' },
290
- { status: 'rejected' },
291
- ])
292
-
293
- await recalculateProposalStatus(em as any, 'p-1')
294
-
295
- expect(proposal.status).toBe('rejected')
296
- })
297
-
298
- it('sets status to partial when actions have mixed statuses', async () => {
299
- const em = createMockEm()
300
- const proposal = { id: 'p-1', status: 'pending' }
301
- mockFindOneWithDecryption.mockResolvedValueOnce(proposal)
302
- mockFindWithDecryption.mockResolvedValueOnce([
303
- { status: 'executed' },
304
- { status: 'pending' },
305
- ])
306
-
307
- await recalculateProposalStatus(em as any, 'p-1')
308
-
309
- expect(proposal.status).toBe('partial')
310
- })
311
-
312
- it('keeps status as pending when all actions are pending', async () => {
313
- const em = createMockEm()
314
- const proposal = { id: 'p-1', status: 'pending' }
315
- mockFindOneWithDecryption.mockResolvedValueOnce(proposal)
316
- mockFindWithDecryption.mockResolvedValueOnce([
317
- { status: 'pending' },
318
- { status: 'pending' },
319
- ])
320
-
321
- await recalculateProposalStatus(em as any, 'p-1')
322
-
323
- expect(proposal.status).toBe('pending')
324
- expect(em.flush).toHaveBeenCalledTimes(0)
325
- })
326
-
327
- it('sets status to pending when no actions exist', async () => {
328
- const em = createMockEm()
329
- const proposal = { id: 'p-1', status: 'partial' }
330
- mockFindOneWithDecryption.mockResolvedValueOnce(proposal)
331
- mockFindWithDecryption.mockResolvedValueOnce([])
332
-
333
- await recalculateProposalStatus(em as any, 'p-1')
334
-
335
- expect(proposal.status).toBe('pending')
336
- expect(em.flush).toHaveBeenCalled()
337
- })
338
- })
339
-
340
- describe('acceptAllActions', () => {
341
- it('executes actions in sort order and stops on first failure', async () => {
342
- const em = createMockEm()
343
- const action1 = makeAction({ id: 'a-1', sortOrder: 0 } as any)
344
- const action2 = makeAction({ id: 'a-2', sortOrder: 1 } as any)
345
-
346
- mockFindWithDecryption.mockResolvedValueOnce([action1, action2])
347
-
348
- // First executeAction: succeeds
349
- em.nativeUpdate.mockResolvedValueOnce(1)
350
- const freshAction1 = makeAction({ id: 'a-1', status: 'processing' })
351
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction1)
352
- mockCommandBus.execute.mockResolvedValueOnce({ result: { orderId: 'o-1' } })
353
-
354
- // Second executeAction: claim fails
355
- em.nativeUpdate.mockResolvedValueOnce(0)
356
-
357
- const { results, stoppedOnFailure } = await acceptAllActions('proposal-1', makeCtx(em))
358
-
359
- expect(results).toHaveLength(2)
360
- expect(results[0].success).toBe(true)
361
- expect(results[1].success).toBe(false)
362
- expect(stoppedOnFailure).toBe(true)
363
- })
364
-
365
- it('returns empty results when no pending actions', async () => {
366
- const em = createMockEm()
367
- mockFindWithDecryption.mockResolvedValueOnce([])
368
-
369
- const { results, stoppedOnFailure } = await acceptAllActions('proposal-1', makeCtx(em))
370
-
371
- expect(results).toHaveLength(0)
372
- expect(stoppedOnFailure).toBe(false)
373
- })
374
- })
375
-
376
- describe('executeAction — create_contact dedup', () => {
377
- it('returns existing contact instead of creating duplicate when email matches', async () => {
378
- const em = createMockEm()
379
- em.nativeUpdate.mockResolvedValue(1)
380
-
381
- const freshAction = makeAction({
382
- id: 'a-contact',
383
- actionType: 'create_contact',
384
- status: 'processing',
385
- payload: {
386
- type: 'person',
387
- name: 'Jane Doe',
388
- email: 'jane@example.com',
389
- source: 'inbox_ops',
390
- },
391
- })
392
- mockFindOneWithDecryption
393
- .mockResolvedValueOnce(freshAction)
394
- .mockResolvedValueOnce({
395
- id: 'existing-contact-1',
396
- entityType: 'person',
397
- primaryEmail: 'jane@example.com',
398
- })
399
-
400
- const action = makeAction({
401
- id: 'a-contact',
402
- actionType: 'create_contact',
403
- payload: {
404
- type: 'person',
405
- name: 'Jane Doe',
406
- email: 'jane@example.com',
407
- source: 'inbox_ops',
408
- },
409
- })
410
-
411
- const result = await executeAction(action, makeCtx(em))
412
-
413
- expect(result.success).toBe(true)
414
- expect(result.createdEntityId).toBe('existing-contact-1')
415
- expect(mockCommandBus.execute).not.toHaveBeenCalled()
416
- })
417
- })
418
-
419
- describe('executeAction — draft_reply no contact', () => {
420
- it('fails with clear error when no contact found for draft reply', async () => {
421
- const em = createMockEm()
422
- em.nativeUpdate.mockResolvedValue(1)
423
-
424
- const freshAction = makeAction({
425
- id: 'a-reply',
426
- actionType: 'draft_reply',
427
- status: 'processing',
428
- payload: {
429
- to: 'unknown@example.com',
430
- subject: 'Re: Order',
431
- body: 'Thank you for your order.',
432
- },
433
- })
434
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
435
-
436
- const action = makeAction({
437
- id: 'a-reply',
438
- actionType: 'draft_reply',
439
- payload: {
440
- to: 'unknown@example.com',
441
- subject: 'Re: Order',
442
- body: 'Thank you for your order.',
443
- },
444
- })
445
-
446
- const result = await executeAction(action, makeCtx(em))
447
-
448
- expect(result.success).toBe(false)
449
- expect(result.error).toContain('No matching contact found')
450
- expect(result.error).toContain('unknown@example.com')
451
- })
452
- })
453
-
454
- describe('acceptAllActions — partial failure', () => {
455
- it('stops on failure and leaves remaining actions as pending', async () => {
456
- const em = createMockEm()
457
-
458
- const action1 = makeAction({ id: 'a-1', sortOrder: 0 })
459
- const action2 = makeAction({ id: 'a-2', sortOrder: 1 })
460
- const action3 = makeAction({ id: 'a-3', sortOrder: 2 })
461
-
462
- mockFindWithDecryption.mockResolvedValueOnce([action1, action2, action3])
463
-
464
- // Action 1: succeeds
465
- em.nativeUpdate.mockResolvedValueOnce(1)
466
- const fresh1 = makeAction({ id: 'a-1', status: 'processing' })
467
- mockFindOneWithDecryption
468
- .mockResolvedValueOnce(fresh1) // fresh action 1
469
- .mockResolvedValueOnce(null) // SalesChannel lookup (resolveEffectiveDocumentKind)
470
- .mockResolvedValueOnce(null) // recalculateProposalStatus proposal (after action 1)
471
- mockCommandBus.execute.mockResolvedValueOnce({ result: { orderId: 'o-1' } })
472
-
473
- // Action 2: fails execution
474
- em.nativeUpdate.mockResolvedValueOnce(1)
475
- const fresh2 = makeAction({ id: 'a-2', status: 'processing' })
476
- mockFindOneWithDecryption
477
- .mockResolvedValueOnce(fresh2) // fresh action 2
478
- .mockResolvedValueOnce(null) // SalesChannel lookup (resolveEffectiveDocumentKind)
479
- mockCommandBus.execute.mockRejectedValueOnce(new Error('Inventory unavailable'))
480
-
481
- const { results, stoppedOnFailure } = await acceptAllActions('proposal-1', makeCtx(em))
482
-
483
- expect(results).toHaveLength(2)
484
- expect(results[0].success).toBe(true)
485
- expect(results[0].createdEntityId).toBe('o-1')
486
- expect(results[1].success).toBe(false)
487
- expect(results[1].error).toBe('Inventory unavailable')
488
- expect(stoppedOnFailure).toBe(true)
489
- // Action 3 was never attempted
490
- expect(fresh1.status).toBe('executed')
491
- expect(fresh2.status).toBe('failed')
492
- })
493
- })
494
-
495
- describe('executeAction — create_quote', () => {
496
- it('creates a quote via sales.quotes.create command', async () => {
497
- const em = createMockEm()
498
- em.nativeUpdate.mockResolvedValue(1)
499
-
500
- const freshAction = makeAction({
501
- id: 'a-quote',
502
- actionType: 'create_quote',
503
- status: 'processing',
504
- payload: {
505
- customerName: 'Acme Corp',
506
- channelId: VALID_UUID,
507
- currencyCode: 'EUR',
508
- lineItems: [{ productName: 'Service A', quantity: '5', kind: 'service' }],
509
- },
510
- })
511
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
512
-
513
- mockCommandBus.execute.mockResolvedValue({ result: { quoteId: 'quote-1' } })
514
-
515
- const action = makeAction({
516
- id: 'a-quote',
517
- actionType: 'create_quote',
518
- payload: {
519
- customerName: 'Acme Corp',
520
- channelId: VALID_UUID,
521
- currencyCode: 'EUR',
522
- lineItems: [{ productName: 'Service A', quantity: '5', kind: 'service' }],
523
- },
524
- })
525
-
526
- const result = await executeAction(action, makeCtx(em))
527
-
528
- expect(result.success).toBe(true)
529
- expect(result.createdEntityId).toBe('quote-1')
530
- expect(result.createdEntityType).toBe('sales_quote')
531
- expect(mockCommandBus.execute).toHaveBeenCalledWith(
532
- 'sales.quotes.create',
533
- expect.objectContaining({
534
- input: expect.objectContaining({ currencyCode: 'EUR' }),
535
- }),
536
- )
537
- })
538
- })
539
-
540
- describe('executeAction — create_order auto-switches to quote when channel requires it', () => {
541
- it('creates a quote instead of order when channel metadata.quotesRequired is true', async () => {
542
- const em = createMockEm()
543
- em.nativeUpdate.mockResolvedValue(1)
544
-
545
- const freshAction = makeAction({
546
- id: 'a-order-switch',
547
- actionType: 'create_order',
548
- status: 'processing',
549
- payload: {
550
- customerName: 'Acme Corp',
551
- channelId: VALID_UUID,
552
- currencyCode: 'EUR',
553
- lineItems: [{ productName: 'Widget', quantity: '10' }],
554
- },
555
- })
556
- mockFindOneWithDecryption
557
- .mockResolvedValueOnce(freshAction)
558
- .mockResolvedValueOnce({ id: VALID_UUID, name: 'Web', metadata: { quotesRequired: true } })
559
-
560
- mockCommandBus.execute.mockResolvedValue({ result: { quoteId: 'quote-auto-1' } })
561
-
562
- const action = makeAction({
563
- id: 'a-order-switch',
564
- actionType: 'create_order',
565
- payload: {
566
- customerName: 'Acme Corp',
567
- channelId: VALID_UUID,
568
- currencyCode: 'EUR',
569
- lineItems: [{ productName: 'Widget', quantity: '10' }],
570
- },
571
- })
572
-
573
- const result = await executeAction(action, makeCtx(em))
574
-
575
- expect(result.success).toBe(true)
576
- expect(result.createdEntityId).toBe('quote-auto-1')
577
- expect(result.createdEntityType).toBe('sales_quote')
578
- expect(mockCommandBus.execute).toHaveBeenCalledWith(
579
- 'sales.quotes.create',
580
- expect.anything(),
581
- )
582
- })
583
-
584
- it('creates an order normally when channel metadata.quotesRequired is absent', async () => {
585
- const em = createMockEm()
586
- em.nativeUpdate.mockResolvedValue(1)
587
-
588
- const freshAction = makeAction({
589
- id: 'a-order-normal',
590
- status: 'processing',
591
- payload: {
592
- customerName: 'Acme Corp',
593
- channelId: VALID_UUID,
594
- currencyCode: 'EUR',
595
- lineItems: [{ productName: 'Widget', quantity: '10' }],
596
- },
597
- })
598
- mockFindOneWithDecryption
599
- .mockResolvedValueOnce(freshAction)
600
- .mockResolvedValueOnce({ id: VALID_UUID, name: 'Web', metadata: {} })
601
-
602
- mockCommandBus.execute.mockResolvedValue({ result: { orderId: 'order-normal-1' } })
603
-
604
- const action = makeAction({
605
- id: 'a-order-normal',
606
- payload: {
607
- customerName: 'Acme Corp',
608
- channelId: VALID_UUID,
609
- currencyCode: 'EUR',
610
- lineItems: [{ productName: 'Widget', quantity: '10' }],
611
- },
612
- })
613
-
614
- const result = await executeAction(action, makeCtx(em))
615
-
616
- expect(result.success).toBe(true)
617
- expect(result.createdEntityId).toBe('order-normal-1')
618
- expect(result.createdEntityType).toBe('sales_order')
619
- expect(mockCommandBus.execute).toHaveBeenCalledWith(
620
- 'sales.orders.create',
621
- expect.anything(),
622
- )
623
- })
624
- })
625
-
626
- describe('executeAction — update_order', () => {
627
- it('updates order delivery date and notes via command', async () => {
628
- const em = createMockEm()
629
- em.nativeUpdate.mockResolvedValue(1)
630
-
631
- const freshAction = makeAction({
632
- id: 'a-update',
633
- actionType: 'update_order',
634
- status: 'processing',
635
- payload: {
636
- orderId: VALID_UUID,
637
- deliveryDateChange: { newDate: '2026-03-15' },
638
- noteAdditions: ['Updated per client request'],
639
- },
640
- })
641
- mockFindOneWithDecryption
642
- .mockResolvedValueOnce(freshAction)
643
- .mockResolvedValueOnce({
644
- id: VALID_UUID,
645
- orderNumber: 'ORD-001',
646
- currencyCode: 'EUR',
647
- comments: 'Existing note',
648
- })
649
-
650
- mockCommandBus.execute.mockResolvedValue({ result: { orderId: VALID_UUID } })
651
-
652
- const action = makeAction({
653
- id: 'a-update',
654
- actionType: 'update_order',
655
- payload: {
656
- orderId: VALID_UUID,
657
- deliveryDateChange: { newDate: '2026-03-15' },
658
- noteAdditions: ['Updated per client request'],
659
- },
660
- })
661
-
662
- const result = await executeAction(action, makeCtx(em))
663
-
664
- expect(result.success).toBe(true)
665
- expect(result.createdEntityId).toBe(VALID_UUID)
666
- expect(result.createdEntityType).toBe('sales_order')
667
- expect(mockCommandBus.execute).toHaveBeenCalledWith(
668
- 'sales.orders.update',
669
- expect.objectContaining({
670
- input: expect.objectContaining({
671
- id: VALID_UUID,
672
- comments: expect.stringContaining('Updated per client request'),
673
- }),
674
- }),
675
- )
676
- })
677
- })
678
-
679
- describe('executeAction — update_shipment', () => {
680
- it('updates shipment status via dictionary lookup and command', async () => {
681
- const em = createMockEm()
682
- em.nativeUpdate.mockResolvedValue(1)
683
-
684
- const freshAction = makeAction({
685
- id: 'a-ship',
686
- actionType: 'update_shipment',
687
- status: 'processing',
688
- payload: {
689
- orderId: VALID_UUID,
690
- statusLabel: 'Shipped',
691
- trackingNumbers: ['TRACK-123'],
692
- carrierName: 'DHL',
693
- },
694
- })
695
- mockFindOneWithDecryption
696
- .mockResolvedValueOnce(freshAction)
697
- .mockResolvedValueOnce({ id: VALID_UUID, orderNumber: 'ORD-001', currencyCode: 'EUR' })
698
- .mockResolvedValueOnce({ id: 'ship-1', order: VALID_UUID })
699
- .mockResolvedValueOnce({ id: 'dict-1', key: 'sales.shipment_status' })
700
-
701
- mockFindWithDecryption.mockResolvedValueOnce([
702
- { id: 'entry-1', label: 'Pending', value: 'pending', normalizedValue: 'pending' },
703
- { id: 'entry-2', label: 'Shipped', value: 'shipped', normalizedValue: 'shipped' },
704
- { id: 'entry-3', label: 'Delivered', value: 'delivered', normalizedValue: 'delivered' },
705
- ])
706
-
707
- mockCommandBus.execute.mockResolvedValue({ result: { shipmentId: 'ship-1' } })
708
-
709
- const action = makeAction({
710
- id: 'a-ship',
711
- actionType: 'update_shipment',
712
- payload: {
713
- orderId: VALID_UUID,
714
- statusLabel: 'Shipped',
715
- trackingNumbers: ['TRACK-123'],
716
- carrierName: 'DHL',
717
- },
718
- })
719
-
720
- const result = await executeAction(action, makeCtx(em))
721
-
722
- expect(result.success).toBe(true)
723
- expect(result.createdEntityId).toBe('ship-1')
724
- expect(result.createdEntityType).toBe('sales_shipment')
725
- expect(mockCommandBus.execute).toHaveBeenCalledWith(
726
- 'sales.shipments.update',
727
- expect.objectContaining({
728
- input: expect.objectContaining({
729
- statusEntryId: 'entry-2',
730
- trackingNumbers: ['TRACK-123'],
731
- carrierName: 'DHL',
732
- }),
733
- }),
734
- )
735
- })
736
-
737
- it('fails when no shipment found for the order', async () => {
738
- const em = createMockEm()
739
- em.nativeUpdate.mockResolvedValue(1)
740
-
741
- const freshAction = makeAction({
742
- id: 'a-ship-missing',
743
- actionType: 'update_shipment',
744
- status: 'processing',
745
- payload: {
746
- orderId: VALID_UUID,
747
- statusLabel: 'Shipped',
748
- },
749
- })
750
- mockFindOneWithDecryption
751
- .mockResolvedValueOnce(freshAction)
752
- .mockResolvedValueOnce({ id: VALID_UUID, orderNumber: 'ORD-001', currencyCode: 'EUR' })
753
-
754
- const action = makeAction({
755
- id: 'a-ship-missing',
756
- actionType: 'update_shipment',
757
- payload: {
758
- orderId: VALID_UUID,
759
- statusLabel: 'Shipped',
760
- },
761
- })
762
-
763
- const result = await executeAction(action, makeCtx(em))
764
-
765
- expect(result.success).toBe(false)
766
- expect(result.error).toContain('No shipment found')
767
- })
768
- })
769
-
770
- describe('executeAction — link_contact', () => {
771
- it('returns matched entity without dispatching a command', async () => {
772
- const em = createMockEm()
773
- em.nativeUpdate.mockResolvedValue(1)
774
-
775
- const freshAction = makeAction({
776
- id: 'a-link',
777
- actionType: 'link_contact',
778
- status: 'processing',
779
- payload: {
780
- emailAddress: 'john@example.com',
781
- contactId: VALID_UUID,
782
- contactType: 'person',
783
- contactName: 'John Doe',
784
- },
785
- })
786
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
787
-
788
- const action = makeAction({
789
- id: 'a-link',
790
- actionType: 'link_contact',
791
- payload: {
792
- emailAddress: 'john@example.com',
793
- contactId: VALID_UUID,
794
- contactType: 'person',
795
- contactName: 'John Doe',
796
- },
797
- })
798
-
799
- const result = await executeAction(action, makeCtx(em))
800
-
801
- expect(result.success).toBe(true)
802
- expect(result.createdEntityId).toBe(VALID_UUID)
803
- expect(result.createdEntityType).toBe('customer_person')
804
- expect(mockCommandBus.execute).not.toHaveBeenCalled()
805
- })
806
-
807
- it('normalizes LLM-style field names (email/id/type/name) to schema-expected names', async () => {
808
- const em = createMockEm()
809
- em.nativeUpdate.mockResolvedValue(1)
810
-
811
- const freshAction = makeAction({
812
- id: 'a-link-llm',
813
- actionType: 'link_contact',
814
- status: 'processing',
815
- payload: {
816
- email: 'john@example.com',
817
- id: VALID_UUID,
818
- type: 'Person',
819
- name: 'John Doe',
820
- },
821
- })
822
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
823
-
824
- const action = makeAction({
825
- id: 'a-link-llm',
826
- actionType: 'link_contact',
827
- payload: {
828
- email: 'john@example.com',
829
- id: VALID_UUID,
830
- type: 'Person',
831
- name: 'John Doe',
832
- },
833
- })
834
-
835
- const result = await executeAction(action, makeCtx(em))
836
-
837
- expect(result.success).toBe(true)
838
- expect(result.createdEntityId).toBe(VALID_UUID)
839
- expect(result.createdEntityType).toBe('customer_person')
840
- })
841
-
842
- it('returns customer_company for company contact type', async () => {
843
- const em = createMockEm()
844
- em.nativeUpdate.mockResolvedValue(1)
845
-
846
- const freshAction = makeAction({
847
- id: 'a-link-co',
848
- actionType: 'link_contact',
849
- status: 'processing',
850
- payload: {
851
- emailAddress: 'info@acme.com',
852
- contactId: VALID_UUID,
853
- contactType: 'company',
854
- contactName: 'Acme Corp',
855
- },
856
- })
857
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
858
-
859
- const action = makeAction({
860
- id: 'a-link-co',
861
- actionType: 'link_contact',
862
- payload: {
863
- emailAddress: 'info@acme.com',
864
- contactId: VALID_UUID,
865
- contactType: 'company',
866
- contactName: 'Acme Corp',
867
- },
868
- })
869
-
870
- const result = await executeAction(action, makeCtx(em))
871
-
872
- expect(result.success).toBe(true)
873
- expect(result.createdEntityType).toBe('customer_company')
874
- })
875
- })
876
-
877
- describe('executeAction — log_activity', () => {
878
- it('creates activity on contact via customers.activities.create', async () => {
879
- const em = createMockEm()
880
- em.nativeUpdate.mockResolvedValue(1)
881
-
882
- const freshAction = makeAction({
883
- id: 'a-activity',
884
- actionType: 'log_activity',
885
- status: 'processing',
886
- payload: {
887
- contactId: VALID_UUID,
888
- contactType: 'person',
889
- contactName: 'Jane Doe',
890
- activityType: 'note',
891
- subject: 'Follow-up from email',
892
- body: 'Client requested updated pricing.',
893
- },
894
- })
895
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
896
-
897
- mockCommandBus.execute.mockResolvedValue({ result: { activityId: 'act-1' } })
898
-
899
- const action = makeAction({
900
- id: 'a-activity',
901
- actionType: 'log_activity',
902
- payload: {
903
- contactId: VALID_UUID,
904
- contactType: 'person',
905
- contactName: 'Jane Doe',
906
- activityType: 'note',
907
- subject: 'Follow-up from email',
908
- body: 'Client requested updated pricing.',
909
- },
910
- })
911
-
912
- const result = await executeAction(action, makeCtx(em))
913
-
914
- expect(result.success).toBe(true)
915
- expect(result.createdEntityId).toBe('act-1')
916
- expect(result.createdEntityType).toBe('customer_activity')
917
- expect(mockCommandBus.execute).toHaveBeenCalledWith(
918
- 'customers.activities.create',
919
- expect.objectContaining({
920
- input: expect.objectContaining({
921
- entityId: VALID_UUID,
922
- activityType: 'note',
923
- subject: 'Follow-up from email',
924
- }),
925
- }),
926
- )
927
- })
928
-
929
- it('resolves contactId by name+type when missing', async () => {
930
- const em = createMockEm()
931
- em.nativeUpdate.mockResolvedValue(1)
932
-
933
- const freshAction = makeAction({
934
- id: 'a-activity-resolve',
935
- actionType: 'log_activity',
936
- status: 'processing',
937
- payload: {
938
- contactType: 'person',
939
- contactName: 'Jane Doe',
940
- activityType: 'note',
941
- subject: 'Follow-up',
942
- body: 'Resolved contact body',
943
- },
944
- })
945
- mockFindOneWithDecryption
946
- .mockResolvedValueOnce(freshAction)
947
- .mockResolvedValueOnce({ id: 'resolved-contact-1', kind: 'person', displayName: 'Jane Doe' })
948
-
949
- mockCommandBus.execute.mockResolvedValue({ result: { activityId: 'act-resolved' } })
950
-
951
- const action = makeAction({
952
- id: 'a-activity-resolve',
953
- actionType: 'log_activity',
954
- payload: {
955
- contactType: 'person',
956
- contactName: 'Jane Doe',
957
- activityType: 'note',
958
- subject: 'Follow-up',
959
- body: 'Resolved contact body',
960
- },
961
- })
962
-
963
- const result = await executeAction(action, makeCtx(em))
964
-
965
- expect(result.success).toBe(true)
966
- expect(result.createdEntityId).toBe('act-resolved')
967
- expect(mockCommandBus.execute).toHaveBeenCalledWith(
968
- 'customers.activities.create',
969
- expect.objectContaining({
970
- input: expect.objectContaining({ entityId: 'resolved-contact-1' }),
971
- }),
972
- )
973
- })
974
-
975
- it('fails when contactId is missing and cannot be resolved', async () => {
976
- const em = createMockEm()
977
- em.nativeUpdate.mockResolvedValue(1)
978
-
979
- const freshAction = makeAction({
980
- id: 'a-activity-no-contact',
981
- actionType: 'log_activity',
982
- status: 'processing',
983
- payload: {
984
- contactType: 'person',
985
- contactName: 'Unknown',
986
- activityType: 'note',
987
- subject: 'Test',
988
- body: 'Test body',
989
- },
990
- })
991
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
992
-
993
- const action = makeAction({
994
- id: 'a-activity-no-contact',
995
- actionType: 'log_activity',
996
- payload: {
997
- contactType: 'person',
998
- contactName: 'Unknown',
999
- activityType: 'note',
1000
- subject: 'Test',
1001
- body: 'Test body',
1002
- },
1003
- })
1004
-
1005
- const result = await executeAction(action, makeCtx(em))
1006
-
1007
- expect(result.success).toBe(false)
1008
- expect(result.error).toContain('contactId')
1009
- expect(result.error).toContain('Unknown')
1010
- })
1011
- })
1012
-
1013
- describe('executeAction — create_contact company', () => {
1014
- it('creates company via customers.companies.create when type is company', async () => {
1015
- const em = createMockEm()
1016
- em.nativeUpdate.mockResolvedValue(1)
1017
-
1018
- const freshAction = makeAction({
1019
- id: 'a-company',
1020
- actionType: 'create_contact',
1021
- status: 'processing',
1022
- payload: {
1023
- type: 'company',
1024
- name: 'Acme Corp',
1025
- email: 'info@acme.com',
1026
- companyName: 'Acme Corporation Ltd',
1027
- source: 'inbox_ops',
1028
- },
1029
- })
1030
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
1031
- mockCommandBus.execute.mockResolvedValue({ result: { entityId: 'company-1' } })
1032
-
1033
- const action = makeAction({
1034
- id: 'a-company',
1035
- actionType: 'create_contact',
1036
- payload: {
1037
- type: 'company',
1038
- name: 'Acme Corp',
1039
- email: 'info@acme.com',
1040
- companyName: 'Acme Corporation Ltd',
1041
- source: 'inbox_ops',
1042
- },
1043
- })
1044
-
1045
- const result = await executeAction(action, makeCtx(em))
1046
-
1047
- expect(result.success).toBe(true)
1048
- expect(result.createdEntityId).toBe('company-1')
1049
- expect(result.createdEntityType).toBe('customer_company')
1050
- expect(mockCommandBus.execute).toHaveBeenCalledWith(
1051
- 'customers.companies.create',
1052
- expect.objectContaining({
1053
- input: expect.objectContaining({
1054
- displayName: 'Acme Corp',
1055
- legalName: 'Acme Corporation Ltd',
1056
- }),
1057
- }),
1058
- )
1059
- })
1060
-
1061
- it('returns existing company when email matches', async () => {
1062
- const em = createMockEm()
1063
- em.nativeUpdate.mockResolvedValue(1)
1064
-
1065
- const freshAction = makeAction({
1066
- id: 'a-company-dup',
1067
- actionType: 'create_contact',
1068
- status: 'processing',
1069
- payload: {
1070
- type: 'company',
1071
- name: 'Acme Corp',
1072
- email: 'info@acme.com',
1073
- source: 'inbox_ops',
1074
- },
1075
- })
1076
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
1077
-
1078
- mockFindOneWithDecryption.mockResolvedValueOnce({
1079
- id: 'existing-company-1',
1080
- kind: 'company',
1081
- displayName: 'Acme Corp',
1082
- primaryEmail: 'info@acme.com',
1083
- })
1084
-
1085
- const action = makeAction({
1086
- id: 'a-company-dup',
1087
- actionType: 'create_contact',
1088
- payload: {
1089
- type: 'company',
1090
- name: 'Acme Corp',
1091
- email: 'info@acme.com',
1092
- source: 'inbox_ops',
1093
- },
1094
- })
1095
-
1096
- const result = await executeAction(action, makeCtx(em))
1097
-
1098
- expect(result.success).toBe(true)
1099
- expect(result.createdEntityId).toBe('existing-company-1')
1100
- expect(result.createdEntityType).toBe('customer_company')
1101
- expect(mockCommandBus.execute).not.toHaveBeenCalled()
1102
- })
1103
- })
1104
-
1105
- describe('executeAction — create_contact company requires customers.companies.manage', () => {
1106
- it('checks customers.companies.manage when create_contact type is company', async () => {
1107
- mockRbacService.userHasAllFeatures.mockResolvedValue(false)
1108
- const em = createMockEm()
1109
-
1110
- const action = makeAction({
1111
- id: 'a-company-perm',
1112
- actionType: 'create_contact',
1113
- payload: {
1114
- type: 'company',
1115
- name: 'Acme Corp',
1116
- source: 'inbox_ops',
1117
- },
1118
- })
1119
-
1120
- const result = await executeAction(action, makeCtx(em))
1121
-
1122
- expect(result.success).toBe(false)
1123
- expect(result.statusCode).toBe(403)
1124
- expect(mockRbacService.userHasAllFeatures).toHaveBeenCalledWith(
1125
- 'user-1',
1126
- ['customers.companies.manage'],
1127
- expect.objectContaining({ tenantId: 'tenant-1' }),
1128
- )
1129
- })
1130
-
1131
- it('checks customers.people.manage when create_contact type is person', async () => {
1132
- mockRbacService.userHasAllFeatures.mockResolvedValue(false)
1133
- const em = createMockEm()
1134
-
1135
- const action = makeAction({
1136
- id: 'a-person-perm',
1137
- actionType: 'create_contact',
1138
- payload: {
1139
- type: 'person',
1140
- name: 'Jane Doe',
1141
- source: 'inbox_ops',
1142
- },
1143
- })
1144
-
1145
- const result = await executeAction(action, makeCtx(em))
1146
-
1147
- expect(result.success).toBe(false)
1148
- expect(result.statusCode).toBe(403)
1149
- expect(mockRbacService.userHasAllFeatures).toHaveBeenCalledWith(
1150
- 'user-1',
1151
- ['customers.people.manage'],
1152
- expect.objectContaining({ tenantId: 'tenant-1' }),
1153
- )
1154
- })
1155
- })
1156
-
1157
- describe('executeAction — create_contact resolves cross-action unknown_contact discrepancies', () => {
1158
- it('resolves unknown_contact discrepancies on other actions (e.g. draft_reply) for the same email', async () => {
1159
- const em = createMockEm()
1160
- em.nativeUpdate.mockResolvedValue(1)
1161
-
1162
- const freshAction = makeAction({
1163
- id: 'a-create-contact',
1164
- proposalId: 'proposal-cross',
1165
- actionType: 'create_contact',
1166
- status: 'processing',
1167
- payload: {
1168
- type: 'person',
1169
- name: 'Arjun Patel',
1170
- email: 'arjun@example.com',
1171
- source: 'inbox_ops',
1172
- },
1173
- })
1174
-
1175
- // 1. findOneWithDecryption: fresh action
1176
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
1177
- // 2. findOneWithDecryption: no existing contact by DB query (triggers in-memory fallback)
1178
- mockFindOneWithDecryption.mockResolvedValueOnce(null)
1179
- // 2b. findWithDecryption: in-memory email fallback → no match (triggers create)
1180
- mockFindWithDecryption.mockResolvedValueOnce([])
1181
- // 3. command bus: create person
1182
- mockCommandBus.execute.mockResolvedValueOnce({ result: { entityId: 'new-contact-1' } })
1183
-
1184
- // After execution: resolveActionDiscrepancies (for the create_contact action itself)
1185
- // 4. findWithDecryption: discrepancies for this action ID → empty
1186
- mockFindWithDecryption.mockResolvedValueOnce([])
1187
-
1188
- // After execution: resolveUnknownContactDiscrepanciesInProposal
1189
- // 5. findWithDecryption: unknown_contact discrepancies in the proposal
1190
- const draftReplyDiscrepancy = { id: 'disc-draft', proposalId: 'proposal-cross', type: 'unknown_contact', resolved: false, foundValue: 'arjun@example.com' }
1191
- const otherDiscrepancy = { id: 'disc-other', proposalId: 'proposal-cross', type: 'unknown_contact', resolved: false, foundValue: 'other@example.com' }
1192
- mockFindWithDecryption.mockResolvedValueOnce([draftReplyDiscrepancy, otherDiscrepancy])
1193
-
1194
- // recalculateProposalStatus
1195
- // 6. findOneWithDecryption: proposal (for recalculate)
1196
- mockFindOneWithDecryption.mockResolvedValueOnce(null)
1197
-
1198
- const action = makeAction({
1199
- id: 'a-create-contact',
1200
- proposalId: 'proposal-cross',
1201
- actionType: 'create_contact',
1202
- payload: {
1203
- type: 'person',
1204
- name: 'Arjun Patel',
1205
- email: 'arjun@example.com',
1206
- source: 'inbox_ops',
1207
- },
1208
- })
1209
-
1210
- const result = await executeAction(action, makeCtx(em))
1211
-
1212
- expect(result.success).toBe(true)
1213
- // The matching discrepancy should be resolved
1214
- expect(draftReplyDiscrepancy.resolved).toBe(true)
1215
- // The non-matching discrepancy should NOT be resolved
1216
- expect(otherDiscrepancy.resolved).toBe(false)
1217
- })
1218
-
1219
- it('resolves unknown_contact discrepancies after link_contact using emailAddress field', async () => {
1220
- const em = createMockEm()
1221
- em.nativeUpdate.mockResolvedValue(1)
1222
-
1223
- const freshAction = makeAction({
1224
- id: 'a-link-cross',
1225
- proposalId: 'proposal-link-cross',
1226
- actionType: 'link_contact',
1227
- status: 'processing',
1228
- payload: {
1229
- emailAddress: 'linked@example.com',
1230
- contactId: VALID_UUID,
1231
- contactType: 'person',
1232
- contactName: 'Linked Person',
1233
- },
1234
- })
1235
-
1236
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
1237
-
1238
- // resolveActionDiscrepancies
1239
- mockFindWithDecryption.mockResolvedValueOnce([])
1240
-
1241
- // resolveUnknownContactDiscrepanciesInProposal
1242
- const discrepancy = { id: 'disc-link', proposalId: 'proposal-link-cross', type: 'unknown_contact', resolved: false, foundValue: 'linked@example.com' }
1243
- mockFindWithDecryption.mockResolvedValueOnce([discrepancy])
1244
-
1245
- // recalculateProposalStatus
1246
- mockFindOneWithDecryption.mockResolvedValueOnce(null)
1247
-
1248
- const action = makeAction({
1249
- id: 'a-link-cross',
1250
- proposalId: 'proposal-link-cross',
1251
- actionType: 'link_contact',
1252
- payload: {
1253
- emailAddress: 'linked@example.com',
1254
- contactId: VALID_UUID,
1255
- contactType: 'person',
1256
- contactName: 'Linked Person',
1257
- },
1258
- })
1259
-
1260
- const result = await executeAction(action, makeCtx(em))
1261
-
1262
- expect(result.success).toBe(true)
1263
- expect(discrepancy.resolved).toBe(true)
1264
- })
1265
- })
1266
-
1267
- describe('executeAction — link_contact normalizes matchedId/matchedType from pre-matched contacts format', () => {
1268
- it('normalizes matchedId to contactId and matchedType to contactType', async () => {
1269
- const em = createMockEm()
1270
- em.nativeUpdate.mockResolvedValue(1)
1271
-
1272
- const freshAction = makeAction({
1273
- id: 'a-link-matched',
1274
- actionType: 'link_contact',
1275
- status: 'processing',
1276
- payload: {
1277
- contactEmail: 'hans@example.com',
1278
- matchedId: VALID_UUID,
1279
- matchedType: 'Person',
1280
- displayName: 'Hans Mueller',
1281
- },
1282
- })
1283
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
1284
-
1285
- const action = makeAction({
1286
- id: 'a-link-matched',
1287
- actionType: 'link_contact',
1288
- payload: {
1289
- contactEmail: 'hans@example.com',
1290
- matchedId: VALID_UUID,
1291
- matchedType: 'Person',
1292
- displayName: 'Hans Mueller',
1293
- },
1294
- })
1295
-
1296
- const result = await executeAction(action, makeCtx(em))
1297
-
1298
- expect(result.success).toBe(true)
1299
- expect(result.createdEntityId).toBe(VALID_UUID)
1300
- expect(result.createdEntityType).toBe('customer_person')
1301
- })
1302
-
1303
- it('normalizes matchedContactId and matchedContactType variants', async () => {
1304
- const em = createMockEm()
1305
- em.nativeUpdate.mockResolvedValue(1)
1306
-
1307
- const freshAction = makeAction({
1308
- id: 'a-link-matched-2',
1309
- actionType: 'link_contact',
1310
- status: 'processing',
1311
- payload: {
1312
- email: 'naomi@example.com',
1313
- matchedContactId: VALID_UUID,
1314
- matchedContactType: 'person',
1315
- name: 'Naomi Harris',
1316
- },
1317
- })
1318
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
1319
-
1320
- const action = makeAction({
1321
- id: 'a-link-matched-2',
1322
- actionType: 'link_contact',
1323
- payload: {
1324
- email: 'naomi@example.com',
1325
- matchedContactId: VALID_UUID,
1326
- matchedContactType: 'person',
1327
- name: 'Naomi Harris',
1328
- },
1329
- })
1330
-
1331
- const result = await executeAction(action, makeCtx(em))
1332
-
1333
- expect(result.success).toBe(true)
1334
- expect(result.createdEntityId).toBe(VALID_UUID)
1335
- })
1336
- })
1337
-
1338
- describe('executeAction — create_order resolves channel from container when entities.SalesChannel is undefined', () => {
1339
- it('resolves channel from container fallback when entities does not include SalesChannel', async () => {
1340
- const em = createMockEm()
1341
- em.nativeUpdate.mockResolvedValue(1)
1342
-
1343
- const freshAction = makeAction({
1344
- id: 'a-order-no-channel',
1345
- status: 'processing',
1346
- payload: {
1347
- customerName: 'Test Customer',
1348
- currencyCode: 'EUR',
1349
- lineItems: [{ productName: 'Widget', quantity: '10' }],
1350
- },
1351
- })
1352
-
1353
- // findOneWithDecryption: fresh action
1354
- mockFindOneWithDecryption.mockResolvedValueOnce(freshAction)
1355
-
1356
- // container.resolve('SalesChannel') fallback
1357
- const MockSalesChannelFallback = class {} as unknown
1358
- mockContainer.resolve.mockImplementation((token: string) => {
1359
- if (token === 'rbacService') return mockRbacService
1360
- if (token === 'commandBus') return mockCommandBus
1361
- if (token === 'SalesChannel') return MockSalesChannelFallback
1362
- return null
1363
- })
1364
-
1365
- // findOneWithDecryption: resolveFirstChannelId (finds a channel)
1366
- mockFindOneWithDecryption.mockResolvedValueOnce({
1367
- id: 'channel-from-container',
1368
- name: 'Online Store',
1369
- metadata: null,
1370
- })
1371
- // findOneWithDecryption: resolveEffectiveDocumentKind
1372
- mockFindOneWithDecryption.mockResolvedValueOnce({
1373
- id: 'channel-from-container',
1374
- name: 'Online Store',
1375
- metadata: {},
1376
- })
1377
-
1378
- mockCommandBus.execute.mockResolvedValue({ result: { orderId: 'order-fallback' } })
1379
-
1380
- const action = makeAction({
1381
- id: 'a-order-no-channel',
1382
- payload: {
1383
- customerName: 'Test Customer',
1384
- currencyCode: 'EUR',
1385
- lineItems: [{ productName: 'Widget', quantity: '10' }],
1386
- },
1387
- })
1388
-
1389
- // Pass entities WITHOUT SalesChannel
1390
- const result = await executeAction(action, makeCtx(em, {
1391
- entities: {
1392
- CustomerEntity: MockCustomerEntity,
1393
- SalesOrder: MockSalesOrder,
1394
- SalesShipment: MockSalesShipment,
1395
- Dictionary: MockDictionary,
1396
- DictionaryEntry: MockDictionaryEntry,
1397
- },
1398
- }))
1399
-
1400
- expect(result.success).toBe(true)
1401
- expect(result.createdEntityId).toBe('order-fallback')
1402
- })
1403
- })
1404
-
1405
- describe('getRequiredFeature', () => {
1406
- it.each([
1407
- ['create_order', 'sales.orders.manage'],
1408
- ['create_quote', 'sales.quotes.manage'],
1409
- ['update_order', 'sales.orders.manage'],
1410
- ['update_shipment', 'sales.shipments.manage'],
1411
- ['create_contact', 'customers.people.manage'],
1412
- ['link_contact', 'customers.people.manage'],
1413
- ['log_activity', 'customers.activities.manage'],
1414
- ['draft_reply', 'inbox_ops.replies.send'],
1415
- ] as const)('returns correct feature for %s', (actionType, expectedFeature) => {
1416
- expect(getRequiredFeature(actionType)).toBe(expectedFeature)
1417
- })
1418
- })
1419
- })