@open-mercato/core 0.6.6-develop.6205.1.109e4b6a84 → 0.6.6-develop.6227.1.2695efff30
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 +1 -1
- package/dist/modules/currencies/backend/currencies/[id]/page.js +33 -8
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +63 -27
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +35 -14
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js +104 -41
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js +57 -8
- package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +5 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +30 -14
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +29 -19
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +166 -64
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
- package/dist/modules/customers/components/AddressFormatSettings.js +31 -16
- package/dist/modules/customers/components/AddressFormatSettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySettings.js +57 -31
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/PipelineSettings.js +156 -76
- package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js +10 -4
- package/dist/modules/customers/components/calendar/AgendaList.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +18 -2
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
- package/dist/modules/customers/components/calendar/MonthGrid.js +5 -2
- package/dist/modules/customers/components/calendar/MonthGrid.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +6 -0
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/RelatedToField.js +2 -0
- package/dist/modules/customers/components/calendar/editor/RelatedToField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/ScheduleSection.js +4 -1
- package/dist/modules/customers/components/calendar/editor/ScheduleSection.js.map +2 -2
- package/dist/modules/customers/lib/calendar/labels.js +33 -0
- package/dist/modules/customers/lib/calendar/labels.js.map +7 -0
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +32 -11
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/data_sync/api/mappings/[id]/route.js +59 -0
- package/dist/modules/data_sync/api/mappings/[id]/route.js.map +2 -2
- package/dist/modules/data_sync/api/mappings/route.js +44 -0
- package/dist/modules/data_sync/api/mappings/route.js.map +2 -2
- package/dist/modules/data_sync/api/run.js +31 -0
- package/dist/modules/data_sync/api/run.js.map +2 -2
- package/dist/modules/data_sync/api/runs/[id]/cancel.js +31 -0
- package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
- package/dist/modules/data_sync/api/runs/[id]/retry.js +31 -0
- package/dist/modules/data_sync/api/runs/[id]/retry.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/[id]/route.js +59 -3
- package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/route.js +33 -4
- package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
- package/dist/modules/directory/api/organization-branding/route.js +54 -2
- package/dist/modules/directory/api/organization-branding/route.js.map +2 -2
- package/dist/modules/directory/backend/directory/branding/page.js +15 -9
- package/dist/modules/directory/backend/directory/branding/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js +28 -9
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +29 -13
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/entities/api/definitions.batch.js +15 -0
- package/dist/modules/entities/api/definitions.batch.js.map +2 -2
- package/dist/modules/entities/api/definitions.js +26 -0
- package/dist/modules/entities/api/definitions.js.map +2 -2
- package/dist/modules/entities/api/definitions.mutation-guard.js +57 -0
- package/dist/modules/entities/api/definitions.mutation-guard.js.map +7 -0
- package/dist/modules/entities/api/definitions.restore.js +15 -0
- package/dist/modules/entities/api/definitions.restore.js.map +2 -2
- package/dist/modules/entities/api/entities.js +31 -3
- package/dist/modules/entities/api/entities.js.map +2 -2
- package/dist/modules/entities/api/records.js +18 -0
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +28 -10
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/feature_toggles/api/overrides/route.js +38 -1
- package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/emails/[id]/route.js +30 -0
- package/dist/modules/inbox_ops/api/emails/[id]/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/[id]/accept-all/route.js +30 -0
- package/dist/modules/inbox_ops/api/proposals/[id]/accept-all/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js +31 -0
- package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/[id]/categorize/route.js +31 -0
- package/dist/modules/inbox_ops/api/proposals/[id]/categorize/route.js.map +2 -2
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js +68 -39
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js.map +2 -2
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +14 -4
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +2 -2
- package/dist/modules/payment_gateways/api/cancel/route.js +37 -0
- package/dist/modules/payment_gateways/api/cancel/route.js.map +2 -2
- package/dist/modules/payment_gateways/api/capture/route.js +37 -0
- package/dist/modules/payment_gateways/api/capture/route.js.map +2 -2
- package/dist/modules/payment_gateways/api/guards.js +31 -0
- package/dist/modules/payment_gateways/api/guards.js.map +7 -0
- package/dist/modules/payment_gateways/api/refund/route.js +37 -0
- package/dist/modules/payment_gateways/api/refund/route.js.map +2 -2
- package/dist/modules/payment_gateways/api/sessions/route.js +37 -0
- package/dist/modules/payment_gateways/api/sessions/route.js.map +2 -2
- package/dist/modules/planner/api/availability-date-specific.js +11 -1
- package/dist/modules/planner/api/availability-date-specific.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +20 -3
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/planner/commands/availability-date-specific.js +16 -0
- package/dist/modules/planner/commands/availability-date-specific.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +109 -40
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/query_index/api/purge.js +35 -3
- package/dist/modules/query_index/api/purge.js.map +2 -2
- package/dist/modules/query_index/api/reindex.js +41 -3
- package/dist/modules/query_index/api/reindex.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +57 -24
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/shipping_carriers/api/shipments/route.js +31 -0
- package/dist/modules/shipping_carriers/api/shipments/route.js.map +2 -2
- package/dist/modules/shipping_carriers/api/tracking/refresh/route.js +55 -0
- package/dist/modules/shipping_carriers/api/tracking/refresh/route.js.map +7 -0
- package/dist/modules/shipping_carriers/data/validators.js +6 -1
- package/dist/modules/shipping_carriers/data/validators.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/shipment-wizard/hooks/useShipmentWizard.js +28 -8
- package/dist/modules/shipping_carriers/lib/shipment-wizard/hooks/useShipmentWizard.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/shipping-service.js +37 -7
- package/dist/modules/shipping_carriers/lib/shipping-service.js.map +2 -2
- package/dist/modules/shipping_carriers/workers/status-poller.js +1 -1
- package/dist/modules/shipping_carriers/workers/status-poller.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +49 -20
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +40 -10
- package/src/modules/currencies/backend/currencies/page.tsx +68 -29
- package/src/modules/currencies/backend/exchange-rates/page.tsx +40 -15
- package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +110 -41
- package/src/modules/customer_accounts/api/admin/roles/[id]/acl.ts +69 -7
- package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +16 -8
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +32 -14
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +32 -20
- package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +171 -64
- package/src/modules/customers/components/AddressFormatSettings.tsx +39 -19
- package/src/modules/customers/components/DictionarySettings.tsx +63 -29
- package/src/modules/customers/components/PipelineSettings.tsx +165 -80
- package/src/modules/customers/components/calendar/AgendaList.tsx +13 -8
- package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +16 -2
- package/src/modules/customers/components/calendar/MonthGrid.tsx +5 -2
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +6 -0
- package/src/modules/customers/components/calendar/editor/RelatedToField.tsx +2 -0
- package/src/modules/customers/components/calendar/editor/ScheduleSection.tsx +7 -0
- package/src/modules/customers/i18n/de.json +11 -7
- package/src/modules/customers/i18n/en.json +6 -2
- package/src/modules/customers/i18n/es.json +11 -7
- package/src/modules/customers/i18n/pl.json +11 -7
- package/src/modules/customers/lib/calendar/labels.ts +42 -0
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +39 -11
- package/src/modules/data_sync/api/mappings/[id]/route.ts +63 -0
- package/src/modules/data_sync/api/mappings/route.ts +48 -0
- package/src/modules/data_sync/api/run.ts +33 -0
- package/src/modules/data_sync/api/runs/[id]/cancel.ts +34 -0
- package/src/modules/data_sync/api/runs/[id]/retry.ts +33 -0
- package/src/modules/data_sync/api/schedules/[id]/route.ts +64 -2
- package/src/modules/data_sync/api/schedules/route.ts +36 -4
- package/src/modules/directory/api/organization-branding/route.ts +61 -0
- package/src/modules/directory/backend/directory/branding/page.tsx +16 -10
- package/src/modules/directory/backend/directory/organizations/page.tsx +35 -8
- package/src/modules/directory/backend/directory/tenants/page.tsx +37 -13
- package/src/modules/entities/api/definitions.batch.ts +17 -0
- package/src/modules/entities/api/definitions.mutation-guard.ts +80 -0
- package/src/modules/entities/api/definitions.restore.ts +17 -0
- package/src/modules/entities/api/definitions.ts +30 -0
- package/src/modules/entities/api/entities.ts +35 -3
- package/src/modules/entities/api/records.ts +20 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +33 -10
- package/src/modules/feature_toggles/api/overrides/route.ts +44 -1
- package/src/modules/inbox_ops/api/emails/[id]/route.ts +32 -0
- package/src/modules/inbox_ops/api/proposals/[id]/accept-all/route.ts +32 -0
- package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.ts +33 -0
- package/src/modules/inbox_ops/api/proposals/[id]/categorize/route.ts +33 -0
- package/src/modules/messages/components/message-detail/hooks/useMessageDetailsActions.ts +80 -42
- package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +21 -4
- package/src/modules/payment_gateways/api/cancel/route.ts +39 -0
- package/src/modules/payment_gateways/api/capture/route.ts +39 -0
- package/src/modules/payment_gateways/api/guards.ts +59 -0
- package/src/modules/payment_gateways/api/refund/route.ts +39 -0
- package/src/modules/payment_gateways/api/sessions/route.ts +40 -0
- package/src/modules/planner/api/availability-date-specific.ts +10 -0
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +26 -5
- package/src/modules/planner/commands/availability-date-specific.ts +24 -0
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +122 -41
- package/src/modules/query_index/api/purge.ts +37 -3
- package/src/modules/query_index/api/reindex.ts +43 -3
- package/src/modules/query_index/components/QueryIndexesTable.tsx +66 -24
- package/src/modules/shipping_carriers/api/shipments/route.ts +31 -0
- package/src/modules/shipping_carriers/api/tracking/refresh/route.ts +53 -0
- package/src/modules/shipping_carriers/data/validators.ts +5 -0
- package/src/modules/shipping_carriers/lib/shipment-wizard/hooks/useShipmentWizard.ts +29 -8
- package/src/modules/shipping_carriers/lib/shipping-service.ts +43 -7
- package/src/modules/shipping_carriers/workers/status-poller.ts +1 -1
- package/src/modules/translations/components/TranslationManager.tsx +65 -21
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
3
|
+
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
4
|
+
import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
|
|
5
|
+
import type { ShippingCarrierService } from '../../../lib/shipping-service'
|
|
6
|
+
import { trackingRefreshSchema } from '../../../data/validators'
|
|
7
|
+
import { shippingCarriersTag } from '../../openapi'
|
|
8
|
+
|
|
9
|
+
export const metadata = {
|
|
10
|
+
path: '/shipping-carriers/tracking/refresh',
|
|
11
|
+
POST: { requireAuth: true, requireFeatures: ['shipping_carriers.manage'] },
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function POST(req: Request) {
|
|
15
|
+
const auth = await getAuthFromRequest(req)
|
|
16
|
+
if (!auth?.tenantId || !auth.orgId) {
|
|
17
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
18
|
+
}
|
|
19
|
+
const payload = await readJsonSafe<unknown>(req)
|
|
20
|
+
const parsed = trackingRefreshSchema.safeParse(payload)
|
|
21
|
+
if (!parsed.success) {
|
|
22
|
+
return NextResponse.json({ error: 'Invalid payload', details: parsed.error.flatten() }, { status: 422 })
|
|
23
|
+
}
|
|
24
|
+
const container = await createRequestContainer()
|
|
25
|
+
const service = container.resolve('shippingCarrierService') as ShippingCarrierService
|
|
26
|
+
try {
|
|
27
|
+
const tracking = await service.refreshTracking({
|
|
28
|
+
...parsed.data,
|
|
29
|
+
organizationId: auth.orgId as string,
|
|
30
|
+
tenantId: auth.tenantId,
|
|
31
|
+
})
|
|
32
|
+
return NextResponse.json(tracking)
|
|
33
|
+
} catch (error: unknown) {
|
|
34
|
+
const message = error instanceof Error ? error.message : 'Failed to refresh tracking'
|
|
35
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const openApi = {
|
|
40
|
+
tags: [shippingCarriersTag],
|
|
41
|
+
summary: 'Refresh tracking',
|
|
42
|
+
methods: {
|
|
43
|
+
POST: {
|
|
44
|
+
summary: 'Refresh tracking and persist the latest shipment status',
|
|
45
|
+
tags: [shippingCarriersTag],
|
|
46
|
+
responses: [
|
|
47
|
+
{ status: 200, description: 'Tracking refreshed and shipment status persisted' },
|
|
48
|
+
{ status: 422, description: 'Validation failed' },
|
|
49
|
+
{ status: 502, description: 'Provider upstream error' },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
}
|
|
@@ -55,6 +55,11 @@ export const trackingQuerySchema = z.object({
|
|
|
55
55
|
path: ['shipmentId'],
|
|
56
56
|
})
|
|
57
57
|
|
|
58
|
+
export const trackingRefreshSchema = z.object({
|
|
59
|
+
providerKey: z.string().min(1),
|
|
60
|
+
shipmentId: z.string().uuid(),
|
|
61
|
+
})
|
|
62
|
+
|
|
58
63
|
export const cancelShipmentSchema = z.object({
|
|
59
64
|
providerKey: z.string().min(1),
|
|
60
65
|
shipmentId: z.string().uuid(),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
2
|
import { useRouter, useSearchParams } from 'next/navigation'
|
|
3
3
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
4
|
+
import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
|
|
4
5
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
5
6
|
import {
|
|
6
7
|
fetchProviders,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
createShipment,
|
|
10
11
|
fetchDropOffPoints,
|
|
11
12
|
} from './shipmentApi'
|
|
13
|
+
import type { CreateShipmentParams } from './shipmentApi'
|
|
12
14
|
import type {
|
|
13
15
|
WizardStep,
|
|
14
16
|
Provider,
|
|
@@ -105,6 +107,9 @@ export const useShipmentWizard = (): ShipmentWizard => {
|
|
|
105
107
|
const t = useT()
|
|
106
108
|
const router = useRouter()
|
|
107
109
|
const searchParams = useSearchParams()
|
|
110
|
+
const { runMutation, retryLastMutation } = useGuardedMutation({
|
|
111
|
+
contextId: 'shipping_carriers.shipment.create',
|
|
112
|
+
})
|
|
108
113
|
const orderId = searchParams?.get('orderId') ?? null
|
|
109
114
|
|
|
110
115
|
const [step, setStep] = React.useState<WizardStep>('provider')
|
|
@@ -192,7 +197,7 @@ export const useShipmentWizard = (): ShipmentWizard => {
|
|
|
192
197
|
const handleSubmit = async () => {
|
|
193
198
|
if (!selectedProvider || !selectedRate || !orderId) return
|
|
194
199
|
setIsSubmitting(true)
|
|
195
|
-
const
|
|
200
|
+
const payload: CreateShipmentParams = {
|
|
196
201
|
providerKey: selectedProvider,
|
|
197
202
|
orderId,
|
|
198
203
|
origin,
|
|
@@ -206,13 +211,29 @@ export const useShipmentWizard = (): ShipmentWizard => {
|
|
|
206
211
|
...(receiverContact.email ? { receiverEmail: receiverContact.email } : {}),
|
|
207
212
|
...(targetPoint ? { targetPoint } : {}),
|
|
208
213
|
...(c2cSendingMethod ? { c2cSendingMethod } : {}),
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
const result = await runMutation({
|
|
217
|
+
operation: () => createShipment(payload),
|
|
218
|
+
context: {
|
|
219
|
+
operation: 'create',
|
|
220
|
+
resourceKind: 'shipping_carriers.shipment',
|
|
221
|
+
resourceId: orderId,
|
|
222
|
+
retryLastMutation,
|
|
223
|
+
},
|
|
224
|
+
mutationPayload: payload as unknown as Record<string, unknown>,
|
|
225
|
+
})
|
|
226
|
+
if (result.ok) {
|
|
227
|
+
flash(t('shipping_carriers.create.success', 'Shipment created successfully.'), 'success')
|
|
228
|
+
router.push(backHref)
|
|
229
|
+
} else {
|
|
230
|
+
flash(t('shipping_carriers.create.error.create', result.error), 'error')
|
|
231
|
+
}
|
|
232
|
+
} catch (error) {
|
|
233
|
+
const message = error instanceof Error ? error.message : t('shipping_carriers.create.error.create', 'Failed to create shipment.')
|
|
234
|
+
flash(t('shipping_carriers.create.error.create', message), 'error')
|
|
235
|
+
} finally {
|
|
236
|
+
setIsSubmitting(false)
|
|
216
237
|
}
|
|
217
238
|
}
|
|
218
239
|
|
|
@@ -5,7 +5,13 @@ import { CarrierShipment } from '../data/entities'
|
|
|
5
5
|
import { emitShippingEvent } from '../events'
|
|
6
6
|
import { getShippingAdapter } from './adapter-registry'
|
|
7
7
|
import type { UnifiedShipmentStatus } from './adapter'
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
getTerminalShippingEvent,
|
|
10
|
+
isValidShippingTransition,
|
|
11
|
+
ShipmentCancelNotAllowedError,
|
|
12
|
+
syncShipmentStatus,
|
|
13
|
+
TERMINAL_SHIPPING_STATUSES,
|
|
14
|
+
} from './status-sync'
|
|
9
15
|
|
|
10
16
|
export function createShippingCarrierService(deps: {
|
|
11
17
|
em: EntityManager
|
|
@@ -160,16 +166,46 @@ export function createShippingCarrierService(deps: {
|
|
|
160
166
|
},
|
|
161
167
|
)
|
|
162
168
|
: null
|
|
163
|
-
|
|
169
|
+
return adapter.getTracking({
|
|
164
170
|
shipmentId: shipment?.carrierShipmentId ?? input.shipmentId,
|
|
165
171
|
trackingNumber: input.trackingNumber ?? shipment?.trackingNumber,
|
|
166
172
|
credentials,
|
|
167
173
|
})
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
async refreshTracking(input: {
|
|
177
|
+
providerKey: string
|
|
178
|
+
shipmentId: string
|
|
179
|
+
organizationId: string
|
|
180
|
+
tenantId: string
|
|
181
|
+
}) {
|
|
182
|
+
const scope = { organizationId: input.organizationId, tenantId: input.tenantId }
|
|
183
|
+
const shipment = await findShipmentOrThrow(input.shipmentId, scope)
|
|
184
|
+
const { adapter, credentials } = await resolveAdapter(input.providerKey, scope)
|
|
185
|
+
const tracking = await adapter.getTracking({
|
|
186
|
+
shipmentId: shipment.carrierShipmentId,
|
|
187
|
+
trackingNumber: shipment.trackingNumber,
|
|
188
|
+
credentials,
|
|
189
|
+
})
|
|
190
|
+
const previousStatus = shipment.unifiedStatus
|
|
191
|
+
shipment.trackingEvents = tracking.events
|
|
192
|
+
shipment.lastPolledAt = new Date()
|
|
193
|
+
const transitionApplied = syncShipmentStatus(shipment, tracking.status)
|
|
194
|
+
await em.flush()
|
|
195
|
+
if (transitionApplied) {
|
|
196
|
+
const eventPayload = {
|
|
197
|
+
shipmentId: shipment.id,
|
|
198
|
+
providerKey: input.providerKey,
|
|
199
|
+
previousStatus,
|
|
200
|
+
newStatus: tracking.status,
|
|
201
|
+
organizationId: input.organizationId,
|
|
202
|
+
tenantId: input.tenantId,
|
|
203
|
+
}
|
|
204
|
+
await emitShippingEvent('shipping_carriers.shipment.status_changed', eventPayload)
|
|
205
|
+
if (TERMINAL_SHIPPING_STATUSES.has(tracking.status)) {
|
|
206
|
+
const terminalEvent = getTerminalShippingEvent(tracking.status)
|
|
207
|
+
if (terminalEvent) await emitShippingEvent(terminalEvent, eventPayload)
|
|
208
|
+
}
|
|
173
209
|
}
|
|
174
210
|
return tracking
|
|
175
211
|
},
|
|
@@ -23,7 +23,7 @@ export const metadata: WorkerMeta = {
|
|
|
23
23
|
export default async function handle(job: QueuedJob<PollerJobPayload>, ctx: HandlerContext): Promise<void> {
|
|
24
24
|
const service = ctx.resolve<ShippingCarrierService>('shippingCarrierService')
|
|
25
25
|
for (const shipmentId of job.payload.shipmentIds) {
|
|
26
|
-
await service.
|
|
26
|
+
await service.refreshTracking({
|
|
27
27
|
providerKey: job.payload.providerKey,
|
|
28
28
|
shipmentId,
|
|
29
29
|
organizationId: job.payload.scope.organizationId,
|
|
@@ -9,6 +9,7 @@ import { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'
|
|
|
9
9
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
10
10
|
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
11
11
|
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
12
|
+
import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
|
|
12
13
|
import { useCustomFieldDefs } from '@open-mercato/ui/backend/utils/customFieldDefs'
|
|
13
14
|
import { Save, Plus, X } from 'lucide-react'
|
|
14
15
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
@@ -19,6 +20,9 @@ import { formatEntityLabel, buildEntityListUrl, getRecordLabel, resolveBaseValue
|
|
|
19
20
|
import { resolveFieldList } from '../lib/resolve-field-list'
|
|
20
21
|
import type { ResolvedField } from '../lib/resolve-field-list'
|
|
21
22
|
|
|
23
|
+
const TRANSLATION_MUTATION_CONTEXT_ID = 'translations.entity-translations'
|
|
24
|
+
const SUPPORTED_LOCALES_MUTATION_CONTEXT_ID = 'translations.supported-locales'
|
|
25
|
+
|
|
22
26
|
type TranslationManagerProps = {
|
|
23
27
|
entityType?: string
|
|
24
28
|
recordId?: string
|
|
@@ -218,6 +222,16 @@ export function TranslationManager({
|
|
|
218
222
|
}
|
|
219
223
|
}, [translationSignature, translationData])
|
|
220
224
|
|
|
225
|
+
const { runMutation, retryLastMutation } = useGuardedMutation<{
|
|
226
|
+
formId: string
|
|
227
|
+
entityType: string
|
|
228
|
+
recordId: string
|
|
229
|
+
resourceKind: string
|
|
230
|
+
resourceId: string
|
|
231
|
+
data: TranslationsResponse | null
|
|
232
|
+
retryLastMutation: () => Promise<boolean>
|
|
233
|
+
}>({ contextId: TRANSLATION_MUTATION_CONTEXT_ID })
|
|
234
|
+
|
|
221
235
|
const mutation = useMutation({
|
|
222
236
|
mutationFn: async () => {
|
|
223
237
|
if (!entityType || !recordId) {
|
|
@@ -239,21 +253,35 @@ export function TranslationManager({
|
|
|
239
253
|
console.warn('[translations] Save skipped: payload is empty — no locale contains any non-empty field')
|
|
240
254
|
throw new Error(t('translations.manager.errors.nothingToSave', 'Nothing to save — enter a translation first'))
|
|
241
255
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
256
|
+
return runMutation({
|
|
257
|
+
operation: async () => {
|
|
258
|
+
const res = await withScopedApiRequestHeaders(
|
|
259
|
+
buildOptimisticLockHeader(translationData?.updatedAt),
|
|
260
|
+
() => apiCall(
|
|
261
|
+
`/api/translations/${encodeURIComponent(entityType)}/${encodeURIComponent(recordId)}`,
|
|
262
|
+
{
|
|
263
|
+
method: 'PUT',
|
|
264
|
+
headers: { 'content-type': 'application/json' },
|
|
265
|
+
body: JSON.stringify(body),
|
|
266
|
+
},
|
|
267
|
+
),
|
|
268
|
+
)
|
|
269
|
+
if (!res.ok) {
|
|
270
|
+
throw new Error(t('translations.manager.errors.save', 'Failed to save translations'))
|
|
271
|
+
}
|
|
272
|
+
return true
|
|
273
|
+
},
|
|
274
|
+
context: {
|
|
275
|
+
formId: TRANSLATION_MUTATION_CONTEXT_ID,
|
|
276
|
+
entityType,
|
|
277
|
+
recordId,
|
|
278
|
+
resourceKind: 'translation',
|
|
279
|
+
resourceId: recordId,
|
|
280
|
+
data: translationData ?? null,
|
|
281
|
+
retryLastMutation,
|
|
282
|
+
},
|
|
283
|
+
mutationPayload: body,
|
|
284
|
+
})
|
|
257
285
|
},
|
|
258
286
|
onSuccess: () => {
|
|
259
287
|
flash(t('translations.manager.flash.saved', 'Translations saved'), 'success')
|
|
@@ -541,16 +569,32 @@ export function LocaleManager() {
|
|
|
541
569
|
const { data: locales = [], isLoading } = useTranslationLocales()
|
|
542
570
|
const [newLocale, setNewLocale] = React.useState('')
|
|
543
571
|
|
|
572
|
+
const { runMutation, retryLastMutation } = useGuardedMutation<{
|
|
573
|
+
formId: string
|
|
574
|
+
resourceKind: string
|
|
575
|
+
retryLastMutation: () => Promise<boolean>
|
|
576
|
+
}>({ contextId: SUPPORTED_LOCALES_MUTATION_CONTEXT_ID })
|
|
577
|
+
|
|
544
578
|
const mutation = useMutation({
|
|
545
579
|
mutationFn: async (updatedLocales: string[]) => {
|
|
546
580
|
// optimistic-lock-exempt: single-row tenant supported-locales settings list — no per-record version / concurrent record edit
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
581
|
+
return runMutation({
|
|
582
|
+
operation: async () => {
|
|
583
|
+
const res = await apiCall<{ locales: string[] }>('/api/translations/locales', {
|
|
584
|
+
method: 'PUT',
|
|
585
|
+
headers: { 'content-type': 'application/json' },
|
|
586
|
+
body: JSON.stringify({ locales: updatedLocales }),
|
|
587
|
+
})
|
|
588
|
+
if (!res.ok) throw new Error('Failed to save locales')
|
|
589
|
+
return res.result?.locales ?? updatedLocales
|
|
590
|
+
},
|
|
591
|
+
context: {
|
|
592
|
+
formId: SUPPORTED_LOCALES_MUTATION_CONTEXT_ID,
|
|
593
|
+
resourceKind: 'translation-locales',
|
|
594
|
+
retryLastMutation,
|
|
595
|
+
},
|
|
596
|
+
mutationPayload: { locales: updatedLocales },
|
|
551
597
|
})
|
|
552
|
-
if (!res.ok) throw new Error('Failed to save locales')
|
|
553
|
-
return res.result?.locales ?? updatedLocales
|
|
554
598
|
},
|
|
555
599
|
onSuccess: (result) => {
|
|
556
600
|
queryClient.setQueryData(['translation-locales'], result)
|