@open-mercato/core 0.6.8-develop.6925.1.cefa200fa4 → 0.6.8-develop.6930.1.1e5976efc3
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.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/eudr_due_diligence_statement/index.js +47 -0
- package/dist/generated/entities/eudr_due_diligence_statement/index.js.map +7 -0
- package/dist/generated/entities/eudr_evidence_submission/index.js +51 -0
- package/dist/generated/entities/eudr_evidence_submission/index.js.map +7 -0
- package/dist/generated/entities/eudr_mitigation_action/index.js +31 -0
- package/dist/generated/entities/eudr_mitigation_action/index.js.map +7 -0
- package/dist/generated/entities/eudr_plot/index.js +39 -0
- package/dist/generated/entities/eudr_plot/index.js.map +7 -0
- package/dist/generated/entities/eudr_product_mapping/index.js +31 -0
- package/dist/generated/entities/eudr_product_mapping/index.js.map +7 -0
- package/dist/generated/entities/eudr_risk_assessment/index.js +35 -0
- package/dist/generated/entities/eudr_risk_assessment/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +9 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +120 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/attachments/fields/attachment.js +5 -1
- package/dist/modules/attachments/fields/attachment.js.map +2 -2
- package/dist/modules/attachments/lib/crud.js +3 -1
- package/dist/modules/attachments/lib/crud.js.map +2 -2
- package/dist/modules/eudr/acl.js +43 -0
- package/dist/modules/eudr/acl.js.map +7 -0
- package/dist/modules/eudr/ai-agents.js +205 -0
- package/dist/modules/eudr/ai-agents.js.map +7 -0
- package/dist/modules/eudr/ai-tools/compliance-pack.js +495 -0
- package/dist/modules/eudr/ai-tools/compliance-pack.js.map +7 -0
- package/dist/modules/eudr/ai-tools/types.js +10 -0
- package/dist/modules/eudr/ai-tools/types.js.map +7 -0
- package/dist/modules/eudr/ai-tools.js +10 -0
- package/dist/modules/eudr/ai-tools.js.map +7 -0
- package/dist/modules/eudr/api/dashboard/widgets/compliance-overview/route.js +386 -0
- package/dist/modules/eudr/api/dashboard/widgets/compliance-overview/route.js.map +7 -0
- package/dist/modules/eudr/api/evidence-submissions/route.js +318 -0
- package/dist/modules/eudr/api/evidence-submissions/route.js.map +7 -0
- package/dist/modules/eudr/api/mitigation-actions/route.js +249 -0
- package/dist/modules/eudr/api/mitigation-actions/route.js.map +7 -0
- package/dist/modules/eudr/api/openapi.js +27 -0
- package/dist/modules/eudr/api/openapi.js.map +7 -0
- package/dist/modules/eudr/api/plots/import/route.js +294 -0
- package/dist/modules/eudr/api/plots/import/route.js.map +7 -0
- package/dist/modules/eudr/api/plots/route.js +279 -0
- package/dist/modules/eudr/api/plots/route.js.map +7 -0
- package/dist/modules/eudr/api/product-mappings/route.js +257 -0
- package/dist/modules/eudr/api/product-mappings/route.js.map +7 -0
- package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js +298 -0
- package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js.map +7 -0
- package/dist/modules/eudr/api/product-mappings/suggestions/route.js +132 -0
- package/dist/modules/eudr/api/product-mappings/suggestions/route.js.map +7 -0
- package/dist/modules/eudr/api/reports/annual/route.js +266 -0
- package/dist/modules/eudr/api/reports/annual/route.js.map +7 -0
- package/dist/modules/eudr/api/risk-assessments/route.js +300 -0
- package/dist/modules/eudr/api/risk-assessments/route.js.map +7 -0
- package/dist/modules/eudr/api/statements/[id]/export/route.js +631 -0
- package/dist/modules/eudr/api/statements/[id]/export/route.js.map +7 -0
- package/dist/modules/eudr/api/statements/[id]/readiness/route.js +111 -0
- package/dist/modules/eudr/api/statements/[id]/readiness/route.js.map +7 -0
- package/dist/modules/eudr/api/statements/route.js +314 -0
- package/dist/modules/eudr/api/statements/route.js.map +7 -0
- package/dist/modules/eudr/api/suppliers/compliance/route.js +173 -0
- package/dist/modules/eudr/api/suppliers/compliance/route.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.js +468 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.js +351 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.js +17 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +313 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/page.js +360 -0
- package/dist/modules/eudr/backend/eudr/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/plots/[id]/page.js +346 -0
- package/dist/modules/eudr/backend/eudr/plots/[id]/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/plots/[id]/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/plots/[id]/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/plots/create/page.js +253 -0
- package/dist/modules/eudr/backend/eudr/plots/create/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/plots/create/page.meta.js +17 -0
- package/dist/modules/eudr/backend/eudr/plots/create/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/plots/page.js +386 -0
- package/dist/modules/eudr/backend/eudr/plots/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/plots/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/plots/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.js +253 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/create/page.js +174 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/create/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/create/page.meta.js +17 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/create/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js +306 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.js +335 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.js +220 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.meta.js +17 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +324 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/statements/[id]/page.js +648 -0
- package/dist/modules/eudr/backend/eudr/statements/[id]/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/statements/[id]/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/statements/[id]/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/statements/create/page.js +432 -0
- package/dist/modules/eudr/backend/eudr/statements/create/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/statements/create/page.meta.js +17 -0
- package/dist/modules/eudr/backend/eudr/statements/create/page.meta.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/statements/page.js +309 -0
- package/dist/modules/eudr/backend/eudr/statements/page.js.map +7 -0
- package/dist/modules/eudr/backend/eudr/statements/page.meta.js +16 -0
- package/dist/modules/eudr/backend/eudr/statements/page.meta.js.map +7 -0
- package/dist/modules/eudr/ce.js +56 -0
- package/dist/modules/eudr/ce.js.map +7 -0
- package/dist/modules/eudr/commands/evidence-submissions.js +571 -0
- package/dist/modules/eudr/commands/evidence-submissions.js.map +7 -0
- package/dist/modules/eudr/commands/index.js +7 -0
- package/dist/modules/eudr/commands/index.js.map +7 -0
- package/dist/modules/eudr/commands/lifecycle-events.js +19 -0
- package/dist/modules/eudr/commands/lifecycle-events.js.map +7 -0
- package/dist/modules/eudr/commands/mitigation-actions.js +488 -0
- package/dist/modules/eudr/commands/mitigation-actions.js.map +7 -0
- package/dist/modules/eudr/commands/plots.js +517 -0
- package/dist/modules/eudr/commands/plots.js.map +7 -0
- package/dist/modules/eudr/commands/product-mappings.js +468 -0
- package/dist/modules/eudr/commands/product-mappings.js.map +7 -0
- package/dist/modules/eudr/commands/risk-assessments.js +599 -0
- package/dist/modules/eudr/commands/risk-assessments.js.map +7 -0
- package/dist/modules/eudr/commands/statements.js +747 -0
- package/dist/modules/eudr/commands/statements.js.map +7 -0
- package/dist/modules/eudr/components/CountrySelectField.js +64 -0
- package/dist/modules/eudr/components/CountrySelectField.js.map +7 -0
- package/dist/modules/eudr/components/GeometryInput.js +133 -0
- package/dist/modules/eudr/components/GeometryInput.js.map +7 -0
- package/dist/modules/eudr/components/MappingSuggestionsDialog.js +307 -0
- package/dist/modules/eudr/components/MappingSuggestionsDialog.js.map +7 -0
- package/dist/modules/eudr/components/MitigationActionsSection.js +345 -0
- package/dist/modules/eudr/components/MitigationActionsSection.js.map +7 -0
- package/dist/modules/eudr/components/OrderSelectField.js +88 -0
- package/dist/modules/eudr/components/OrderSelectField.js.map +7 -0
- package/dist/modules/eudr/components/PlotImportDialog.js +229 -0
- package/dist/modules/eudr/components/PlotImportDialog.js.map +7 -0
- package/dist/modules/eudr/components/PlotMapPreview.js +35 -0
- package/dist/modules/eudr/components/PlotMapPreview.js.map +7 -0
- package/dist/modules/eudr/components/PlotMapPreviewImpl.js +97 -0
- package/dist/modules/eudr/components/PlotMapPreviewImpl.js.map +7 -0
- package/dist/modules/eudr/components/PlotMultiSelectField.js +198 -0
- package/dist/modules/eudr/components/PlotMultiSelectField.js.map +7 -0
- package/dist/modules/eudr/components/RiskCriteriaField.js +128 -0
- package/dist/modules/eudr/components/RiskCriteriaField.js.map +7 -0
- package/dist/modules/eudr/components/StatementLifecycleBar.js +274 -0
- package/dist/modules/eudr/components/StatementLifecycleBar.js.map +7 -0
- package/dist/modules/eudr/components/StatementReadinessChecklist.js +56 -0
- package/dist/modules/eudr/components/StatementReadinessChecklist.js.map +7 -0
- package/dist/modules/eudr/components/StatementRiskSection.js +179 -0
- package/dist/modules/eudr/components/StatementRiskSection.js.map +7 -0
- package/dist/modules/eudr/components/crudErrorI18n.js +31 -0
- package/dist/modules/eudr/components/crudErrorI18n.js.map +7 -0
- package/dist/modules/eudr/components/formConfig.js +593 -0
- package/dist/modules/eudr/components/formConfig.js.map +7 -0
- package/dist/modules/eudr/components/plotForm.js +68 -0
- package/dist/modules/eudr/components/plotForm.js.map +7 -0
- package/dist/modules/eudr/data/enrichers.js +62 -0
- package/dist/modules/eudr/data/enrichers.js.map +7 -0
- package/dist/modules/eudr/data/entities.js +437 -0
- package/dist/modules/eudr/data/entities.js.map +7 -0
- package/dist/modules/eudr/data/validators.js +271 -0
- package/dist/modules/eudr/data/validators.js.map +7 -0
- package/dist/modules/eudr/encryption.js +33 -0
- package/dist/modules/eudr/encryption.js.map +7 -0
- package/dist/modules/eudr/events.js +38 -0
- package/dist/modules/eudr/events.js.map +7 -0
- package/dist/modules/eudr/index.js +15 -0
- package/dist/modules/eudr/index.js.map +7 -0
- package/dist/modules/eudr/lib/annual-report.js +104 -0
- package/dist/modules/eudr/lib/annual-report.js.map +7 -0
- package/dist/modules/eudr/lib/completeness.js +64 -0
- package/dist/modules/eudr/lib/completeness.js.map +7 -0
- package/dist/modules/eudr/lib/detail-read-scope.js +16 -0
- package/dist/modules/eudr/lib/detail-read-scope.js.map +7 -0
- package/dist/modules/eudr/lib/geometry.js +142 -0
- package/dist/modules/eudr/lib/geometry.js.map +7 -0
- package/dist/modules/eudr/lib/notifications.js +56 -0
- package/dist/modules/eudr/lib/notifications.js.map +7 -0
- package/dist/modules/eudr/lib/plural.js +26 -0
- package/dist/modules/eudr/lib/plural.js.map +7 -0
- package/dist/modules/eudr/lib/reference-data.js +240 -0
- package/dist/modules/eudr/lib/reference-data.js.map +7 -0
- package/dist/modules/eudr/lib/species.js +10 -0
- package/dist/modules/eudr/lib/species.js.map +7 -0
- package/dist/modules/eudr/lib/statement-lifecycle.js +84 -0
- package/dist/modules/eudr/lib/statement-lifecycle.js.map +7 -0
- package/dist/modules/eudr/lib/statement-seeding.js +49 -0
- package/dist/modules/eudr/lib/statement-seeding.js.map +7 -0
- package/dist/modules/eudr/migrations/Migration20260706102002_eudr.js +15 -0
- package/dist/modules/eudr/migrations/Migration20260706102002_eudr.js.map +7 -0
- package/dist/modules/eudr/migrations/Migration20260706152612_eudr.js +24 -0
- package/dist/modules/eudr/migrations/Migration20260706152612_eudr.js.map +7 -0
- package/dist/modules/eudr/migrations/Migration20260722100000_eudr.js +15 -0
- package/dist/modules/eudr/migrations/Migration20260722100000_eudr.js.map +7 -0
- package/dist/modules/eudr/notifications.js +58 -0
- package/dist/modules/eudr/notifications.js.map +7 -0
- package/dist/modules/eudr/search.js +186 -0
- package/dist/modules/eudr/search.js.map +7 -0
- package/dist/modules/eudr/setup.js +12 -0
- package/dist/modules/eudr/setup.js.map +7 -0
- package/dist/modules/eudr/subscribers/notify-mitigation-completed.js +34 -0
- package/dist/modules/eudr/subscribers/notify-mitigation-completed.js.map +7 -0
- package/dist/modules/eudr/subscribers/notify-risk-concluded.js +35 -0
- package/dist/modules/eudr/subscribers/notify-risk-concluded.js.map +7 -0
- package/dist/modules/eudr/subscribers/notify-statement-reference-issued.js +37 -0
- package/dist/modules/eudr/subscribers/notify-statement-reference-issued.js.map +7 -0
- package/dist/modules/eudr/subscribers/notify-statement-submitted.js +34 -0
- package/dist/modules/eudr/subscribers/notify-statement-submitted.js.map +7 -0
- package/dist/modules/eudr/subscribers/notify-statement-withdrawn.js +34 -0
- package/dist/modules/eudr/subscribers/notify-statement-withdrawn.js.map +7 -0
- package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-created.js +124 -0
- package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-created.js.map +7 -0
- package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-deleted.js +22 -0
- package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-deleted.js.map +7 -0
- package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.client.js +203 -0
- package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.client.js.map +7 -0
- package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.js +23 -0
- package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.js.map +7 -0
- package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.client.js +19 -0
- package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.client.js.map +7 -0
- package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.js +31 -0
- package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.js.map +7 -0
- package/dist/modules/eudr/widgets/injection/order-compliance/widget.client.js +100 -0
- package/dist/modules/eudr/widgets/injection/order-compliance/widget.client.js.map +7 -0
- package/dist/modules/eudr/widgets/injection/order-compliance/widget.js +17 -0
- package/dist/modules/eudr/widgets/injection/order-compliance/widget.js.map +7 -0
- package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.client.js +116 -0
- package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.client.js.map +7 -0
- package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.js +17 -0
- package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.js.map +7 -0
- package/dist/modules/eudr/widgets/injection-table.js +32 -0
- package/dist/modules/eudr/widgets/injection-table.js.map +7 -0
- package/dist/modules/notifications/lib/notificationService.js +67 -3
- package/dist/modules/notifications/lib/notificationService.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +121 -48
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/sales/api/documents/factory.js +17 -0
- package/dist/modules/sales/api/documents/factory.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +32 -18
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/data/entities.js +1 -0
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/sales/migrations/Migration20260806120000_sales_tag_assignment_document_idx.js +17 -0
- package/dist/modules/sales/migrations/Migration20260806120000_sales_tag_assignment_document_idx.js.map +7 -0
- package/generated/entities/eudr_due_diligence_statement/index.ts +22 -0
- package/generated/entities/eudr_evidence_submission/index.ts +24 -0
- package/generated/entities/eudr_mitigation_action/index.ts +14 -0
- package/generated/entities/eudr_plot/index.ts +18 -0
- package/generated/entities/eudr_product_mapping/index.ts +14 -0
- package/generated/entities/eudr_risk_assessment/index.ts +16 -0
- package/generated/entities.ids.generated.ts +9 -0
- package/generated/entity-fields-registry.ts +120 -0
- package/package.json +7 -7
- package/src/modules/attachments/fields/attachment.tsx +5 -0
- package/src/modules/attachments/lib/crud.ts +2 -0
- package/src/modules/eudr/acl.ts +39 -0
- package/src/modules/eudr/ai-agents.ts +258 -0
- package/src/modules/eudr/ai-tools/compliance-pack.ts +618 -0
- package/src/modules/eudr/ai-tools/types.ts +44 -0
- package/src/modules/eudr/ai-tools.ts +15 -0
- package/src/modules/eudr/api/dashboard/widgets/compliance-overview/route.ts +481 -0
- package/src/modules/eudr/api/evidence-submissions/route.ts +335 -0
- package/src/modules/eudr/api/mitigation-actions/route.ts +263 -0
- package/src/modules/eudr/api/openapi.ts +28 -0
- package/src/modules/eudr/api/plots/import/route.ts +369 -0
- package/src/modules/eudr/api/plots/route.ts +296 -0
- package/src/modules/eudr/api/product-mappings/route.ts +269 -0
- package/src/modules/eudr/api/product-mappings/suggestions/apply/route.ts +382 -0
- package/src/modules/eudr/api/product-mappings/suggestions/route.ts +169 -0
- package/src/modules/eudr/api/reports/annual/route.ts +457 -0
- package/src/modules/eudr/api/risk-assessments/route.ts +323 -0
- package/src/modules/eudr/api/statements/[id]/export/route.ts +713 -0
- package/src/modules/eudr/api/statements/[id]/readiness/route.ts +129 -0
- package/src/modules/eudr/api/statements/route.ts +329 -0
- package/src/modules/eudr/api/suppliers/compliance/route.ts +241 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/[id]/page.tsx +545 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.ts +13 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/create/page.tsx +383 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +379 -0
- package/src/modules/eudr/backend/eudr/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/page.tsx +477 -0
- package/src/modules/eudr/backend/eudr/plots/[id]/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/plots/[id]/page.tsx +404 -0
- package/src/modules/eudr/backend/eudr/plots/create/page.meta.ts +13 -0
- package/src/modules/eudr/backend/eudr/plots/create/page.tsx +267 -0
- package/src/modules/eudr/backend/eudr/plots/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/plots/page.tsx +442 -0
- package/src/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/product-mappings/[id]/page.tsx +311 -0
- package/src/modules/eudr/backend/eudr/product-mappings/create/page.meta.ts +13 -0
- package/src/modules/eudr/backend/eudr/product-mappings/create/page.tsx +190 -0
- package/src/modules/eudr/backend/eudr/product-mappings/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +344 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/[id]/page.tsx +421 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/create/page.meta.ts +13 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/create/page.tsx +247 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +383 -0
- package/src/modules/eudr/backend/eudr/statements/[id]/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/statements/[id]/page.tsx +777 -0
- package/src/modules/eudr/backend/eudr/statements/create/page.meta.ts +13 -0
- package/src/modules/eudr/backend/eudr/statements/create/page.tsx +511 -0
- package/src/modules/eudr/backend/eudr/statements/page.meta.ts +12 -0
- package/src/modules/eudr/backend/eudr/statements/page.tsx +372 -0
- package/src/modules/eudr/ce.ts +52 -0
- package/src/modules/eudr/commands/evidence-submissions.ts +699 -0
- package/src/modules/eudr/commands/index.ts +6 -0
- package/src/modules/eudr/commands/lifecycle-events.ts +28 -0
- package/src/modules/eudr/commands/mitigation-actions.ts +574 -0
- package/src/modules/eudr/commands/plots.ts +627 -0
- package/src/modules/eudr/commands/product-mappings.ts +556 -0
- package/src/modules/eudr/commands/risk-assessments.ts +728 -0
- package/src/modules/eudr/commands/statements.ts +933 -0
- package/src/modules/eudr/components/CountrySelectField.tsx +77 -0
- package/src/modules/eudr/components/GeometryInput.tsx +170 -0
- package/src/modules/eudr/components/MappingSuggestionsDialog.tsx +385 -0
- package/src/modules/eudr/components/MitigationActionsSection.tsx +417 -0
- package/src/modules/eudr/components/OrderSelectField.tsx +116 -0
- package/src/modules/eudr/components/PlotImportDialog.tsx +277 -0
- package/src/modules/eudr/components/PlotMapPreview.tsx +46 -0
- package/src/modules/eudr/components/PlotMapPreviewImpl.tsx +111 -0
- package/src/modules/eudr/components/PlotMultiSelectField.tsx +238 -0
- package/src/modules/eudr/components/RiskCriteriaField.tsx +173 -0
- package/src/modules/eudr/components/StatementLifecycleBar.tsx +363 -0
- package/src/modules/eudr/components/StatementReadinessChecklist.tsx +82 -0
- package/src/modules/eudr/components/StatementRiskSection.tsx +242 -0
- package/src/modules/eudr/components/crudErrorI18n.ts +36 -0
- package/src/modules/eudr/components/formConfig.tsx +717 -0
- package/src/modules/eudr/components/plotForm.ts +75 -0
- package/src/modules/eudr/data/enrichers.ts +82 -0
- package/src/modules/eudr/data/entities.ts +369 -0
- package/src/modules/eudr/data/validators.ts +357 -0
- package/src/modules/eudr/encryption.ts +31 -0
- package/src/modules/eudr/events.ts +38 -0
- package/src/modules/eudr/i18n/de.json +747 -0
- package/src/modules/eudr/i18n/en.json +747 -0
- package/src/modules/eudr/i18n/es.json +747 -0
- package/src/modules/eudr/i18n/ko.json +747 -0
- package/src/modules/eudr/i18n/pl.json +747 -0
- package/src/modules/eudr/index.ts +13 -0
- package/src/modules/eudr/lib/annual-report.ts +120 -0
- package/src/modules/eudr/lib/completeness.ts +90 -0
- package/src/modules/eudr/lib/detail-read-scope.ts +44 -0
- package/src/modules/eudr/lib/geometry.ts +191 -0
- package/src/modules/eudr/lib/notifications.ts +85 -0
- package/src/modules/eudr/lib/plural.ts +36 -0
- package/src/modules/eudr/lib/reference-data.ts +128 -0
- package/src/modules/eudr/lib/species.ts +12 -0
- package/src/modules/eudr/lib/statement-lifecycle.ts +109 -0
- package/src/modules/eudr/lib/statement-seeding.ts +86 -0
- package/src/modules/eudr/migrations/.snapshot-open-mercato.json +2046 -0
- package/src/modules/eudr/migrations/Migration20260706102002_eudr.ts +16 -0
- package/src/modules/eudr/migrations/Migration20260706152612_eudr.ts +30 -0
- package/src/modules/eudr/migrations/Migration20260722100000_eudr.ts +17 -0
- package/src/modules/eudr/notifications.ts +56 -0
- package/src/modules/eudr/search.ts +212 -0
- package/src/modules/eudr/setup.ts +10 -0
- package/src/modules/eudr/subscribers/notify-mitigation-completed.ts +56 -0
- package/src/modules/eudr/subscribers/notify-risk-concluded.ts +58 -0
- package/src/modules/eudr/subscribers/notify-statement-reference-issued.ts +59 -0
- package/src/modules/eudr/subscribers/notify-statement-submitted.ts +49 -0
- package/src/modules/eudr/subscribers/notify-statement-withdrawn.ts +49 -0
- package/src/modules/eudr/subscribers/recompute-completeness-on-attachment-created.ts +189 -0
- package/src/modules/eudr/subscribers/recompute-completeness-on-attachment-deleted.ts +31 -0
- package/src/modules/eudr/widgets/dashboard/compliance-overview/widget.client.tsx +271 -0
- package/src/modules/eudr/widgets/dashboard/compliance-overview/widget.ts +24 -0
- package/src/modules/eudr/widgets/injection/eudr-product-column/widget.client.tsx +37 -0
- package/src/modules/eudr/widgets/injection/eudr-product-column/widget.ts +30 -0
- package/src/modules/eudr/widgets/injection/order-compliance/widget.client.tsx +131 -0
- package/src/modules/eudr/widgets/injection/order-compliance/widget.ts +16 -0
- package/src/modules/eudr/widgets/injection/supplier-compliance/widget.client.tsx +168 -0
- package/src/modules/eudr/widgets/injection/supplier-compliance/widget.ts +16 -0
- package/src/modules/eudr/widgets/injection-table.ts +31 -0
- package/src/modules/notifications/lib/notificationService.ts +83 -4
- package/src/modules/query_index/lib/engine.ts +139 -51
- package/src/modules/sales/api/documents/factory.ts +29 -0
- package/src/modules/sales/commands/documents.ts +65 -18
- package/src/modules/sales/data/entities.ts +1 -0
- package/src/modules/sales/migrations/.snapshot-open-mercato.json +10 -0
- 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
|