@open-mercato/core 0.4.7-develop-0a657b411f → 0.4.7-develop-e249d3e7d0
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/dist/generated/entities/carrier_shipment/index.js +37 -0
- package/dist/generated/entities/carrier_shipment/index.js.map +7 -0
- package/dist/generated/entities/gateway_transaction/index.js +47 -0
- package/dist/generated/entities/gateway_transaction/index.js.map +7 -0
- package/dist/generated/entities/webhook_processed_event/index.js +17 -0
- package/dist/generated/entities/webhook_processed_event/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +10 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +6 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/data_sync/api/runs/[id]/cancel.js +14 -5
- package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.meta.js +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.meta.js.map +1 -1
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +37 -12
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
- package/dist/modules/directory/api/get/tenants/lookup.js +1 -0
- package/dist/modules/directory/api/get/tenants/lookup.js.map +2 -2
- package/dist/modules/integrations/api/[id]/route.js +38 -11
- package/dist/modules/integrations/api/[id]/route.js.map +2 -2
- package/dist/modules/integrations/api/logs/route.js +52 -26
- package/dist/modules/integrations/api/logs/route.js.map +2 -2
- package/dist/modules/integrations/api/route.js +37 -7
- package/dist/modules/integrations/api/route.js.map +2 -2
- package/dist/modules/integrations/api/umes-read.js +121 -0
- package/dist/modules/integrations/api/umes-read.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/[id]/page.js +715 -183
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +30 -9
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/detail-page-widgets.js +46 -0
- package/dist/modules/integrations/backend/integrations/detail-page-widgets.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/page.js +78 -62
- package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/page.meta.js +2 -2
- package/dist/modules/integrations/backend/integrations/page.meta.js.map +1 -1
- package/dist/modules/integrations/setup.js +2 -2
- package/dist/modules/integrations/setup.js.map +2 -2
- package/dist/modules/payment_gateways/acl.js +12 -0
- package/dist/modules/payment_gateways/acl.js.map +7 -0
- package/dist/modules/payment_gateways/api/cancel/route.js +55 -0
- package/dist/modules/payment_gateways/api/cancel/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/capture/route.js +55 -0
- package/dist/modules/payment_gateways/api/capture/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/interceptors.js +24 -0
- package/dist/modules/payment_gateways/api/interceptors.js.map +7 -0
- package/dist/modules/payment_gateways/api/openapi.js +5 -0
- package/dist/modules/payment_gateways/api/openapi.js.map +7 -0
- package/dist/modules/payment_gateways/api/refund/route.js +56 -0
- package/dist/modules/payment_gateways/api/refund/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/sessions/route.js +74 -0
- package/dist/modules/payment_gateways/api/sessions/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/status/route.js +66 -0
- package/dist/modules/payment_gateways/api/status/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/transactions/[id]/route.js +118 -0
- package/dist/modules/payment_gateways/api/transactions/[id]/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/transactions/route.js +113 -0
- package/dist/modules/payment_gateways/api/transactions/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +136 -0
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +7 -0
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +496 -0
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +7 -0
- package/dist/modules/payment_gateways/backend/payment-gateways/page.meta.js +23 -0
- package/dist/modules/payment_gateways/backend/payment-gateways/page.meta.js.map +7 -0
- package/dist/modules/payment_gateways/data/enrichers.js +5 -0
- package/dist/modules/payment_gateways/data/enrichers.js.map +7 -0
- package/dist/modules/payment_gateways/data/entities.js +131 -0
- package/dist/modules/payment_gateways/data/entities.js.map +7 -0
- package/dist/modules/payment_gateways/data/validators.js +57 -0
- package/dist/modules/payment_gateways/data/validators.js.map +7 -0
- package/dist/modules/payment_gateways/di.js +16 -0
- package/dist/modules/payment_gateways/di.js.map +7 -0
- package/dist/modules/payment_gateways/events.js +21 -0
- package/dist/modules/payment_gateways/events.js.map +7 -0
- package/dist/modules/payment_gateways/i18n/en.js +6 -0
- package/dist/modules/payment_gateways/i18n/en.js.map +7 -0
- package/dist/modules/payment_gateways/i18n/pl.js +6 -0
- package/dist/modules/payment_gateways/i18n/pl.js.map +7 -0
- package/dist/modules/payment_gateways/index.js +9 -0
- package/dist/modules/payment_gateways/index.js.map +7 -0
- package/dist/modules/payment_gateways/lib/gateway-service.js +378 -0
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +7 -0
- package/dist/modules/payment_gateways/lib/queue.js +17 -0
- package/dist/modules/payment_gateways/lib/queue.js.map +7 -0
- package/dist/modules/payment_gateways/lib/status-machine.js +29 -0
- package/dist/modules/payment_gateways/lib/status-machine.js.map +7 -0
- package/dist/modules/payment_gateways/lib/webhook-processor.js +88 -0
- package/dist/modules/payment_gateways/lib/webhook-processor.js.map +7 -0
- package/dist/modules/payment_gateways/lib/webhook-utils.js +42 -0
- package/dist/modules/payment_gateways/lib/webhook-utils.js.map +7 -0
- package/dist/modules/payment_gateways/migrations/Migration20260305122155.js +19 -0
- package/dist/modules/payment_gateways/migrations/Migration20260305122155.js.map +7 -0
- package/dist/modules/payment_gateways/setup.js +13 -0
- package/dist/modules/payment_gateways/setup.js.map +7 -0
- package/dist/modules/payment_gateways/widgets/injection-table.js +7 -0
- package/dist/modules/payment_gateways/widgets/injection-table.js.map +7 -0
- package/dist/modules/payment_gateways/workers/status-poller.js +44 -0
- package/dist/modules/payment_gateways/workers/status-poller.js.map +7 -0
- package/dist/modules/payment_gateways/workers/webhook-processor.js +20 -0
- package/dist/modules/payment_gateways/workers/webhook-processor.js.map +7 -0
- package/dist/modules/sales/data/enrichers.js +72 -0
- package/dist/modules/sales/data/enrichers.js.map +7 -0
- package/dist/modules/sales/lib/makeSalesLineRoute.js +3 -0
- package/dist/modules/sales/lib/makeSalesLineRoute.js.map +2 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-config-field/widget.js +29 -0
- package/dist/modules/sales/widgets/injection/payment-gateway-config-field/widget.js.map +7 -0
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +23 -0
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +7 -0
- package/dist/modules/sales/widgets/injection-table.js +13 -1
- package/dist/modules/sales/widgets/injection-table.js.map +2 -2
- package/dist/modules/shipping_carriers/acl.js +10 -0
- package/dist/modules/shipping_carriers/acl.js.map +7 -0
- package/dist/modules/shipping_carriers/api/cancel/route.js +55 -0
- package/dist/modules/shipping_carriers/api/cancel/route.js.map +7 -0
- package/dist/modules/shipping_carriers/api/interceptors.js +21 -0
- package/dist/modules/shipping_carriers/api/interceptors.js.map +7 -0
- package/dist/modules/shipping_carriers/api/openapi.js +5 -0
- package/dist/modules/shipping_carriers/api/openapi.js.map +7 -0
- package/dist/modules/shipping_carriers/api/rates/route.js +55 -0
- package/dist/modules/shipping_carriers/api/rates/route.js.map +7 -0
- package/dist/modules/shipping_carriers/api/shipments/route.js +61 -0
- package/dist/modules/shipping_carriers/api/shipments/route.js.map +7 -0
- package/dist/modules/shipping_carriers/api/tracking/route.js +58 -0
- package/dist/modules/shipping_carriers/api/tracking/route.js.map +7 -0
- package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js +119 -0
- package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js.map +7 -0
- package/dist/modules/shipping_carriers/data/enrichers.js +82 -0
- package/dist/modules/shipping_carriers/data/enrichers.js.map +7 -0
- package/dist/modules/shipping_carriers/data/entities.js +80 -0
- package/dist/modules/shipping_carriers/data/entities.js.map +7 -0
- package/dist/modules/shipping_carriers/data/validators.js +49 -0
- package/dist/modules/shipping_carriers/data/validators.js.map +7 -0
- package/dist/modules/shipping_carriers/di.js +15 -0
- package/dist/modules/shipping_carriers/di.js.map +7 -0
- package/dist/modules/shipping_carriers/events.js +19 -0
- package/dist/modules/shipping_carriers/events.js.map +7 -0
- package/dist/modules/shipping_carriers/i18n/en.js +11 -0
- package/dist/modules/shipping_carriers/i18n/en.js.map +7 -0
- package/dist/modules/shipping_carriers/i18n/pl.js +11 -0
- package/dist/modules/shipping_carriers/i18n/pl.js.map +7 -0
- package/dist/modules/shipping_carriers/index.js +9 -0
- package/dist/modules/shipping_carriers/index.js.map +7 -0
- package/dist/modules/shipping_carriers/lib/adapter-registry.js +29 -0
- package/dist/modules/shipping_carriers/lib/adapter-registry.js.map +7 -0
- package/dist/modules/shipping_carriers/lib/adapter.js +1 -0
- package/dist/modules/shipping_carriers/lib/adapter.js.map +7 -0
- package/dist/modules/shipping_carriers/lib/queue.js +17 -0
- package/dist/modules/shipping_carriers/lib/queue.js.map +7 -0
- package/dist/modules/shipping_carriers/lib/shipping-service.js +155 -0
- package/dist/modules/shipping_carriers/lib/shipping-service.js.map +7 -0
- package/dist/modules/shipping_carriers/lib/status-sync.js +37 -0
- package/dist/modules/shipping_carriers/lib/status-sync.js.map +7 -0
- package/dist/modules/shipping_carriers/migrations/Migration20260305170000.js +16 -0
- package/dist/modules/shipping_carriers/migrations/Migration20260305170000.js.map +7 -0
- package/dist/modules/shipping_carriers/setup.js +13 -0
- package/dist/modules/shipping_carriers/setup.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection/create-shipment-button/widget.js +25 -0
- package/dist/modules/shipping_carriers/widgets/injection/create-shipment-button/widget.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-column/widget.js +23 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-column/widget.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js +40 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection-table.js +24 -0
- package/dist/modules/shipping_carriers/widgets/injection-table.js.map +7 -0
- package/dist/modules/shipping_carriers/workers/status-poller.js +21 -0
- package/dist/modules/shipping_carriers/workers/status-poller.js.map +7 -0
- package/dist/modules/shipping_carriers/workers/webhook-processor.js +54 -0
- package/dist/modules/shipping_carriers/workers/webhook-processor.js.map +7 -0
- package/dist/modules/translations/api/get/locales.js +1 -0
- package/dist/modules/translations/api/get/locales.js.map +2 -2
- package/dist/modules/translations/api/put/locales.js +1 -0
- package/dist/modules/translations/api/put/locales.js.map +2 -2
- package/generated/entities/carrier_shipment/index.ts +17 -0
- package/generated/entities/gateway_transaction/index.ts +22 -0
- package/generated/entities/webhook_processed_event/index.ts +7 -0
- package/generated/entities.ids.generated.ts +10 -1
- package/generated/entity-fields-registry.ts +6 -0
- package/jest.config.cjs +1 -0
- package/package.json +5 -2
- package/src/modules/auth/i18n/de.json +1 -0
- package/src/modules/auth/i18n/en.json +1 -0
- package/src/modules/auth/i18n/es.json +1 -0
- package/src/modules/auth/i18n/pl.json +1 -0
- package/src/modules/data_sync/api/runs/[id]/cancel.ts +18 -5
- package/src/modules/data_sync/backend/data-sync/page.meta.ts +2 -2
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +50 -12
- package/src/modules/directory/api/get/tenants/lookup.ts +1 -0
- package/src/modules/integrations/AGENTS.md +31 -0
- package/src/modules/integrations/api/[id]/route.ts +38 -11
- package/src/modules/integrations/api/logs/route.ts +53 -27
- package/src/modules/integrations/api/route.ts +31 -1
- package/src/modules/integrations/api/umes-read.ts +177 -0
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +902 -202
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +43 -9
- package/src/modules/integrations/backend/integrations/detail-page-widgets.ts +74 -0
- package/src/modules/integrations/backend/integrations/page.meta.ts +2 -2
- package/src/modules/integrations/backend/integrations/page.tsx +65 -54
- package/src/modules/integrations/i18n/de.json +15 -0
- package/src/modules/integrations/i18n/en.json +15 -0
- package/src/modules/integrations/i18n/es.json +15 -0
- package/src/modules/integrations/i18n/pl.json +15 -0
- package/src/modules/integrations/setup.ts +2 -2
- package/src/modules/payment_gateways/acl.ts +8 -0
- package/src/modules/payment_gateways/api/cancel/route.ts +56 -0
- package/src/modules/payment_gateways/api/capture/route.ts +56 -0
- package/src/modules/payment_gateways/api/interceptors.ts +22 -0
- package/src/modules/payment_gateways/api/openapi.ts +1 -0
- package/src/modules/payment_gateways/api/refund/route.ts +57 -0
- package/src/modules/payment_gateways/api/sessions/route.ts +76 -0
- package/src/modules/payment_gateways/api/status/route.ts +69 -0
- package/src/modules/payment_gateways/api/transactions/[id]/route.ts +123 -0
- package/src/modules/payment_gateways/api/transactions/route.ts +120 -0
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +161 -0
- package/src/modules/payment_gateways/backend/payment-gateways/page.meta.ts +19 -0
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +660 -0
- package/src/modules/payment_gateways/data/enrichers.ts +8 -0
- package/src/modules/payment_gateways/data/entities.ts +106 -0
- package/src/modules/payment_gateways/data/validators.ts +67 -0
- package/src/modules/payment_gateways/di.ts +26 -0
- package/src/modules/payment_gateways/events.ts +17 -0
- package/src/modules/payment_gateways/i18n/de.json +77 -0
- package/src/modules/payment_gateways/i18n/en.json +77 -0
- package/src/modules/payment_gateways/i18n/en.ts +4 -0
- package/src/modules/payment_gateways/i18n/es.json +77 -0
- package/src/modules/payment_gateways/i18n/pl.json +77 -0
- package/src/modules/payment_gateways/i18n/pl.ts +4 -0
- package/src/modules/payment_gateways/index.ts +5 -0
- package/src/modules/payment_gateways/lib/gateway-service.ts +486 -0
- package/src/modules/payment_gateways/lib/queue.ts +19 -0
- package/src/modules/payment_gateways/lib/status-machine.ts +28 -0
- package/src/modules/payment_gateways/lib/webhook-processor.ts +133 -0
- package/src/modules/payment_gateways/lib/webhook-utils.ts +52 -0
- package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +373 -0
- package/src/modules/payment_gateways/migrations/Migration20260305122155.ts +20 -0
- package/src/modules/payment_gateways/setup.ts +11 -0
- package/src/modules/payment_gateways/widgets/injection-table.ts +9 -0
- package/src/modules/payment_gateways/workers/status-poller.ts +58 -0
- package/src/modules/payment_gateways/workers/webhook-processor.ts +30 -0
- package/src/modules/sales/data/enrichers.ts +120 -0
- package/src/modules/sales/lib/makeSalesLineRoute.ts +3 -0
- package/src/modules/sales/widgets/injection/payment-gateway-config-field/widget.ts +28 -0
- package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +22 -0
- package/src/modules/sales/widgets/injection-table.ts +12 -0
- package/src/modules/shipping_carriers/acl.ts +6 -0
- package/src/modules/shipping_carriers/api/cancel/route.ts +53 -0
- package/src/modules/shipping_carriers/api/interceptors.ts +19 -0
- package/src/modules/shipping_carriers/api/openapi.ts +1 -0
- package/src/modules/shipping_carriers/api/rates/route.ts +53 -0
- package/src/modules/shipping_carriers/api/shipments/route.ts +59 -0
- package/src/modules/shipping_carriers/api/tracking/route.ts +56 -0
- package/src/modules/shipping_carriers/api/webhook/[provider]/route.ts +134 -0
- package/src/modules/shipping_carriers/data/enrichers.ts +89 -0
- package/src/modules/shipping_carriers/data/entities.ts +60 -0
- package/src/modules/shipping_carriers/data/validators.ts +48 -0
- package/src/modules/shipping_carriers/di.ts +20 -0
- package/src/modules/shipping_carriers/events.ts +16 -0
- package/src/modules/shipping_carriers/i18n/de.json +7 -0
- package/src/modules/shipping_carriers/i18n/en.json +7 -0
- package/src/modules/shipping_carriers/i18n/en.ts +7 -0
- package/src/modules/shipping_carriers/i18n/es.json +7 -0
- package/src/modules/shipping_carriers/i18n/pl.json +7 -0
- package/src/modules/shipping_carriers/i18n/pl.ts +7 -0
- package/src/modules/shipping_carriers/index.ts +5 -0
- package/src/modules/shipping_carriers/lib/adapter-registry.ts +33 -0
- package/src/modules/shipping_carriers/lib/adapter.ts +93 -0
- package/src/modules/shipping_carriers/lib/queue.ts +19 -0
- package/src/modules/shipping_carriers/lib/shipping-service.ts +204 -0
- package/src/modules/shipping_carriers/lib/status-sync.ts +38 -0
- package/src/modules/shipping_carriers/migrations/Migration20260305170000.ts +14 -0
- package/src/modules/shipping_carriers/setup.ts +11 -0
- package/src/modules/shipping_carriers/widgets/injection/create-shipment-button/widget.ts +24 -0
- package/src/modules/shipping_carriers/widgets/injection/tracking-column/widget.ts +22 -0
- package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.tsx +44 -0
- package/src/modules/shipping_carriers/widgets/injection-table.ts +22 -0
- package/src/modules/shipping_carriers/workers/status-poller.ts +33 -0
- package/src/modules/shipping_carriers/workers/webhook-processor.ts +79 -0
- package/src/modules/translations/api/get/locales.ts +1 -0
- package/src/modules/translations/api/put/locales.ts +1 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createModuleEvents } from '@open-mercato/shared/modules/events'
|
|
2
|
+
|
|
3
|
+
const events = [
|
|
4
|
+
{ id: 'shipping_carriers.shipment.created', label: 'Shipment Created', category: 'lifecycle', entity: 'shipment' },
|
|
5
|
+
{ id: 'shipping_carriers.shipment.status_changed', label: 'Shipment Status Changed', category: 'lifecycle', entity: 'shipment' },
|
|
6
|
+
{ id: 'shipping_carriers.shipment.delivered', label: 'Shipment Delivered', category: 'lifecycle', entity: 'shipment' },
|
|
7
|
+
{ id: 'shipping_carriers.shipment.returned', label: 'Shipment Returned', category: 'lifecycle', entity: 'shipment' },
|
|
8
|
+
{ id: 'shipping_carriers.shipment.cancelled', label: 'Shipment Cancelled', category: 'lifecycle', entity: 'shipment' },
|
|
9
|
+
{ id: 'shipping_carriers.webhook.received', label: 'Shipping Webhook Received', category: 'system', excludeFromTriggers: true },
|
|
10
|
+
{ id: 'shipping_carriers.webhook.failed', label: 'Shipping Webhook Failed', category: 'system', excludeFromTriggers: true },
|
|
11
|
+
] as const
|
|
12
|
+
|
|
13
|
+
export const eventsConfig = createModuleEvents({ moduleId: 'shipping_carriers', events })
|
|
14
|
+
export const emitShippingEvent = eventsConfig.emit
|
|
15
|
+
export type ShippingEventId = typeof events[number]['id']
|
|
16
|
+
export default eventsConfig
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shipping_carriers.action.createShipment": "Sendung erstellen",
|
|
3
|
+
"shipping_carriers.column.shippingStatus": "Versandstatus",
|
|
4
|
+
"shipping_carriers.column.trackingStatus": "Tracking-Status",
|
|
5
|
+
"shipping_carriers.feature.manage": "Versanddienstleister-Vorgaenge verwalten",
|
|
6
|
+
"shipping_carriers.feature.view": "Sendungen der Versanddienstleister anzeigen"
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shipping_carriers.action.createShipment": "Create shipment",
|
|
3
|
+
"shipping_carriers.column.shippingStatus": "Shipping status",
|
|
4
|
+
"shipping_carriers.column.trackingStatus": "Tracking status",
|
|
5
|
+
"shipping_carriers.feature.manage": "Manage shipping carrier operations",
|
|
6
|
+
"shipping_carriers.feature.view": "View shipping carrier shipments"
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
'shipping_carriers.feature.view': 'View shipping carrier shipments',
|
|
3
|
+
'shipping_carriers.feature.manage': 'Manage shipping carrier operations',
|
|
4
|
+
'shipping_carriers.column.trackingStatus': 'Tracking status',
|
|
5
|
+
'shipping_carriers.column.shippingStatus': 'Shipping status',
|
|
6
|
+
'shipping_carriers.action.createShipment': 'Create shipment',
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shipping_carriers.action.createShipment": "Crear envio",
|
|
3
|
+
"shipping_carriers.column.shippingStatus": "Estado del envio",
|
|
4
|
+
"shipping_carriers.column.trackingStatus": "Estado del seguimiento",
|
|
5
|
+
"shipping_carriers.feature.manage": "Gestionar operaciones de transportistas",
|
|
6
|
+
"shipping_carriers.feature.view": "Ver envios de transportistas"
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shipping_carriers.action.createShipment": "Utworz przesylke",
|
|
3
|
+
"shipping_carriers.column.shippingStatus": "Status wysylki",
|
|
4
|
+
"shipping_carriers.column.trackingStatus": "Status sledzenia",
|
|
5
|
+
"shipping_carriers.feature.manage": "Zarzadzanie operacjami przewoznikow",
|
|
6
|
+
"shipping_carriers.feature.view": "Podglad przesylek przewoznikow"
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
'shipping_carriers.feature.view': 'Podgląd przesyłek przewoźników',
|
|
3
|
+
'shipping_carriers.feature.manage': 'Zarządzanie operacjami przewoźników',
|
|
4
|
+
'shipping_carriers.column.trackingStatus': 'Status śledzenia',
|
|
5
|
+
'shipping_carriers.column.shippingStatus': 'Status wysyłki',
|
|
6
|
+
'shipping_carriers.action.createShipment': 'Utwórz przesyłkę',
|
|
7
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ShippingAdapter } from './adapter'
|
|
2
|
+
|
|
3
|
+
const SHIPPING_ADAPTER_REGISTRY_KEY = Symbol.for('@open-mercato/shipping-carriers/adapter-registry')
|
|
4
|
+
|
|
5
|
+
type GlobalWithShippingRegistry = typeof globalThis & {
|
|
6
|
+
[SHIPPING_ADAPTER_REGISTRY_KEY]?: Map<string, ShippingAdapter>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function getAdapterRegistry(): Map<string, ShippingAdapter> {
|
|
10
|
+
const globalScope = globalThis as GlobalWithShippingRegistry
|
|
11
|
+
if (!globalScope[SHIPPING_ADAPTER_REGISTRY_KEY]) {
|
|
12
|
+
globalScope[SHIPPING_ADAPTER_REGISTRY_KEY] = new Map<string, ShippingAdapter>()
|
|
13
|
+
}
|
|
14
|
+
return globalScope[SHIPPING_ADAPTER_REGISTRY_KEY]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function registerShippingAdapter(adapter: ShippingAdapter): () => void {
|
|
18
|
+
const adapterRegistry = getAdapterRegistry()
|
|
19
|
+
adapterRegistry.set(adapter.providerKey, adapter)
|
|
20
|
+
return () => adapterRegistry.delete(adapter.providerKey)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getShippingAdapter(providerKey: string): ShippingAdapter | undefined {
|
|
24
|
+
return getAdapterRegistry().get(providerKey)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function listShippingAdapters(): ShippingAdapter[] {
|
|
28
|
+
return Array.from(getAdapterRegistry().values())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function clearShippingAdapters(): void {
|
|
32
|
+
getAdapterRegistry().clear()
|
|
33
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export type UnifiedShipmentStatus =
|
|
2
|
+
| 'label_created'
|
|
3
|
+
| 'picked_up'
|
|
4
|
+
| 'in_transit'
|
|
5
|
+
| 'out_for_delivery'
|
|
6
|
+
| 'delivered'
|
|
7
|
+
| 'failed_delivery'
|
|
8
|
+
| 'returned'
|
|
9
|
+
| 'cancelled'
|
|
10
|
+
| 'unknown'
|
|
11
|
+
|
|
12
|
+
export type Address = {
|
|
13
|
+
countryCode: string
|
|
14
|
+
postalCode: string
|
|
15
|
+
city: string
|
|
16
|
+
line1: string
|
|
17
|
+
line2?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type PackageInfo = {
|
|
21
|
+
weightKg: number
|
|
22
|
+
lengthCm: number
|
|
23
|
+
widthCm: number
|
|
24
|
+
heightCm: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type ShippingRate = {
|
|
28
|
+
serviceCode: string
|
|
29
|
+
serviceName: string
|
|
30
|
+
amount: number
|
|
31
|
+
currencyCode: string
|
|
32
|
+
estimatedDays?: number
|
|
33
|
+
guaranteedDelivery?: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type CreateShipmentInput = {
|
|
37
|
+
orderId: string
|
|
38
|
+
origin: Address
|
|
39
|
+
destination: Address
|
|
40
|
+
packages: PackageInfo[]
|
|
41
|
+
serviceCode: string
|
|
42
|
+
credentials: Record<string, unknown>
|
|
43
|
+
labelFormat?: 'pdf' | 'zpl' | 'png'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type CreateShipmentResult = {
|
|
47
|
+
shipmentId: string
|
|
48
|
+
trackingNumber: string
|
|
49
|
+
labelUrl?: string
|
|
50
|
+
labelData?: string
|
|
51
|
+
estimatedDelivery?: Date
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type TrackingResult = {
|
|
55
|
+
trackingNumber: string
|
|
56
|
+
status: UnifiedShipmentStatus
|
|
57
|
+
events: Array<{ status: UnifiedShipmentStatus; occurredAt: string; location?: string }>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type ShippingWebhookEvent = {
|
|
61
|
+
eventType: string
|
|
62
|
+
eventId: string
|
|
63
|
+
idempotencyKey: string
|
|
64
|
+
data: Record<string, unknown>
|
|
65
|
+
timestamp: Date
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface ShippingAdapter {
|
|
69
|
+
readonly providerKey: string
|
|
70
|
+
calculateRates(input: {
|
|
71
|
+
origin: Address
|
|
72
|
+
destination: Address
|
|
73
|
+
packages: PackageInfo[]
|
|
74
|
+
credentials: Record<string, unknown>
|
|
75
|
+
}): Promise<ShippingRate[]>
|
|
76
|
+
createShipment(input: CreateShipmentInput): Promise<CreateShipmentResult>
|
|
77
|
+
getTracking(input: {
|
|
78
|
+
shipmentId?: string
|
|
79
|
+
trackingNumber?: string
|
|
80
|
+
credentials: Record<string, unknown>
|
|
81
|
+
}): Promise<TrackingResult>
|
|
82
|
+
cancelShipment(input: {
|
|
83
|
+
shipmentId: string
|
|
84
|
+
reason?: string
|
|
85
|
+
credentials: Record<string, unknown>
|
|
86
|
+
}): Promise<{ status: UnifiedShipmentStatus }>
|
|
87
|
+
verifyWebhook(input: {
|
|
88
|
+
rawBody: string | Buffer
|
|
89
|
+
headers: Record<string, string | string[] | undefined>
|
|
90
|
+
credentials: Record<string, unknown>
|
|
91
|
+
}): Promise<ShippingWebhookEvent>
|
|
92
|
+
mapStatus(carrierStatus: string): UnifiedShipmentStatus
|
|
93
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createQueue, type Queue } from '@open-mercato/queue'
|
|
2
|
+
import { getRedisUrl } from '@open-mercato/shared/lib/redis/connection'
|
|
3
|
+
|
|
4
|
+
const queues = new Map<string, Queue<Record<string, unknown>>>()
|
|
5
|
+
|
|
6
|
+
export function getShippingCarrierQueue(queueName: string): Queue<Record<string, unknown>> {
|
|
7
|
+
const existing = queues.get(queueName)
|
|
8
|
+
if (existing) return existing
|
|
9
|
+
|
|
10
|
+
const created = process.env.QUEUE_STRATEGY === 'async'
|
|
11
|
+
? createQueue<Record<string, unknown>>(queueName, 'async', {
|
|
12
|
+
connection: { url: getRedisUrl('QUEUE') },
|
|
13
|
+
concurrency: Math.max(1, Number.parseInt(process.env.SHIPPING_CARRIER_QUEUE_CONCURRENCY ?? '5', 10) || 5),
|
|
14
|
+
})
|
|
15
|
+
: createQueue<Record<string, unknown>>(queueName, 'local')
|
|
16
|
+
|
|
17
|
+
queues.set(queueName, created)
|
|
18
|
+
return created
|
|
19
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
3
|
+
import type { CredentialsService } from '../../integrations/lib/credentials-service'
|
|
4
|
+
import { CarrierShipment } from '../data/entities'
|
|
5
|
+
import { emitShippingEvent } from '../events'
|
|
6
|
+
import { getShippingAdapter } from './adapter-registry'
|
|
7
|
+
|
|
8
|
+
export function createShippingCarrierService(deps: {
|
|
9
|
+
em: EntityManager
|
|
10
|
+
integrationCredentialsService: CredentialsService
|
|
11
|
+
}) {
|
|
12
|
+
const { em, integrationCredentialsService } = deps
|
|
13
|
+
|
|
14
|
+
async function findShipmentOrThrow(
|
|
15
|
+
shipmentId: string,
|
|
16
|
+
scope: { organizationId: string; tenantId: string },
|
|
17
|
+
): Promise<CarrierShipment> {
|
|
18
|
+
const shipment = await findOneWithDecryption(
|
|
19
|
+
em,
|
|
20
|
+
CarrierShipment,
|
|
21
|
+
{
|
|
22
|
+
id: shipmentId,
|
|
23
|
+
organizationId: scope.organizationId,
|
|
24
|
+
tenantId: scope.tenantId,
|
|
25
|
+
deletedAt: null,
|
|
26
|
+
},
|
|
27
|
+
undefined,
|
|
28
|
+
scope,
|
|
29
|
+
)
|
|
30
|
+
if (!shipment) {
|
|
31
|
+
throw new Error('Shipment not found')
|
|
32
|
+
}
|
|
33
|
+
return shipment
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function resolveAdapter(providerKey: string, scope: { organizationId: string; tenantId: string }) {
|
|
37
|
+
const adapter = getShippingAdapter(providerKey)
|
|
38
|
+
if (!adapter) throw new Error(`No shipping adapter registered for provider: ${providerKey}`)
|
|
39
|
+
const credentials = await integrationCredentialsService.resolve(`carrier_${providerKey}`, scope) ?? {}
|
|
40
|
+
return { adapter, credentials }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
async calculateRates(input: {
|
|
45
|
+
providerKey: string
|
|
46
|
+
origin: { countryCode: string; postalCode: string; city: string; line1: string; line2?: string }
|
|
47
|
+
destination: { countryCode: string; postalCode: string; city: string; line1: string; line2?: string }
|
|
48
|
+
packages: Array<{ weightKg: number; lengthCm: number; widthCm: number; heightCm: number }>
|
|
49
|
+
organizationId: string
|
|
50
|
+
tenantId: string
|
|
51
|
+
}) {
|
|
52
|
+
const { adapter, credentials } = await resolveAdapter(input.providerKey, {
|
|
53
|
+
organizationId: input.organizationId,
|
|
54
|
+
tenantId: input.tenantId,
|
|
55
|
+
})
|
|
56
|
+
return adapter.calculateRates({
|
|
57
|
+
origin: input.origin,
|
|
58
|
+
destination: input.destination,
|
|
59
|
+
packages: input.packages,
|
|
60
|
+
credentials,
|
|
61
|
+
})
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
async createShipment(input: {
|
|
65
|
+
providerKey: string
|
|
66
|
+
orderId: string
|
|
67
|
+
origin: { countryCode: string; postalCode: string; city: string; line1: string; line2?: string }
|
|
68
|
+
destination: { countryCode: string; postalCode: string; city: string; line1: string; line2?: string }
|
|
69
|
+
packages: Array<{ weightKg: number; lengthCm: number; widthCm: number; heightCm: number }>
|
|
70
|
+
serviceCode: string
|
|
71
|
+
labelFormat?: 'pdf' | 'zpl' | 'png'
|
|
72
|
+
organizationId: string
|
|
73
|
+
tenantId: string
|
|
74
|
+
}) {
|
|
75
|
+
const { adapter, credentials } = await resolveAdapter(input.providerKey, {
|
|
76
|
+
organizationId: input.organizationId,
|
|
77
|
+
tenantId: input.tenantId,
|
|
78
|
+
})
|
|
79
|
+
const created = await adapter.createShipment({
|
|
80
|
+
orderId: input.orderId,
|
|
81
|
+
origin: input.origin,
|
|
82
|
+
destination: input.destination,
|
|
83
|
+
packages: input.packages,
|
|
84
|
+
serviceCode: input.serviceCode,
|
|
85
|
+
credentials,
|
|
86
|
+
labelFormat: input.labelFormat,
|
|
87
|
+
})
|
|
88
|
+
const shipment = em.create(CarrierShipment, {
|
|
89
|
+
orderId: input.orderId,
|
|
90
|
+
providerKey: input.providerKey,
|
|
91
|
+
carrierShipmentId: created.shipmentId,
|
|
92
|
+
trackingNumber: created.trackingNumber,
|
|
93
|
+
unifiedStatus: 'label_created',
|
|
94
|
+
labelUrl: created.labelUrl ?? null,
|
|
95
|
+
labelData: created.labelData ?? null,
|
|
96
|
+
organizationId: input.organizationId,
|
|
97
|
+
tenantId: input.tenantId,
|
|
98
|
+
})
|
|
99
|
+
await em.persistAndFlush(shipment)
|
|
100
|
+
await emitShippingEvent('shipping_carriers.shipment.created', {
|
|
101
|
+
shipmentId: shipment.id,
|
|
102
|
+
orderId: input.orderId,
|
|
103
|
+
providerKey: input.providerKey,
|
|
104
|
+
trackingNumber: created.trackingNumber,
|
|
105
|
+
organizationId: input.organizationId,
|
|
106
|
+
tenantId: input.tenantId,
|
|
107
|
+
})
|
|
108
|
+
return shipment
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
async getTracking(input: {
|
|
112
|
+
providerKey: string
|
|
113
|
+
shipmentId?: string
|
|
114
|
+
trackingNumber?: string
|
|
115
|
+
organizationId: string
|
|
116
|
+
tenantId: string
|
|
117
|
+
}) {
|
|
118
|
+
const { adapter, credentials } = await resolveAdapter(input.providerKey, {
|
|
119
|
+
organizationId: input.organizationId,
|
|
120
|
+
tenantId: input.tenantId,
|
|
121
|
+
})
|
|
122
|
+
const shipment = input.shipmentId
|
|
123
|
+
? await findOneWithDecryption(
|
|
124
|
+
em,
|
|
125
|
+
CarrierShipment,
|
|
126
|
+
{
|
|
127
|
+
id: input.shipmentId,
|
|
128
|
+
organizationId: input.organizationId,
|
|
129
|
+
tenantId: input.tenantId,
|
|
130
|
+
deletedAt: null,
|
|
131
|
+
},
|
|
132
|
+
undefined,
|
|
133
|
+
{
|
|
134
|
+
organizationId: input.organizationId,
|
|
135
|
+
tenantId: input.tenantId,
|
|
136
|
+
},
|
|
137
|
+
)
|
|
138
|
+
: null
|
|
139
|
+
const tracking = await adapter.getTracking({
|
|
140
|
+
shipmentId: shipment?.carrierShipmentId ?? input.shipmentId,
|
|
141
|
+
trackingNumber: input.trackingNumber,
|
|
142
|
+
credentials,
|
|
143
|
+
})
|
|
144
|
+
if (shipment) {
|
|
145
|
+
shipment.unifiedStatus = tracking.status
|
|
146
|
+
shipment.trackingEvents = tracking.events
|
|
147
|
+
shipment.lastPolledAt = new Date()
|
|
148
|
+
await em.flush()
|
|
149
|
+
}
|
|
150
|
+
return tracking
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
async cancelShipment(input: {
|
|
154
|
+
providerKey: string
|
|
155
|
+
shipmentId: string
|
|
156
|
+
reason?: string
|
|
157
|
+
organizationId: string
|
|
158
|
+
tenantId: string
|
|
159
|
+
}) {
|
|
160
|
+
const scope = { organizationId: input.organizationId, tenantId: input.tenantId }
|
|
161
|
+
const shipment = await findShipmentOrThrow(input.shipmentId, scope)
|
|
162
|
+
const { adapter, credentials } = await resolveAdapter(input.providerKey, {
|
|
163
|
+
organizationId: input.organizationId,
|
|
164
|
+
tenantId: input.tenantId,
|
|
165
|
+
})
|
|
166
|
+
const result = await adapter.cancelShipment({
|
|
167
|
+
shipmentId: shipment.carrierShipmentId,
|
|
168
|
+
reason: input.reason,
|
|
169
|
+
credentials,
|
|
170
|
+
})
|
|
171
|
+
shipment.unifiedStatus = result.status
|
|
172
|
+
await em.flush()
|
|
173
|
+
await emitShippingEvent('shipping_carriers.shipment.cancelled', {
|
|
174
|
+
shipmentId: shipment.id,
|
|
175
|
+
providerKey: input.providerKey,
|
|
176
|
+
organizationId: input.organizationId,
|
|
177
|
+
tenantId: input.tenantId,
|
|
178
|
+
})
|
|
179
|
+
return result
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
async findShipmentByCarrierId(
|
|
183
|
+
providerKey: string,
|
|
184
|
+
carrierShipmentId: string,
|
|
185
|
+
scope: { organizationId: string; tenantId: string },
|
|
186
|
+
) {
|
|
187
|
+
return findOneWithDecryption(
|
|
188
|
+
em,
|
|
189
|
+
CarrierShipment,
|
|
190
|
+
{
|
|
191
|
+
providerKey,
|
|
192
|
+
carrierShipmentId,
|
|
193
|
+
organizationId: scope.organizationId,
|
|
194
|
+
tenantId: scope.tenantId,
|
|
195
|
+
deletedAt: null,
|
|
196
|
+
},
|
|
197
|
+
undefined,
|
|
198
|
+
scope,
|
|
199
|
+
)
|
|
200
|
+
},
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export type ShippingCarrierService = ReturnType<typeof createShippingCarrierService>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { UnifiedShipmentStatus } from './adapter'
|
|
2
|
+
import type { CarrierShipment } from '../data/entities'
|
|
3
|
+
import type { ShippingEventId } from '../events'
|
|
4
|
+
|
|
5
|
+
const VALID_SHIPPING_TRANSITIONS: Record<string, UnifiedShipmentStatus[]> = {
|
|
6
|
+
label_created: ['picked_up', 'in_transit', 'cancelled'],
|
|
7
|
+
picked_up: ['in_transit', 'cancelled'],
|
|
8
|
+
in_transit: ['out_for_delivery', 'delivered', 'returned', 'failed_delivery'],
|
|
9
|
+
out_for_delivery: ['delivered', 'returned', 'failed_delivery'],
|
|
10
|
+
failed_delivery: ['in_transit', 'out_for_delivery', 'delivered', 'returned', 'cancelled'],
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const TERMINAL_SHIPPING_STATUSES: Set<UnifiedShipmentStatus> = new Set([
|
|
14
|
+
'delivered',
|
|
15
|
+
'returned',
|
|
16
|
+
'cancelled',
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
export function isValidShippingTransition(from: UnifiedShipmentStatus, to: UnifiedShipmentStatus): boolean {
|
|
20
|
+
if (from === to) return false
|
|
21
|
+
const allowed = VALID_SHIPPING_TRANSITIONS[from]
|
|
22
|
+
if (!allowed) return false
|
|
23
|
+
return allowed.includes(to)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function syncShipmentStatus(shipment: CarrierShipment, newStatus: UnifiedShipmentStatus): boolean {
|
|
27
|
+
const currentStatus = shipment.unifiedStatus as UnifiedShipmentStatus
|
|
28
|
+
if (!isValidShippingTransition(currentStatus, newStatus)) return false
|
|
29
|
+
shipment.unifiedStatus = newStatus
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getTerminalShippingEvent(status: UnifiedShipmentStatus): ShippingEventId | null {
|
|
34
|
+
if (status === 'delivered') return 'shipping_carriers.shipment.delivered'
|
|
35
|
+
if (status === 'returned') return 'shipping_carriers.shipment.returned'
|
|
36
|
+
if (status === 'cancelled') return 'shipping_carriers.shipment.cancelled'
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations'
|
|
2
|
+
|
|
3
|
+
export class Migration20260305170000 extends Migration {
|
|
4
|
+
override async up(): Promise<void> {
|
|
5
|
+
this.addSql(`create table "carrier_shipments" ("id" uuid not null default gen_random_uuid(), "order_id" uuid not null, "provider_key" text not null, "carrier_shipment_id" text not null, "tracking_number" text not null, "unified_status" text not null default 'label_created', "carrier_status" text null, "label_url" text null, "label_data" text null, "tracking_events" jsonb null, "organization_id" uuid not null, "tenant_id" uuid not null, "last_webhook_at" timestamptz null, "last_polled_at" timestamptz null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, constraint "carrier_shipments_pkey" primary key ("id"));`)
|
|
6
|
+
this.addSql(`create index "carrier_shipments_organization_id_tenant_id_unif_b5ab4_index" on "carrier_shipments" ("organization_id", "tenant_id", "unified_status");`)
|
|
7
|
+
this.addSql(`create index "carrier_shipments_provider_key_carrier_shipment_i_f9f17_index" on "carrier_shipments" ("provider_key", "carrier_shipment_id", "organization_id");`)
|
|
8
|
+
this.addSql(`create index "carrier_shipments_order_id_organization_id_tenant_id_index" on "carrier_shipments" ("order_id", "organization_id", "tenant_id");`)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
override async down(): Promise<void> {
|
|
12
|
+
this.addSql(`drop table if exists "carrier_shipments";`)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
|
|
2
|
+
|
|
3
|
+
export const setup: ModuleSetupConfig = {
|
|
4
|
+
defaultRoleFeatures: {
|
|
5
|
+
superadmin: ['shipping_carriers.view', 'shipping_carriers.manage'],
|
|
6
|
+
admin: ['shipping_carriers.view', 'shipping_carriers.manage'],
|
|
7
|
+
employee: ['shipping_carriers.view'],
|
|
8
|
+
},
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default setup
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { InjectionRowActionWidget } from '@open-mercato/shared/modules/widgets/injection'
|
|
2
|
+
|
|
3
|
+
const widget: InjectionRowActionWidget = {
|
|
4
|
+
metadata: {
|
|
5
|
+
id: 'shipping_carriers.injection.create-shipment-button',
|
|
6
|
+
priority: 30,
|
|
7
|
+
},
|
|
8
|
+
rowActions: [
|
|
9
|
+
{
|
|
10
|
+
id: 'create_shipment',
|
|
11
|
+
label: 'shipping_carriers.action.createShipment',
|
|
12
|
+
icon: 'Truck',
|
|
13
|
+
onSelect: (row: unknown, context: unknown) => {
|
|
14
|
+
const ctx = context as { navigate?: (path: string) => void }
|
|
15
|
+
const order = row as { id?: string }
|
|
16
|
+
if (ctx.navigate && order.id) {
|
|
17
|
+
ctx.navigate(`/backend/shipping-carriers/create?orderId=${order.id}`)
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default widget
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { InjectionColumnWidget } from '@open-mercato/shared/modules/widgets/injection'
|
|
2
|
+
|
|
3
|
+
const widget: InjectionColumnWidget = {
|
|
4
|
+
metadata: {
|
|
5
|
+
id: 'shipping_carriers.injection.tracking-column',
|
|
6
|
+
priority: 40,
|
|
7
|
+
},
|
|
8
|
+
columns: [
|
|
9
|
+
{
|
|
10
|
+
id: 'carrier_tracking_status',
|
|
11
|
+
header: 'shipping_carriers.column.trackingStatus',
|
|
12
|
+
accessorKey: '_carrier.status',
|
|
13
|
+
sortable: false,
|
|
14
|
+
cell: ({ getValue }) => {
|
|
15
|
+
const value = getValue()
|
|
16
|
+
return typeof value === 'string' && value.length > 0 ? value : 'unknown'
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default widget
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { InjectionColumnWidget } from '@open-mercato/shared/modules/widgets/injection'
|
|
2
|
+
|
|
3
|
+
const SHIPPING_STATUS_COLORS: Record<string, string> = {
|
|
4
|
+
pending: 'bg-gray-100 text-gray-700',
|
|
5
|
+
label_created: 'bg-slate-100 text-slate-700',
|
|
6
|
+
picked_up: 'bg-sky-100 text-sky-700',
|
|
7
|
+
in_transit: 'bg-blue-100 text-blue-700',
|
|
8
|
+
out_for_delivery: 'bg-indigo-100 text-indigo-700',
|
|
9
|
+
delivered: 'bg-green-100 text-green-700',
|
|
10
|
+
returned: 'bg-amber-100 text-amber-700',
|
|
11
|
+
cancelled: 'bg-red-100 text-red-700',
|
|
12
|
+
failed_delivery: 'bg-orange-100 text-orange-700',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function formatShippingStatusLabel(value: string): string {
|
|
16
|
+
return value.replace(/_/g, ' ')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const widget: InjectionColumnWidget = {
|
|
20
|
+
metadata: {
|
|
21
|
+
id: 'shipping_carriers.injection.tracking-status-badge',
|
|
22
|
+
priority: 45,
|
|
23
|
+
},
|
|
24
|
+
columns: [
|
|
25
|
+
{
|
|
26
|
+
id: 'carrier_status_badge',
|
|
27
|
+
header: 'shipping_carriers.column.shippingStatus',
|
|
28
|
+
accessorKey: '_carrier.status',
|
|
29
|
+
sortable: false,
|
|
30
|
+
cell: ({ getValue }) => {
|
|
31
|
+
const value = getValue()
|
|
32
|
+
if (typeof value !== 'string' || value.length === 0) return null
|
|
33
|
+
const colors = SHIPPING_STATUS_COLORS[value] ?? 'bg-gray-100 text-gray-700'
|
|
34
|
+
return (
|
|
35
|
+
<span className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${colors}`}>
|
|
36
|
+
{formatShippingStatusLabel(value)}
|
|
37
|
+
</span>
|
|
38
|
+
)
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default widget
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ModuleInjectionTable } from '@open-mercato/shared/modules/widgets/injection'
|
|
2
|
+
|
|
3
|
+
export const injectionTable: ModuleInjectionTable = {
|
|
4
|
+
'data-table:sales.shipments:columns': [
|
|
5
|
+
{
|
|
6
|
+
widgetId: 'shipping_carriers.injection.tracking-column',
|
|
7
|
+
priority: 40,
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
widgetId: 'shipping_carriers.injection.tracking-status-badge',
|
|
11
|
+
priority: 45,
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
'data-table:sales.orders:row-actions': [
|
|
15
|
+
{
|
|
16
|
+
widgetId: 'shipping_carriers.injection.create-shipment-button',
|
|
17
|
+
priority: 30,
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default injectionTable
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { JobContext, QueuedJob, WorkerMeta } from '@open-mercato/queue'
|
|
2
|
+
import type { ShippingCarrierService } from '../lib/shipping-service'
|
|
3
|
+
|
|
4
|
+
type PollerJobPayload = {
|
|
5
|
+
providerKey: string
|
|
6
|
+
shipmentIds: string[]
|
|
7
|
+
scope: {
|
|
8
|
+
organizationId: string
|
|
9
|
+
tenantId: string
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type HandlerContext = JobContext & {
|
|
14
|
+
resolve: <T = unknown>(name: string) => T
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const metadata: WorkerMeta = {
|
|
18
|
+
queue: 'shipping-carriers-status-poller',
|
|
19
|
+
id: 'shipping-carriers:status-poller',
|
|
20
|
+
concurrency: 2,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default async function handle(job: QueuedJob<PollerJobPayload>, ctx: HandlerContext): Promise<void> {
|
|
24
|
+
const service = ctx.resolve<ShippingCarrierService>('shippingCarrierService')
|
|
25
|
+
for (const shipmentId of job.payload.shipmentIds) {
|
|
26
|
+
await service.getTracking({
|
|
27
|
+
providerKey: job.payload.providerKey,
|
|
28
|
+
shipmentId,
|
|
29
|
+
organizationId: job.payload.scope.organizationId,
|
|
30
|
+
tenantId: job.payload.scope.tenantId,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
}
|