@open-mercato/core 0.6.8-develop.6925.1.cefa200fa4 → 0.6.8-develop.6931.1.4a1e1c786b

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 (405) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/eudr_due_diligence_statement/index.js +47 -0
  3. package/dist/generated/entities/eudr_due_diligence_statement/index.js.map +7 -0
  4. package/dist/generated/entities/eudr_evidence_submission/index.js +51 -0
  5. package/dist/generated/entities/eudr_evidence_submission/index.js.map +7 -0
  6. package/dist/generated/entities/eudr_mitigation_action/index.js +31 -0
  7. package/dist/generated/entities/eudr_mitigation_action/index.js.map +7 -0
  8. package/dist/generated/entities/eudr_plot/index.js +39 -0
  9. package/dist/generated/entities/eudr_plot/index.js.map +7 -0
  10. package/dist/generated/entities/eudr_product_mapping/index.js +31 -0
  11. package/dist/generated/entities/eudr_product_mapping/index.js.map +7 -0
  12. package/dist/generated/entities/eudr_risk_assessment/index.js +35 -0
  13. package/dist/generated/entities/eudr_risk_assessment/index.js.map +7 -0
  14. package/dist/generated/entities.ids.generated.js +9 -0
  15. package/dist/generated/entities.ids.generated.js.map +2 -2
  16. package/dist/generated/entity-fields-registry.js +120 -0
  17. package/dist/generated/entity-fields-registry.js.map +2 -2
  18. package/dist/helpers/integration/ui.js +3 -0
  19. package/dist/helpers/integration/ui.js.map +2 -2
  20. package/dist/modules/attachments/fields/attachment.js +5 -1
  21. package/dist/modules/attachments/fields/attachment.js.map +2 -2
  22. package/dist/modules/attachments/lib/crud.js +3 -1
  23. package/dist/modules/attachments/lib/crud.js.map +2 -2
  24. package/dist/modules/eudr/acl.js +43 -0
  25. package/dist/modules/eudr/acl.js.map +7 -0
  26. package/dist/modules/eudr/ai-agents.js +205 -0
  27. package/dist/modules/eudr/ai-agents.js.map +7 -0
  28. package/dist/modules/eudr/ai-tools/compliance-pack.js +495 -0
  29. package/dist/modules/eudr/ai-tools/compliance-pack.js.map +7 -0
  30. package/dist/modules/eudr/ai-tools/types.js +10 -0
  31. package/dist/modules/eudr/ai-tools/types.js.map +7 -0
  32. package/dist/modules/eudr/ai-tools.js +10 -0
  33. package/dist/modules/eudr/ai-tools.js.map +7 -0
  34. package/dist/modules/eudr/api/dashboard/widgets/compliance-overview/route.js +386 -0
  35. package/dist/modules/eudr/api/dashboard/widgets/compliance-overview/route.js.map +7 -0
  36. package/dist/modules/eudr/api/evidence-submissions/route.js +318 -0
  37. package/dist/modules/eudr/api/evidence-submissions/route.js.map +7 -0
  38. package/dist/modules/eudr/api/mitigation-actions/route.js +249 -0
  39. package/dist/modules/eudr/api/mitigation-actions/route.js.map +7 -0
  40. package/dist/modules/eudr/api/openapi.js +27 -0
  41. package/dist/modules/eudr/api/openapi.js.map +7 -0
  42. package/dist/modules/eudr/api/plots/import/route.js +294 -0
  43. package/dist/modules/eudr/api/plots/import/route.js.map +7 -0
  44. package/dist/modules/eudr/api/plots/route.js +279 -0
  45. package/dist/modules/eudr/api/plots/route.js.map +7 -0
  46. package/dist/modules/eudr/api/product-mappings/route.js +257 -0
  47. package/dist/modules/eudr/api/product-mappings/route.js.map +7 -0
  48. package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js +298 -0
  49. package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js.map +7 -0
  50. package/dist/modules/eudr/api/product-mappings/suggestions/route.js +132 -0
  51. package/dist/modules/eudr/api/product-mappings/suggestions/route.js.map +7 -0
  52. package/dist/modules/eudr/api/reports/annual/route.js +266 -0
  53. package/dist/modules/eudr/api/reports/annual/route.js.map +7 -0
  54. package/dist/modules/eudr/api/risk-assessments/route.js +300 -0
  55. package/dist/modules/eudr/api/risk-assessments/route.js.map +7 -0
  56. package/dist/modules/eudr/api/statements/[id]/export/route.js +631 -0
  57. package/dist/modules/eudr/api/statements/[id]/export/route.js.map +7 -0
  58. package/dist/modules/eudr/api/statements/[id]/readiness/route.js +111 -0
  59. package/dist/modules/eudr/api/statements/[id]/readiness/route.js.map +7 -0
  60. package/dist/modules/eudr/api/statements/route.js +314 -0
  61. package/dist/modules/eudr/api/statements/route.js.map +7 -0
  62. package/dist/modules/eudr/api/suppliers/compliance/route.js +173 -0
  63. package/dist/modules/eudr/api/suppliers/compliance/route.js.map +7 -0
  64. package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.js +468 -0
  65. package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.js.map +7 -0
  66. package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.js +16 -0
  67. package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.js.map +7 -0
  68. package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.js +351 -0
  69. package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.js.map +7 -0
  70. package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.js +17 -0
  71. package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.js.map +7 -0
  72. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +313 -0
  73. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +7 -0
  74. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.meta.js +16 -0
  75. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.meta.js.map +7 -0
  76. package/dist/modules/eudr/backend/eudr/page.js +360 -0
  77. package/dist/modules/eudr/backend/eudr/page.js.map +7 -0
  78. package/dist/modules/eudr/backend/eudr/page.meta.js +16 -0
  79. package/dist/modules/eudr/backend/eudr/page.meta.js.map +7 -0
  80. package/dist/modules/eudr/backend/eudr/plots/[id]/page.js +346 -0
  81. package/dist/modules/eudr/backend/eudr/plots/[id]/page.js.map +7 -0
  82. package/dist/modules/eudr/backend/eudr/plots/[id]/page.meta.js +16 -0
  83. package/dist/modules/eudr/backend/eudr/plots/[id]/page.meta.js.map +7 -0
  84. package/dist/modules/eudr/backend/eudr/plots/create/page.js +253 -0
  85. package/dist/modules/eudr/backend/eudr/plots/create/page.js.map +7 -0
  86. package/dist/modules/eudr/backend/eudr/plots/create/page.meta.js +17 -0
  87. package/dist/modules/eudr/backend/eudr/plots/create/page.meta.js.map +7 -0
  88. package/dist/modules/eudr/backend/eudr/plots/page.js +386 -0
  89. package/dist/modules/eudr/backend/eudr/plots/page.js.map +7 -0
  90. package/dist/modules/eudr/backend/eudr/plots/page.meta.js +16 -0
  91. package/dist/modules/eudr/backend/eudr/plots/page.meta.js.map +7 -0
  92. package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.js +253 -0
  93. package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.js.map +7 -0
  94. package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.js +16 -0
  95. package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.js.map +7 -0
  96. package/dist/modules/eudr/backend/eudr/product-mappings/create/page.js +174 -0
  97. package/dist/modules/eudr/backend/eudr/product-mappings/create/page.js.map +7 -0
  98. package/dist/modules/eudr/backend/eudr/product-mappings/create/page.meta.js +17 -0
  99. package/dist/modules/eudr/backend/eudr/product-mappings/create/page.meta.js.map +7 -0
  100. package/dist/modules/eudr/backend/eudr/product-mappings/page.js +306 -0
  101. package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +7 -0
  102. package/dist/modules/eudr/backend/eudr/product-mappings/page.meta.js +16 -0
  103. package/dist/modules/eudr/backend/eudr/product-mappings/page.meta.js.map +7 -0
  104. package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.js +335 -0
  105. package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.js.map +7 -0
  106. package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.js +16 -0
  107. package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.js.map +7 -0
  108. package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.js +220 -0
  109. package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.js.map +7 -0
  110. package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.meta.js +17 -0
  111. package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.meta.js.map +7 -0
  112. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +324 -0
  113. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +7 -0
  114. package/dist/modules/eudr/backend/eudr/risk-assessments/page.meta.js +16 -0
  115. package/dist/modules/eudr/backend/eudr/risk-assessments/page.meta.js.map +7 -0
  116. package/dist/modules/eudr/backend/eudr/statements/[id]/page.js +648 -0
  117. package/dist/modules/eudr/backend/eudr/statements/[id]/page.js.map +7 -0
  118. package/dist/modules/eudr/backend/eudr/statements/[id]/page.meta.js +16 -0
  119. package/dist/modules/eudr/backend/eudr/statements/[id]/page.meta.js.map +7 -0
  120. package/dist/modules/eudr/backend/eudr/statements/create/page.js +432 -0
  121. package/dist/modules/eudr/backend/eudr/statements/create/page.js.map +7 -0
  122. package/dist/modules/eudr/backend/eudr/statements/create/page.meta.js +17 -0
  123. package/dist/modules/eudr/backend/eudr/statements/create/page.meta.js.map +7 -0
  124. package/dist/modules/eudr/backend/eudr/statements/page.js +309 -0
  125. package/dist/modules/eudr/backend/eudr/statements/page.js.map +7 -0
  126. package/dist/modules/eudr/backend/eudr/statements/page.meta.js +16 -0
  127. package/dist/modules/eudr/backend/eudr/statements/page.meta.js.map +7 -0
  128. package/dist/modules/eudr/ce.js +56 -0
  129. package/dist/modules/eudr/ce.js.map +7 -0
  130. package/dist/modules/eudr/commands/evidence-submissions.js +571 -0
  131. package/dist/modules/eudr/commands/evidence-submissions.js.map +7 -0
  132. package/dist/modules/eudr/commands/index.js +7 -0
  133. package/dist/modules/eudr/commands/index.js.map +7 -0
  134. package/dist/modules/eudr/commands/lifecycle-events.js +19 -0
  135. package/dist/modules/eudr/commands/lifecycle-events.js.map +7 -0
  136. package/dist/modules/eudr/commands/mitigation-actions.js +488 -0
  137. package/dist/modules/eudr/commands/mitigation-actions.js.map +7 -0
  138. package/dist/modules/eudr/commands/plots.js +517 -0
  139. package/dist/modules/eudr/commands/plots.js.map +7 -0
  140. package/dist/modules/eudr/commands/product-mappings.js +468 -0
  141. package/dist/modules/eudr/commands/product-mappings.js.map +7 -0
  142. package/dist/modules/eudr/commands/risk-assessments.js +599 -0
  143. package/dist/modules/eudr/commands/risk-assessments.js.map +7 -0
  144. package/dist/modules/eudr/commands/statements.js +747 -0
  145. package/dist/modules/eudr/commands/statements.js.map +7 -0
  146. package/dist/modules/eudr/components/CountrySelectField.js +64 -0
  147. package/dist/modules/eudr/components/CountrySelectField.js.map +7 -0
  148. package/dist/modules/eudr/components/GeometryInput.js +133 -0
  149. package/dist/modules/eudr/components/GeometryInput.js.map +7 -0
  150. package/dist/modules/eudr/components/MappingSuggestionsDialog.js +307 -0
  151. package/dist/modules/eudr/components/MappingSuggestionsDialog.js.map +7 -0
  152. package/dist/modules/eudr/components/MitigationActionsSection.js +345 -0
  153. package/dist/modules/eudr/components/MitigationActionsSection.js.map +7 -0
  154. package/dist/modules/eudr/components/OrderSelectField.js +88 -0
  155. package/dist/modules/eudr/components/OrderSelectField.js.map +7 -0
  156. package/dist/modules/eudr/components/PlotImportDialog.js +229 -0
  157. package/dist/modules/eudr/components/PlotImportDialog.js.map +7 -0
  158. package/dist/modules/eudr/components/PlotMapPreview.js +35 -0
  159. package/dist/modules/eudr/components/PlotMapPreview.js.map +7 -0
  160. package/dist/modules/eudr/components/PlotMapPreviewImpl.js +97 -0
  161. package/dist/modules/eudr/components/PlotMapPreviewImpl.js.map +7 -0
  162. package/dist/modules/eudr/components/PlotMultiSelectField.js +198 -0
  163. package/dist/modules/eudr/components/PlotMultiSelectField.js.map +7 -0
  164. package/dist/modules/eudr/components/RiskCriteriaField.js +128 -0
  165. package/dist/modules/eudr/components/RiskCriteriaField.js.map +7 -0
  166. package/dist/modules/eudr/components/StatementLifecycleBar.js +274 -0
  167. package/dist/modules/eudr/components/StatementLifecycleBar.js.map +7 -0
  168. package/dist/modules/eudr/components/StatementReadinessChecklist.js +56 -0
  169. package/dist/modules/eudr/components/StatementReadinessChecklist.js.map +7 -0
  170. package/dist/modules/eudr/components/StatementRiskSection.js +179 -0
  171. package/dist/modules/eudr/components/StatementRiskSection.js.map +7 -0
  172. package/dist/modules/eudr/components/crudErrorI18n.js +31 -0
  173. package/dist/modules/eudr/components/crudErrorI18n.js.map +7 -0
  174. package/dist/modules/eudr/components/formConfig.js +593 -0
  175. package/dist/modules/eudr/components/formConfig.js.map +7 -0
  176. package/dist/modules/eudr/components/plotForm.js +68 -0
  177. package/dist/modules/eudr/components/plotForm.js.map +7 -0
  178. package/dist/modules/eudr/data/enrichers.js +62 -0
  179. package/dist/modules/eudr/data/enrichers.js.map +7 -0
  180. package/dist/modules/eudr/data/entities.js +437 -0
  181. package/dist/modules/eudr/data/entities.js.map +7 -0
  182. package/dist/modules/eudr/data/validators.js +271 -0
  183. package/dist/modules/eudr/data/validators.js.map +7 -0
  184. package/dist/modules/eudr/encryption.js +33 -0
  185. package/dist/modules/eudr/encryption.js.map +7 -0
  186. package/dist/modules/eudr/events.js +38 -0
  187. package/dist/modules/eudr/events.js.map +7 -0
  188. package/dist/modules/eudr/index.js +15 -0
  189. package/dist/modules/eudr/index.js.map +7 -0
  190. package/dist/modules/eudr/lib/annual-report.js +104 -0
  191. package/dist/modules/eudr/lib/annual-report.js.map +7 -0
  192. package/dist/modules/eudr/lib/completeness.js +64 -0
  193. package/dist/modules/eudr/lib/completeness.js.map +7 -0
  194. package/dist/modules/eudr/lib/detail-read-scope.js +16 -0
  195. package/dist/modules/eudr/lib/detail-read-scope.js.map +7 -0
  196. package/dist/modules/eudr/lib/geometry.js +142 -0
  197. package/dist/modules/eudr/lib/geometry.js.map +7 -0
  198. package/dist/modules/eudr/lib/notifications.js +56 -0
  199. package/dist/modules/eudr/lib/notifications.js.map +7 -0
  200. package/dist/modules/eudr/lib/plural.js +26 -0
  201. package/dist/modules/eudr/lib/plural.js.map +7 -0
  202. package/dist/modules/eudr/lib/reference-data.js +240 -0
  203. package/dist/modules/eudr/lib/reference-data.js.map +7 -0
  204. package/dist/modules/eudr/lib/species.js +10 -0
  205. package/dist/modules/eudr/lib/species.js.map +7 -0
  206. package/dist/modules/eudr/lib/statement-lifecycle.js +84 -0
  207. package/dist/modules/eudr/lib/statement-lifecycle.js.map +7 -0
  208. package/dist/modules/eudr/lib/statement-seeding.js +49 -0
  209. package/dist/modules/eudr/lib/statement-seeding.js.map +7 -0
  210. package/dist/modules/eudr/migrations/Migration20260706102002_eudr.js +15 -0
  211. package/dist/modules/eudr/migrations/Migration20260706102002_eudr.js.map +7 -0
  212. package/dist/modules/eudr/migrations/Migration20260706152612_eudr.js +24 -0
  213. package/dist/modules/eudr/migrations/Migration20260706152612_eudr.js.map +7 -0
  214. package/dist/modules/eudr/migrations/Migration20260722100000_eudr.js +15 -0
  215. package/dist/modules/eudr/migrations/Migration20260722100000_eudr.js.map +7 -0
  216. package/dist/modules/eudr/notifications.js +58 -0
  217. package/dist/modules/eudr/notifications.js.map +7 -0
  218. package/dist/modules/eudr/search.js +186 -0
  219. package/dist/modules/eudr/search.js.map +7 -0
  220. package/dist/modules/eudr/setup.js +12 -0
  221. package/dist/modules/eudr/setup.js.map +7 -0
  222. package/dist/modules/eudr/subscribers/notify-mitigation-completed.js +34 -0
  223. package/dist/modules/eudr/subscribers/notify-mitigation-completed.js.map +7 -0
  224. package/dist/modules/eudr/subscribers/notify-risk-concluded.js +35 -0
  225. package/dist/modules/eudr/subscribers/notify-risk-concluded.js.map +7 -0
  226. package/dist/modules/eudr/subscribers/notify-statement-reference-issued.js +37 -0
  227. package/dist/modules/eudr/subscribers/notify-statement-reference-issued.js.map +7 -0
  228. package/dist/modules/eudr/subscribers/notify-statement-submitted.js +34 -0
  229. package/dist/modules/eudr/subscribers/notify-statement-submitted.js.map +7 -0
  230. package/dist/modules/eudr/subscribers/notify-statement-withdrawn.js +34 -0
  231. package/dist/modules/eudr/subscribers/notify-statement-withdrawn.js.map +7 -0
  232. package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-created.js +124 -0
  233. package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-created.js.map +7 -0
  234. package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-deleted.js +22 -0
  235. package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-deleted.js.map +7 -0
  236. package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.client.js +203 -0
  237. package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.client.js.map +7 -0
  238. package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.js +23 -0
  239. package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.js.map +7 -0
  240. package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.client.js +19 -0
  241. package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.client.js.map +7 -0
  242. package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.js +31 -0
  243. package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.js.map +7 -0
  244. package/dist/modules/eudr/widgets/injection/order-compliance/widget.client.js +100 -0
  245. package/dist/modules/eudr/widgets/injection/order-compliance/widget.client.js.map +7 -0
  246. package/dist/modules/eudr/widgets/injection/order-compliance/widget.js +17 -0
  247. package/dist/modules/eudr/widgets/injection/order-compliance/widget.js.map +7 -0
  248. package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.client.js +116 -0
  249. package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.client.js.map +7 -0
  250. package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.js +17 -0
  251. package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.js.map +7 -0
  252. package/dist/modules/eudr/widgets/injection-table.js +32 -0
  253. package/dist/modules/eudr/widgets/injection-table.js.map +7 -0
  254. package/dist/modules/notifications/lib/notificationService.js +67 -3
  255. package/dist/modules/notifications/lib/notificationService.js.map +2 -2
  256. package/dist/modules/query_index/lib/engine.js +121 -48
  257. package/dist/modules/query_index/lib/engine.js.map +2 -2
  258. package/dist/modules/sales/api/documents/factory.js +17 -0
  259. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  260. package/dist/modules/sales/commands/documents.js +32 -18
  261. package/dist/modules/sales/commands/documents.js.map +2 -2
  262. package/dist/modules/sales/data/entities.js +1 -0
  263. package/dist/modules/sales/data/entities.js.map +2 -2
  264. package/dist/modules/sales/migrations/Migration20260806120000_sales_tag_assignment_document_idx.js +17 -0
  265. package/dist/modules/sales/migrations/Migration20260806120000_sales_tag_assignment_document_idx.js.map +7 -0
  266. package/generated/entities/eudr_due_diligence_statement/index.ts +22 -0
  267. package/generated/entities/eudr_evidence_submission/index.ts +24 -0
  268. package/generated/entities/eudr_mitigation_action/index.ts +14 -0
  269. package/generated/entities/eudr_plot/index.ts +18 -0
  270. package/generated/entities/eudr_product_mapping/index.ts +14 -0
  271. package/generated/entities/eudr_risk_assessment/index.ts +16 -0
  272. package/generated/entities.ids.generated.ts +9 -0
  273. package/generated/entity-fields-registry.ts +120 -0
  274. package/package.json +7 -7
  275. package/src/helpers/integration/ui.ts +12 -0
  276. package/src/modules/attachments/fields/attachment.tsx +5 -0
  277. package/src/modules/attachments/lib/crud.ts +2 -0
  278. package/src/modules/eudr/acl.ts +39 -0
  279. package/src/modules/eudr/ai-agents.ts +258 -0
  280. package/src/modules/eudr/ai-tools/compliance-pack.ts +618 -0
  281. package/src/modules/eudr/ai-tools/types.ts +44 -0
  282. package/src/modules/eudr/ai-tools.ts +15 -0
  283. package/src/modules/eudr/api/dashboard/widgets/compliance-overview/route.ts +481 -0
  284. package/src/modules/eudr/api/evidence-submissions/route.ts +335 -0
  285. package/src/modules/eudr/api/mitigation-actions/route.ts +263 -0
  286. package/src/modules/eudr/api/openapi.ts +28 -0
  287. package/src/modules/eudr/api/plots/import/route.ts +369 -0
  288. package/src/modules/eudr/api/plots/route.ts +296 -0
  289. package/src/modules/eudr/api/product-mappings/route.ts +269 -0
  290. package/src/modules/eudr/api/product-mappings/suggestions/apply/route.ts +382 -0
  291. package/src/modules/eudr/api/product-mappings/suggestions/route.ts +169 -0
  292. package/src/modules/eudr/api/reports/annual/route.ts +457 -0
  293. package/src/modules/eudr/api/risk-assessments/route.ts +323 -0
  294. package/src/modules/eudr/api/statements/[id]/export/route.ts +713 -0
  295. package/src/modules/eudr/api/statements/[id]/readiness/route.ts +129 -0
  296. package/src/modules/eudr/api/statements/route.ts +329 -0
  297. package/src/modules/eudr/api/suppliers/compliance/route.ts +241 -0
  298. package/src/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.ts +12 -0
  299. package/src/modules/eudr/backend/eudr/evidence-submissions/[id]/page.tsx +545 -0
  300. package/src/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.ts +13 -0
  301. package/src/modules/eudr/backend/eudr/evidence-submissions/create/page.tsx +383 -0
  302. package/src/modules/eudr/backend/eudr/evidence-submissions/page.meta.ts +12 -0
  303. package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +379 -0
  304. package/src/modules/eudr/backend/eudr/page.meta.ts +12 -0
  305. package/src/modules/eudr/backend/eudr/page.tsx +477 -0
  306. package/src/modules/eudr/backend/eudr/plots/[id]/page.meta.ts +12 -0
  307. package/src/modules/eudr/backend/eudr/plots/[id]/page.tsx +404 -0
  308. package/src/modules/eudr/backend/eudr/plots/create/page.meta.ts +13 -0
  309. package/src/modules/eudr/backend/eudr/plots/create/page.tsx +267 -0
  310. package/src/modules/eudr/backend/eudr/plots/page.meta.ts +12 -0
  311. package/src/modules/eudr/backend/eudr/plots/page.tsx +442 -0
  312. package/src/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.ts +12 -0
  313. package/src/modules/eudr/backend/eudr/product-mappings/[id]/page.tsx +311 -0
  314. package/src/modules/eudr/backend/eudr/product-mappings/create/page.meta.ts +13 -0
  315. package/src/modules/eudr/backend/eudr/product-mappings/create/page.tsx +190 -0
  316. package/src/modules/eudr/backend/eudr/product-mappings/page.meta.ts +12 -0
  317. package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +344 -0
  318. package/src/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.ts +12 -0
  319. package/src/modules/eudr/backend/eudr/risk-assessments/[id]/page.tsx +421 -0
  320. package/src/modules/eudr/backend/eudr/risk-assessments/create/page.meta.ts +13 -0
  321. package/src/modules/eudr/backend/eudr/risk-assessments/create/page.tsx +247 -0
  322. package/src/modules/eudr/backend/eudr/risk-assessments/page.meta.ts +12 -0
  323. package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +383 -0
  324. package/src/modules/eudr/backend/eudr/statements/[id]/page.meta.ts +12 -0
  325. package/src/modules/eudr/backend/eudr/statements/[id]/page.tsx +777 -0
  326. package/src/modules/eudr/backend/eudr/statements/create/page.meta.ts +13 -0
  327. package/src/modules/eudr/backend/eudr/statements/create/page.tsx +511 -0
  328. package/src/modules/eudr/backend/eudr/statements/page.meta.ts +12 -0
  329. package/src/modules/eudr/backend/eudr/statements/page.tsx +372 -0
  330. package/src/modules/eudr/ce.ts +52 -0
  331. package/src/modules/eudr/commands/evidence-submissions.ts +699 -0
  332. package/src/modules/eudr/commands/index.ts +6 -0
  333. package/src/modules/eudr/commands/lifecycle-events.ts +28 -0
  334. package/src/modules/eudr/commands/mitigation-actions.ts +574 -0
  335. package/src/modules/eudr/commands/plots.ts +627 -0
  336. package/src/modules/eudr/commands/product-mappings.ts +556 -0
  337. package/src/modules/eudr/commands/risk-assessments.ts +728 -0
  338. package/src/modules/eudr/commands/statements.ts +933 -0
  339. package/src/modules/eudr/components/CountrySelectField.tsx +77 -0
  340. package/src/modules/eudr/components/GeometryInput.tsx +170 -0
  341. package/src/modules/eudr/components/MappingSuggestionsDialog.tsx +385 -0
  342. package/src/modules/eudr/components/MitigationActionsSection.tsx +417 -0
  343. package/src/modules/eudr/components/OrderSelectField.tsx +116 -0
  344. package/src/modules/eudr/components/PlotImportDialog.tsx +277 -0
  345. package/src/modules/eudr/components/PlotMapPreview.tsx +46 -0
  346. package/src/modules/eudr/components/PlotMapPreviewImpl.tsx +111 -0
  347. package/src/modules/eudr/components/PlotMultiSelectField.tsx +238 -0
  348. package/src/modules/eudr/components/RiskCriteriaField.tsx +173 -0
  349. package/src/modules/eudr/components/StatementLifecycleBar.tsx +363 -0
  350. package/src/modules/eudr/components/StatementReadinessChecklist.tsx +82 -0
  351. package/src/modules/eudr/components/StatementRiskSection.tsx +242 -0
  352. package/src/modules/eudr/components/crudErrorI18n.ts +36 -0
  353. package/src/modules/eudr/components/formConfig.tsx +717 -0
  354. package/src/modules/eudr/components/plotForm.ts +75 -0
  355. package/src/modules/eudr/data/enrichers.ts +82 -0
  356. package/src/modules/eudr/data/entities.ts +369 -0
  357. package/src/modules/eudr/data/validators.ts +357 -0
  358. package/src/modules/eudr/encryption.ts +31 -0
  359. package/src/modules/eudr/events.ts +38 -0
  360. package/src/modules/eudr/i18n/de.json +747 -0
  361. package/src/modules/eudr/i18n/en.json +747 -0
  362. package/src/modules/eudr/i18n/es.json +747 -0
  363. package/src/modules/eudr/i18n/ko.json +747 -0
  364. package/src/modules/eudr/i18n/pl.json +747 -0
  365. package/src/modules/eudr/index.ts +13 -0
  366. package/src/modules/eudr/lib/annual-report.ts +120 -0
  367. package/src/modules/eudr/lib/completeness.ts +90 -0
  368. package/src/modules/eudr/lib/detail-read-scope.ts +44 -0
  369. package/src/modules/eudr/lib/geometry.ts +191 -0
  370. package/src/modules/eudr/lib/notifications.ts +85 -0
  371. package/src/modules/eudr/lib/plural.ts +36 -0
  372. package/src/modules/eudr/lib/reference-data.ts +128 -0
  373. package/src/modules/eudr/lib/species.ts +12 -0
  374. package/src/modules/eudr/lib/statement-lifecycle.ts +109 -0
  375. package/src/modules/eudr/lib/statement-seeding.ts +86 -0
  376. package/src/modules/eudr/migrations/.snapshot-open-mercato.json +2046 -0
  377. package/src/modules/eudr/migrations/Migration20260706102002_eudr.ts +16 -0
  378. package/src/modules/eudr/migrations/Migration20260706152612_eudr.ts +30 -0
  379. package/src/modules/eudr/migrations/Migration20260722100000_eudr.ts +17 -0
  380. package/src/modules/eudr/notifications.ts +56 -0
  381. package/src/modules/eudr/search.ts +212 -0
  382. package/src/modules/eudr/setup.ts +10 -0
  383. package/src/modules/eudr/subscribers/notify-mitigation-completed.ts +56 -0
  384. package/src/modules/eudr/subscribers/notify-risk-concluded.ts +58 -0
  385. package/src/modules/eudr/subscribers/notify-statement-reference-issued.ts +59 -0
  386. package/src/modules/eudr/subscribers/notify-statement-submitted.ts +49 -0
  387. package/src/modules/eudr/subscribers/notify-statement-withdrawn.ts +49 -0
  388. package/src/modules/eudr/subscribers/recompute-completeness-on-attachment-created.ts +189 -0
  389. package/src/modules/eudr/subscribers/recompute-completeness-on-attachment-deleted.ts +31 -0
  390. package/src/modules/eudr/widgets/dashboard/compliance-overview/widget.client.tsx +271 -0
  391. package/src/modules/eudr/widgets/dashboard/compliance-overview/widget.ts +24 -0
  392. package/src/modules/eudr/widgets/injection/eudr-product-column/widget.client.tsx +37 -0
  393. package/src/modules/eudr/widgets/injection/eudr-product-column/widget.ts +30 -0
  394. package/src/modules/eudr/widgets/injection/order-compliance/widget.client.tsx +131 -0
  395. package/src/modules/eudr/widgets/injection/order-compliance/widget.ts +16 -0
  396. package/src/modules/eudr/widgets/injection/supplier-compliance/widget.client.tsx +168 -0
  397. package/src/modules/eudr/widgets/injection/supplier-compliance/widget.ts +16 -0
  398. package/src/modules/eudr/widgets/injection-table.ts +31 -0
  399. package/src/modules/notifications/lib/notificationService.ts +83 -4
  400. package/src/modules/query_index/lib/engine.ts +139 -51
  401. package/src/modules/sales/api/documents/factory.ts +29 -0
  402. package/src/modules/sales/commands/documents.ts +65 -18
  403. package/src/modules/sales/data/entities.ts +1 -0
  404. package/src/modules/sales/migrations/.snapshot-open-mercato.json +10 -0
  405. package/src/modules/sales/migrations/Migration20260806120000_sales_tag_assignment_document_idx.ts +59 -0
@@ -0,0 +1,618 @@
1
+ import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'
2
+ import { z } from 'zod'
3
+ import { createLogger } from '@open-mercato/shared/lib/logger'
4
+ import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
5
+ import type { QueryEngine } from '@open-mercato/shared/lib/query/types'
6
+ import { E } from '#generated/entities.ids.generated'
7
+ import {
8
+ EudrDueDiligenceStatement,
9
+ EudrEvidenceSubmission,
10
+ EudrMitigationAction,
11
+ EudrProductMapping,
12
+ EudrRiskAssessment,
13
+ } from '../data/entities'
14
+ import {
15
+ EUDR_COMMODITIES,
16
+ EUDR_STATEMENT_STATUSES,
17
+ EUDR_SUBMISSION_STATUSES,
18
+ } from '../data/validators'
19
+ import {
20
+ EUDR_APPLICATION_DATES,
21
+ EUDR_HIGH_RISK_COUNTRIES,
22
+ EUDR_LOW_RISK_COUNTRIES,
23
+ getCountryRiskTier,
24
+ suggestCommodityForHsCode,
25
+ } from '../lib/reference-data'
26
+ import {
27
+ evaluateSubmissionGate,
28
+ type GateAssessmentView,
29
+ type GateSubmissionView,
30
+ } from '../lib/statement-lifecycle'
31
+ import { assertTenantScope, type EudrAiToolDefinition, type EudrToolContext } from './types'
32
+
33
+ type Scope = {
34
+ tenantId: string
35
+ organizationId: string
36
+ }
37
+
38
+ type AvgCompletenessRow = {
39
+ avg_completeness: string | number | null
40
+ }
41
+
42
+ type CatalogProductRecord = Record<string, unknown> & {
43
+ id?: unknown
44
+ title?: unknown
45
+ name?: unknown
46
+ sku?: unknown
47
+ hs_code?: unknown
48
+ }
49
+
50
+ type ReadinessGap = {
51
+ submissionId: string
52
+ status: string
53
+ completenessScore: number
54
+ missingFields: string[]
55
+ }
56
+
57
+ const logger = createLogger('eudr').child({ component: 'ai-tools/compliance-pack' })
58
+
59
+ const DAY_MS = 24 * 60 * 60 * 1000
60
+
61
+ const overviewInput = z.object({}).strict()
62
+
63
+ const listStatementReadinessInput = z
64
+ .object({
65
+ statementId: z.string().uuid().optional(),
66
+ limit: z.coerce.number().int().min(1).max(50).default(10),
67
+ })
68
+ .strict()
69
+
70
+ const listEvidenceGapsInput = z
71
+ .object({
72
+ commodity: z.enum(EUDR_COMMODITIES).optional(),
73
+ supplierEntityId: z.string().uuid().optional(),
74
+ limit: z.coerce.number().int().min(1).max(100).default(25),
75
+ })
76
+ .strict()
77
+
78
+ const checkProductScopeInput = z
79
+ .object({
80
+ productId: z.string().uuid().optional(),
81
+ hsCode: z.string().trim().min(1).max(20).optional(),
82
+ })
83
+ .strict()
84
+ .refine((input) => input.productId !== undefined || input.hsCode !== undefined, {
85
+ message: 'Provide productId or hsCode',
86
+ })
87
+
88
+ const getCountryRiskInput = z
89
+ .object({
90
+ country: z
91
+ .string()
92
+ .trim()
93
+ .regex(/^[A-Za-z]{2}$/)
94
+ .transform((value) => value.toUpperCase())
95
+ .optional(),
96
+ includeLowList: z.boolean().optional(),
97
+ })
98
+ .strict()
99
+
100
+ function resolveEm(ctx: EudrToolContext): EntityManager {
101
+ return ctx.container.resolve<EntityManager>('em')
102
+ }
103
+
104
+ /**
105
+ * A MikroORM EntityManager is not concurrency-safe: parallel work on one
106
+ * instance shares its identity map and unit of work. Every branch that runs
107
+ * inside a `Promise.all` here gets its own fork.
108
+ */
109
+ function forked(em: EntityManager): EntityManager {
110
+ return em.fork()
111
+ }
112
+
113
+ function toIsoString(value: Date | string | null | undefined): string | null {
114
+ if (value == null) return null
115
+ if (value instanceof Date) return value.toISOString()
116
+ if (value.length === 0) return null
117
+ const date = new Date(value)
118
+ return Number.isNaN(date.getTime()) ? value : date.toISOString()
119
+ }
120
+
121
+ function asNumber(value: unknown): number {
122
+ if (typeof value === 'number' && Number.isFinite(value)) return value
123
+ if (typeof value === 'string' && value.trim().length > 0) {
124
+ const parsed = Number(value)
125
+ if (Number.isFinite(parsed)) return parsed
126
+ }
127
+ return 0
128
+ }
129
+
130
+ function stringArray(value: unknown): string[] {
131
+ if (!Array.isArray(value)) return []
132
+ return value.filter((entry): entry is string => typeof entry === 'string')
133
+ }
134
+
135
+ function readString(value: unknown): string | null {
136
+ return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null
137
+ }
138
+
139
+ function daysLeft(deadline: string, now: Date): number {
140
+ const deadlineDate = new Date(`${deadline}T00:00:00.000Z`)
141
+ return Math.ceil((deadlineDate.getTime() - now.getTime()) / DAY_MS)
142
+ }
143
+
144
+ function countRowsByStatus<T extends object>(
145
+ em: EntityManager,
146
+ entity: new () => T,
147
+ statuses: readonly string[],
148
+ scope: Scope,
149
+ ): Promise<Record<string, number>> {
150
+ return Promise.all(
151
+ statuses.map(async (status) => {
152
+ const count = await forked(em).count(entity, {
153
+ tenantId: scope.tenantId,
154
+ organizationId: scope.organizationId,
155
+ deletedAt: null,
156
+ status,
157
+ } as FilterQuery<T>)
158
+ return [status, count] as const
159
+ }),
160
+ ).then((entries) => Object.fromEntries(entries))
161
+ }
162
+
163
+ async function fetchAverageCompleteness(em: EntityManager, scope: Scope): Promise<number | null> {
164
+ const rows = await em.getConnection().execute(
165
+ `select avg(completeness_score) as avg_completeness
166
+ from eudr_evidence_submissions
167
+ where tenant_id = ?
168
+ and organization_id = ?
169
+ and deleted_at is null`,
170
+ [scope.tenantId, scope.organizationId],
171
+ ) as AvgCompletenessRow[]
172
+ const value = rows[0]?.avg_completeness ?? null
173
+ if (value === null) return null
174
+ const parsed = typeof value === 'number' ? value : Number(value)
175
+ return Number.isFinite(parsed) ? parsed : null
176
+ }
177
+
178
+ function hasConcernAnswers(criteria: Record<string, { answer?: string }>): boolean {
179
+ return Object.values(criteria).some((entry) => entry.answer === 'concern')
180
+ }
181
+
182
+ function buildReadinessGaps(submissions: EudrEvidenceSubmission[]): ReadinessGap[] {
183
+ return submissions
184
+ .filter((submission) => submission.status !== 'verified' || asNumber(submission.completenessScore) !== 100)
185
+ .map((submission) => ({
186
+ submissionId: submission.id,
187
+ status: submission.status,
188
+ completenessScore: asNumber(submission.completenessScore),
189
+ missingFields: stringArray(submission.missingFields),
190
+ }))
191
+ }
192
+
193
+ function riskSummary(assessment: EudrRiskAssessment | null) {
194
+ if (!assessment) return null
195
+ return {
196
+ conclusion: assessment.conclusion,
197
+ overallTier: assessment.overallTier,
198
+ reviewDueAt: toIsoString(assessment.reviewDueAt),
199
+ }
200
+ }
201
+
202
+ async function loadSubmissionsForStatements(
203
+ em: EntityManager,
204
+ statementIds: string[],
205
+ scope: Scope,
206
+ ): Promise<Map<string, EudrEvidenceSubmission[]>> {
207
+ const byStatement = new Map<string, EudrEvidenceSubmission[]>()
208
+ if (!statementIds.length) return byStatement
209
+ const submissions = await findWithDecryption(
210
+ em,
211
+ EudrEvidenceSubmission,
212
+ {
213
+ statementId: { $in: statementIds },
214
+ tenantId: scope.tenantId,
215
+ organizationId: scope.organizationId,
216
+ deletedAt: null,
217
+ } as FilterQuery<EudrEvidenceSubmission>,
218
+ { orderBy: { createdAt: 'ASC' } },
219
+ scope,
220
+ )
221
+ for (const submission of submissions) {
222
+ if (!submission.statementId) continue
223
+ const existing = byStatement.get(submission.statementId) ?? []
224
+ existing.push(submission)
225
+ byStatement.set(submission.statementId, existing)
226
+ }
227
+ return byStatement
228
+ }
229
+
230
+ async function loadLatestAssessmentsForStatements(
231
+ em: EntityManager,
232
+ statementIds: string[],
233
+ scope: Scope,
234
+ ): Promise<Map<string, EudrRiskAssessment>> {
235
+ const latestByStatement = new Map<string, EudrRiskAssessment>()
236
+ if (!statementIds.length) return latestByStatement
237
+ const assessments = await findWithDecryption(
238
+ em,
239
+ EudrRiskAssessment,
240
+ {
241
+ statementId: { $in: statementIds },
242
+ tenantId: scope.tenantId,
243
+ organizationId: scope.organizationId,
244
+ deletedAt: null,
245
+ } as FilterQuery<EudrRiskAssessment>,
246
+ { orderBy: { assessedAt: 'DESC', createdAt: 'DESC' } },
247
+ scope,
248
+ )
249
+ for (const assessment of assessments) {
250
+ if (latestByStatement.has(assessment.statementId)) continue
251
+ latestByStatement.set(assessment.statementId, assessment)
252
+ }
253
+ return latestByStatement
254
+ }
255
+
256
+ async function buildGateAssessment(
257
+ em: EntityManager,
258
+ assessment: EudrRiskAssessment | null,
259
+ scope: Scope,
260
+ ): Promise<GateAssessmentView> {
261
+ if (!assessment) return null
262
+ const completedMitigationCount = await em.count(EudrMitigationAction, {
263
+ riskAssessmentId: assessment.id,
264
+ tenantId: scope.tenantId,
265
+ organizationId: scope.organizationId,
266
+ status: 'completed',
267
+ deletedAt: null,
268
+ })
269
+ return {
270
+ conclusion: assessment.conclusion,
271
+ countryRisks: assessment.countryRisks.map((risk) => ({ country: risk.country, tier: risk.tier })),
272
+ reviewDueAt: assessment.reviewDueAt ?? null,
273
+ hasConcernAnswers: hasConcernAnswers(assessment.criteria),
274
+ hasCompletedMitigation: completedMitigationCount > 0,
275
+ }
276
+ }
277
+
278
+ const GATE_REASON_TEXT: Record<string, string> = {
279
+ referencedStatementsRequired: 'Referenced due diligence statement numbers are required for SME trader statements.',
280
+ noSubmissions: 'No evidence submissions are linked to this statement.',
281
+ submissionsNotReady: 'All linked evidence submissions must be verified and 100% complete.',
282
+ originCountryMissing: 'Every linked evidence submission must include an origin country.',
283
+ riskConclusionMissing: 'A latest negligible-risk assessment is required unless all origin countries are low risk.',
284
+ riskAssessmentStale: 'The latest risk assessment does not cover the current set of origin countries.',
285
+ riskReviewOverdue: 'The latest risk assessment review date is overdue.',
286
+ mitigationIncomplete: 'At least one completed mitigation action is required for concern answers.',
287
+ }
288
+
289
+ function gateReasonKey(reason: string): string {
290
+ return `eudr.gate.${reason}`
291
+ }
292
+
293
+ function gateReasonText(reason: string): string {
294
+ return GATE_REASON_TEXT[reason] ?? reason
295
+ }
296
+
297
+ async function loadCatalogProductById(
298
+ ctx: EudrToolContext,
299
+ productId: string | undefined,
300
+ ): Promise<{
301
+ id: string
302
+ name: string | null
303
+ sku: string | null
304
+ hsCode: string | null
305
+ } | null> {
306
+ if (!productId) return null
307
+ try {
308
+ const queryEngine = ctx.container.resolve<QueryEngine>('queryEngine')
309
+ const scope = assertTenantScope(ctx)
310
+ const result = await queryEngine.query<CatalogProductRecord>(E.catalog.catalog_product, {
311
+ fields: ['id', 'title', 'name', 'sku', 'hs_code'],
312
+ filters: [
313
+ { field: 'id', op: 'eq', value: productId },
314
+ ],
315
+ page: { page: 1, pageSize: 1 },
316
+ tenantId: scope.tenantId,
317
+ organizationId: scope.organizationId,
318
+ })
319
+ const product = result.items[0]
320
+ if (!product) return null
321
+ const id = readString(product.id)
322
+ if (!id) return null
323
+ return {
324
+ id,
325
+ name: readString(product.title) ?? readString(product.name),
326
+ sku: readString(product.sku),
327
+ hsCode: readString(product.hs_code),
328
+ }
329
+ } catch (err) {
330
+ // A lookup failure is not the same as "product does not exist"; surface it so
331
+ // check_product_scope cannot report an absent product on an infra error.
332
+ logger.warn('catalog product lookup failed', { err })
333
+ throw err
334
+ }
335
+ }
336
+
337
+ const getComplianceOverviewTool: EudrAiToolDefinition = {
338
+ name: 'eudr.get_compliance_overview',
339
+ displayName: 'Get EUDR compliance overview',
340
+ description:
341
+ 'Returns a live EUDR readiness dashboard for the current tenant and organization. Use this when the operator asks for overall compliance status, deadlines, how many mappings/submissions/statements exist, or whether risk reviews are coming due. Fields returned: deadline { date, daysLeft }, mappingsInScope, submissions { total, byStatus, incomplete, avgCompleteness }, statements { total, byStatus, notReady, missingReference }, and riskReviewsDueSoon.',
342
+ inputSchema: overviewInput,
343
+ requiredFeatures: ['eudr.statements.view', 'eudr.mappings.view', 'eudr.submissions.view', 'eudr.risk.view'],
344
+ tags: ['read', 'eudr', 'overview', 'compliance'],
345
+ isMutation: false,
346
+ handler: async (rawInput, ctx) => {
347
+ overviewInput.parse(rawInput)
348
+ const scope = assertTenantScope(ctx)
349
+ const em = resolveEm(ctx)
350
+ const now = new Date()
351
+ const reviewWindowEnd = new Date(now.getTime() + 30 * DAY_MS)
352
+
353
+ const [
354
+ mappingsInScope,
355
+ submissionsTotal,
356
+ submissionsByStatus,
357
+ avgCompleteness,
358
+ incomplete,
359
+ statementsTotal,
360
+ statementsByStatus,
361
+ notReady,
362
+ missingReference,
363
+ riskReviewsDueSoon,
364
+ ] = await Promise.all([
365
+ forked(em).count(EudrProductMapping, { ...scope, deletedAt: null, isInScope: true }),
366
+ forked(em).count(EudrEvidenceSubmission, { ...scope, deletedAt: null }),
367
+ countRowsByStatus(em, EudrEvidenceSubmission, EUDR_SUBMISSION_STATUSES, scope),
368
+ fetchAverageCompleteness(forked(em), scope),
369
+ forked(em).count(EudrEvidenceSubmission, {
370
+ ...scope,
371
+ deletedAt: null,
372
+ completenessScore: { $lt: 100 },
373
+ } as FilterQuery<EudrEvidenceSubmission>),
374
+ forked(em).count(EudrDueDiligenceStatement, { ...scope, deletedAt: null }),
375
+ countRowsByStatus(em, EudrDueDiligenceStatement, EUDR_STATEMENT_STATUSES, scope),
376
+ forked(em).count(EudrDueDiligenceStatement, { ...scope, deletedAt: null, status: 'draft' }),
377
+ forked(em).count(EudrDueDiligenceStatement, {
378
+ ...scope,
379
+ deletedAt: null,
380
+ status: { $in: ['submitted', 'available'] },
381
+ referenceNumber: null,
382
+ } as FilterQuery<EudrDueDiligenceStatement>),
383
+ forked(em).count(EudrRiskAssessment, {
384
+ ...scope,
385
+ deletedAt: null,
386
+ reviewDueAt: { $gte: now, $lte: reviewWindowEnd },
387
+ } as FilterQuery<EudrRiskAssessment>),
388
+ ])
389
+
390
+ return {
391
+ deadline: {
392
+ date: EUDR_APPLICATION_DATES.largeAndMedium,
393
+ daysLeft: daysLeft(EUDR_APPLICATION_DATES.largeAndMedium, now),
394
+ },
395
+ mappingsInScope,
396
+ submissions: {
397
+ total: submissionsTotal,
398
+ byStatus: submissionsByStatus,
399
+ avgCompleteness,
400
+ incomplete,
401
+ },
402
+ statements: {
403
+ total: statementsTotal,
404
+ byStatus: statementsByStatus,
405
+ notReady,
406
+ missingReference,
407
+ },
408
+ riskReviewsDueSoon,
409
+ }
410
+ },
411
+ }
412
+
413
+ const listStatementReadinessTool: EudrAiToolDefinition = {
414
+ name: 'eudr.list_statement_readiness',
415
+ displayName: 'List EUDR statement readiness',
416
+ description:
417
+ 'Checks due diligence statement export/submission readiness for one statement or the most recent non-archived statements. Use this when the operator asks whether statements are ready to submit/export, why a draft cannot move forward, what evidence is blocking a statement, or what the latest risk result says. Fields returned per item: id, title, status, commodity, readiness { ready, submissionCount, verifiedCount, completeCount, gaps [{ submissionId, status, completenessScore, missingFields }] }, latestRisk { conclusion, overallTier, reviewDueAt } or null, gateReasons as eudr.gate.* keys, and gateReasonsPlainText.',
418
+ inputSchema: listStatementReadinessInput,
419
+ requiredFeatures: ['eudr.statements.view', 'eudr.submissions.view', 'eudr.risk.view'],
420
+ tags: ['read', 'eudr', 'statements', 'readiness'],
421
+ isMutation: false,
422
+ handler: async (rawInput, ctx) => {
423
+ const input = listStatementReadinessInput.parse(rawInput)
424
+ const scope = assertTenantScope(ctx)
425
+ const em = resolveEm(ctx)
426
+ const statementWhere: FilterQuery<EudrDueDiligenceStatement> = input.statementId
427
+ ? {
428
+ id: input.statementId,
429
+ tenantId: scope.tenantId,
430
+ organizationId: scope.organizationId,
431
+ deletedAt: null,
432
+ }
433
+ : {
434
+ tenantId: scope.tenantId,
435
+ organizationId: scope.organizationId,
436
+ deletedAt: null,
437
+ status: { $ne: 'archived' },
438
+ }
439
+ const statements = await em.find(EudrDueDiligenceStatement, statementWhere, {
440
+ orderBy: { updatedAt: 'DESC', createdAt: 'DESC' },
441
+ limit: input.statementId ? 1 : input.limit,
442
+ })
443
+ const statementIds = statements.map((statement) => statement.id)
444
+ const submissionsByStatement = await loadSubmissionsForStatements(em, statementIds, scope)
445
+ const latestRiskByStatement = await loadLatestAssessmentsForStatements(em, statementIds, scope)
446
+
447
+ const items = await Promise.all(
448
+ statements.map(async (statement) => {
449
+ const submissions = submissionsByStatement.get(statement.id) ?? []
450
+ const latestAssessment = latestRiskByStatement.get(statement.id) ?? null
451
+ const readinessGaps = buildReadinessGaps(submissions)
452
+ const gateSubmissions: GateSubmissionView[] = submissions.map((submission) => ({
453
+ status: submission.status,
454
+ completenessScore: asNumber(submission.completenessScore),
455
+ originCountry: submission.originCountry ?? null,
456
+ }))
457
+ const gate = evaluateSubmissionGate({
458
+ actorRole: statement.actorRole ?? null,
459
+ referencedStatementsCount: Array.isArray(statement.referencedStatements)
460
+ ? statement.referencedStatements.length
461
+ : 0,
462
+ submissions: gateSubmissions,
463
+ latestAssessment: await buildGateAssessment(forked(em), latestAssessment, scope),
464
+ })
465
+
466
+ return {
467
+ id: statement.id,
468
+ title: statement.title,
469
+ status: statement.status,
470
+ commodity: statement.commodity,
471
+ readiness: {
472
+ ready: submissions.length > 0 && readinessGaps.length === 0,
473
+ submissionCount: submissions.length,
474
+ verifiedCount: submissions.filter((submission) => submission.status === 'verified').length,
475
+ completeCount: submissions.filter((submission) => asNumber(submission.completenessScore) === 100).length,
476
+ gaps: readinessGaps,
477
+ },
478
+ latestRisk: riskSummary(latestAssessment),
479
+ gateReasons: gate.reasons.map(gateReasonKey),
480
+ gateReasonsPlainText: gate.reasons.map(gateReasonText),
481
+ }
482
+ }),
483
+ )
484
+
485
+ return {
486
+ items,
487
+ count: items.length,
488
+ }
489
+ },
490
+ }
491
+
492
+ const listEvidenceGapsTool: EudrAiToolDefinition = {
493
+ name: 'eudr.list_evidence_gaps',
494
+ displayName: 'List EUDR evidence gaps',
495
+ description:
496
+ 'Lists incomplete EUDR evidence submissions for the current tenant and organization. Use this when the operator asks what supplier evidence is missing, which submissions are incomplete, which origin countries increase risk, or where to focus cleanup. Fields returned per item: id, supplier, commodity, status, completenessScore, missingFields, originCountry, and countryRiskTier.',
497
+ inputSchema: listEvidenceGapsInput,
498
+ requiredFeatures: ['eudr.submissions.view'],
499
+ tags: ['read', 'eudr', 'submissions', 'gaps'],
500
+ isMutation: false,
501
+ handler: async (rawInput, ctx) => {
502
+ const input = listEvidenceGapsInput.parse(rawInput)
503
+ const scope = assertTenantScope(ctx)
504
+ const em = resolveEm(ctx)
505
+ const where: FilterQuery<EudrEvidenceSubmission> = {
506
+ tenantId: scope.tenantId,
507
+ organizationId: scope.organizationId,
508
+ deletedAt: null,
509
+ completenessScore: { $lt: 100 },
510
+ }
511
+ if (input.commodity) where.commodity = input.commodity
512
+ if (input.supplierEntityId) where.supplierEntityId = input.supplierEntityId
513
+
514
+ const submissions = await findWithDecryption(
515
+ em,
516
+ EudrEvidenceSubmission,
517
+ where,
518
+ { orderBy: { completenessScore: 'ASC', updatedAt: 'DESC' }, limit: input.limit },
519
+ scope,
520
+ )
521
+
522
+ return {
523
+ items: submissions.map((submission) => ({
524
+ id: submission.id,
525
+ supplier: submission.supplierSnapshot?.displayName ?? null,
526
+ commodity: submission.commodity,
527
+ status: submission.status,
528
+ completenessScore: asNumber(submission.completenessScore),
529
+ missingFields: stringArray(submission.missingFields),
530
+ originCountry: submission.originCountry ?? null,
531
+ countryRiskTier: getCountryRiskTier(submission.originCountry ?? null),
532
+ })),
533
+ count: submissions.length,
534
+ limit: input.limit,
535
+ }
536
+ },
537
+ }
538
+
539
+ const checkProductScopeTool: EudrAiToolDefinition = {
540
+ name: 'eudr.check_product_scope',
541
+ displayName: 'Check EUDR product scope',
542
+ description:
543
+ 'Checks whether a product or HS code appears in EUDR Annex I scope. Use this when the operator asks if a product needs EUDR mapping, wants a commodity suggestion from an HS code, or needs to compare existing mappings against catalog HS data. Fields returned: existingMappings [{ id, commodity, isInScope, hsCode }], catalogProduct { id, name, sku, hsCode } or null, suggestedCommodity, and inAnnexScope.',
544
+ inputSchema: checkProductScopeInput,
545
+ requiredFeatures: ['eudr.mappings.view'],
546
+ tags: ['read', 'eudr', 'mappings', 'scope'],
547
+ isMutation: false,
548
+ handler: async (rawInput, ctx) => {
549
+ const input = checkProductScopeInput.parse(rawInput)
550
+ const scope = assertTenantScope(ctx)
551
+ const em = resolveEm(ctx)
552
+ const catalogProduct = await loadCatalogProductById(ctx, input.productId)
553
+ const existingMappings = input.productId
554
+ ? await em.find(EudrProductMapping, {
555
+ productId: input.productId,
556
+ tenantId: scope.tenantId,
557
+ organizationId: scope.organizationId,
558
+ deletedAt: null,
559
+ } as FilterQuery<EudrProductMapping>, {
560
+ orderBy: { createdAt: 'DESC' },
561
+ limit: 50,
562
+ })
563
+ : []
564
+ const effectiveHsCode = input.hsCode ?? catalogProduct?.hsCode ?? null
565
+ const suggestedCommodity = suggestCommodityForHsCode(effectiveHsCode)
566
+
567
+ return {
568
+ existingMappings: existingMappings.map((mapping) => ({
569
+ id: mapping.id,
570
+ commodity: mapping.commodity,
571
+ isInScope: mapping.isInScope,
572
+ hsCode: mapping.hsCode ?? null,
573
+ })),
574
+ catalogProduct,
575
+ suggestedCommodity,
576
+ inAnnexScope: suggestedCommodity !== null,
577
+ }
578
+ },
579
+ }
580
+
581
+ const getCountryRiskTool: EudrAiToolDefinition = {
582
+ name: 'eudr.get_country_risk',
583
+ displayName: 'Get EUDR country risk',
584
+ description:
585
+ 'Returns the current EUDR country-risk tier from the module reference data. Use this when the operator asks whether a specific origin country is low, standard, high, or unknown risk, or when they need the compact high-risk list. With country, returns { country, tier }. Without country, returns { high, lowCount, note } and only includes the low-risk list when includeLowList is true.',
586
+ inputSchema: getCountryRiskInput,
587
+ // Static, law-versioned reference data — no tenant rows are read, so this is
588
+ // gated on the module's lowest-privilege view feature rather than submissions.
589
+ requiredFeatures: ['eudr.mappings.view'],
590
+ tags: ['read', 'eudr', 'country-risk', 'reference-data'],
591
+ isMutation: false,
592
+ handler: async (rawInput, ctx) => {
593
+ const input = getCountryRiskInput.parse(rawInput)
594
+ assertTenantScope(ctx)
595
+ if (input.country) {
596
+ return {
597
+ country: input.country,
598
+ tier: getCountryRiskTier(input.country),
599
+ }
600
+ }
601
+ return {
602
+ high: [...EUDR_HIGH_RISK_COUNTRIES],
603
+ lowCount: EUDR_LOW_RISK_COUNTRIES.length,
604
+ ...(input.includeLowList === true ? { low: [...EUDR_LOW_RISK_COUNTRIES] } : {}),
605
+ note: 'Unlisted countries are standard risk.',
606
+ }
607
+ },
608
+ }
609
+
610
+ export const eudrComplianceAiTools: EudrAiToolDefinition[] = [
611
+ getComplianceOverviewTool,
612
+ listStatementReadinessTool,
613
+ listEvidenceGapsTool,
614
+ checkProductScopeTool,
615
+ getCountryRiskTool,
616
+ ]
617
+
618
+ export default eudrComplianceAiTools
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Local AI tool shape for the EUDR module.
3
+ *
4
+ * Mirrors the catalog module pattern: keep the module contribution as plain
5
+ * serializable tool objects so the generator can discover them without adding
6
+ * runtime AI assistant imports to the core module graph.
7
+ */
8
+ import type { AwilixContainer } from 'awilix'
9
+ import type { z } from 'zod'
10
+
11
+ export interface EudrToolContext {
12
+ tenantId: string | null
13
+ organizationId: string | null
14
+ userId: string | null
15
+ container: AwilixContainer
16
+ userFeatures: string[]
17
+ isSuperAdmin: boolean
18
+ apiKeySecret?: string
19
+ sessionId?: string
20
+ }
21
+
22
+ export interface EudrAiToolDefinition<TInput = unknown, TOutput = unknown> {
23
+ name: string
24
+ displayName?: string
25
+ description: string
26
+ inputSchema: z.ZodType<TInput>
27
+ requiredFeatures?: string[]
28
+ tags?: string[]
29
+ isMutation?: boolean
30
+ isBulk?: boolean
31
+ maxCallsPerTurn?: number
32
+ supportsAttachments?: boolean
33
+ handler: (input: TInput, context: EudrToolContext) => Promise<TOutput>
34
+ }
35
+
36
+ export function assertTenantScope(ctx: EudrToolContext): {
37
+ tenantId: string
38
+ organizationId: string
39
+ } {
40
+ if (!ctx.tenantId || !ctx.organizationId) {
41
+ throw new Error('[internal] Tenant and organization context is required for eudr.* tools')
42
+ }
43
+ return { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
44
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Module-root AI tool contribution for the EUDR module.
3
+ *
4
+ * The generator discovers this file and aggregates the read-only compliance
5
+ * pack into the global AI tool registry. The pack exposes scoped EUDR
6
+ * readiness, evidence-gap, product-scope, and country-risk tools only.
7
+ */
8
+ import eudrComplianceAiTools from './ai-tools/compliance-pack'
9
+ import type { EudrAiToolDefinition } from './ai-tools/types'
10
+
11
+ export const aiTools: EudrAiToolDefinition[] = [
12
+ ...eudrComplianceAiTools,
13
+ ]
14
+
15
+ export default aiTools