@burdenoff/microfe-movethewheels 2026.1011.1 → 2026.1011.2
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/MoveTheWheelsRoot.js +5 -0
- package/dist/MoveTheWheelsRoutes.js +54 -50
- package/dist/generated/shipment-status-authority-operations.d.ts +4473 -0
- package/dist/hooks/useEpod.js +85 -77
- package/dist/hooks/useShipmentStatusAuthority.js +127 -0
- package/dist/hooks/useTracking.js +15 -14
- package/dist/hooks/useTrackingEventQuality.js +43 -17
- package/dist/movethewheels/hooks/useEpod.d.ts +23 -0
- package/dist/movethewheels/hooks/useShipmentStatusAuthority.d.ts +23 -0
- package/dist/movethewheels/hooks/useTrackingEventQuality.d.ts +5 -0
- package/dist/movethewheels/pages/ShipmentStatusAuthorityPage.d.ts +1 -0
- package/dist/movethewheels/utils/shipmentStatusDraft.d.ts +45 -0
- package/dist/pages/DeliveryCapturePage.js +181 -116
- package/dist/pages/ShipmentStatusAuthorityPage.js +563 -0
- package/dist/pages/TrackingEventQualityPage.js +6 -1
- package/dist/src/generated/shipment-status-authority-operations.js +86 -0
- package/dist/utils/shipmentStatusDraft.js +41 -0
- package/package.json +5 -4
- package/src/generated/shipment-status-authority-operations.ts +5503 -0
- package/src/movethewheels/MoveTheWheelsRoot.tsx +6 -0
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +2 -0
- package/src/movethewheels/hooks/useEpod.ts +47 -12
- package/src/movethewheels/hooks/useShipmentStatusAuthority.ts +179 -0
- package/src/movethewheels/hooks/useTracking.ts +27 -12
- package/src/movethewheels/hooks/useTrackingEventQuality.ts +42 -0
- package/src/movethewheels/pages/DeliveryCapturePage.tsx +113 -6
- package/src/movethewheels/pages/ShipmentStatusAuthorityPage.tsx +639 -0
- package/src/movethewheels/pages/TrackingEventQualityPage.tsx +13 -2
- package/src/movethewheels/utils/shipmentStatusDraft.ts +118 -0
- package/src/operations/shipment-status-authority/status.graphql +80 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export interface ShipmentSourceDraft {
|
|
2
|
+
integrationId: string;
|
|
3
|
+
basisTrackingEventId: string;
|
|
4
|
+
maxSourceAgeSeconds: string;
|
|
5
|
+
maxFutureSkewSeconds: string;
|
|
6
|
+
reason: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function statusDecisionReason(value: string): string {
|
|
10
|
+
const reason = value.trim();
|
|
11
|
+
if (!reason || reason.length > 1000) throw new Error('Enter a reason of 1–1000 characters.');
|
|
12
|
+
return reason;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function explicitSeconds(value: string, minimum: number, maximum: number, label: string): number {
|
|
16
|
+
if (!/^\d+$/.test(value.trim()))
|
|
17
|
+
throw new Error(`${label} must be an explicit whole number of seconds.`);
|
|
18
|
+
const result = Number(value.trim());
|
|
19
|
+
if (!Number.isSafeInteger(result) || result < minimum || result > maximum)
|
|
20
|
+
throw new Error(`${label} must be between ${minimum} and ${maximum} seconds.`);
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function shipmentSourceInput(draft: ShipmentSourceDraft, expectedStatusRevision: number) {
|
|
25
|
+
if (!draft.integrationId || !draft.basisTrackingEventId)
|
|
26
|
+
throw new Error('Choose one integration and one recorded basis event.');
|
|
27
|
+
return {
|
|
28
|
+
expectedStatusRevision,
|
|
29
|
+
integrationId: draft.integrationId,
|
|
30
|
+
basisTrackingEventId: draft.basisTrackingEventId,
|
|
31
|
+
maxSourceAgeSeconds: explicitSeconds(
|
|
32
|
+
draft.maxSourceAgeSeconds,
|
|
33
|
+
1,
|
|
34
|
+
2592000,
|
|
35
|
+
'Maximum source age'
|
|
36
|
+
),
|
|
37
|
+
maxFutureSkewSeconds: explicitSeconds(
|
|
38
|
+
draft.maxFutureSkewSeconds,
|
|
39
|
+
0,
|
|
40
|
+
86400,
|
|
41
|
+
'Allowed future skew'
|
|
42
|
+
),
|
|
43
|
+
reason: statusDecisionReason(draft.reason),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface StatusAcknowledgement {
|
|
48
|
+
id: string;
|
|
49
|
+
status: string;
|
|
50
|
+
statusRevision: number;
|
|
51
|
+
statusAuthority: string;
|
|
52
|
+
statusAuthorityEpoch: number;
|
|
53
|
+
designatedIntegrationId?: string | null;
|
|
54
|
+
statusBasisEventId?: string | null;
|
|
55
|
+
statusBasisSourceTime?: string | null;
|
|
56
|
+
maxSourceAgeSeconds?: number | null;
|
|
57
|
+
maxFutureSkewSeconds?: number | null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function sourceStatusAcknowledged(
|
|
61
|
+
actual: StatusAcknowledgement | null | undefined,
|
|
62
|
+
expected: {
|
|
63
|
+
id: string;
|
|
64
|
+
epoch: number;
|
|
65
|
+
input: ReturnType<typeof shipmentSourceInput>;
|
|
66
|
+
basis: { id: string; eventType: string; providerEventTime?: string | null } | undefined;
|
|
67
|
+
}
|
|
68
|
+
): boolean {
|
|
69
|
+
const statuses: Record<string, string> = {
|
|
70
|
+
PICKED_UP: 'PICKED_UP',
|
|
71
|
+
IN_TRANSIT: 'IN_TRANSIT',
|
|
72
|
+
ARRIVED: 'IN_TRANSIT',
|
|
73
|
+
DEPARTED: 'IN_TRANSIT',
|
|
74
|
+
OUT_FOR_DELIVERY: 'IN_TRANSIT',
|
|
75
|
+
DELIVERED: 'DELIVERED',
|
|
76
|
+
FAILED: 'FAILED',
|
|
77
|
+
RETURNED: 'RETURNED',
|
|
78
|
+
};
|
|
79
|
+
const basis = expected.basis;
|
|
80
|
+
const time = basis?.providerEventTime ? Date.parse(basis.providerEventTime) : NaN;
|
|
81
|
+
return (
|
|
82
|
+
!!actual &&
|
|
83
|
+
!!basis &&
|
|
84
|
+
Number.isFinite(time) &&
|
|
85
|
+
actual.id === expected.id &&
|
|
86
|
+
actual.statusRevision === expected.input.expectedStatusRevision + 1 &&
|
|
87
|
+
actual.statusAuthority === 'INTEGRATION_EVENT_TIME' &&
|
|
88
|
+
actual.statusAuthorityEpoch === expected.epoch + 1 &&
|
|
89
|
+
actual.designatedIntegrationId === expected.input.integrationId &&
|
|
90
|
+
actual.statusBasisEventId === basis.id &&
|
|
91
|
+
basis.id === expected.input.basisTrackingEventId &&
|
|
92
|
+
typeof actual.statusBasisSourceTime === 'string' &&
|
|
93
|
+
Date.parse(actual.statusBasisSourceTime) === time &&
|
|
94
|
+
actual.maxSourceAgeSeconds === expected.input.maxSourceAgeSeconds &&
|
|
95
|
+
actual.maxFutureSkewSeconds === expected.input.maxFutureSkewSeconds &&
|
|
96
|
+
typeof statuses[basis.eventType] === 'string' &&
|
|
97
|
+
actual.status === statuses[basis.eventType]
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function manualStatusAcknowledged(
|
|
102
|
+
actual: StatusAcknowledgement | null | undefined,
|
|
103
|
+
expected: { id: string; revision: number; epoch: number; status: string }
|
|
104
|
+
): boolean {
|
|
105
|
+
return (
|
|
106
|
+
!!actual &&
|
|
107
|
+
actual.id === expected.id &&
|
|
108
|
+
actual.statusRevision === expected.revision + 1 &&
|
|
109
|
+
actual.status === expected.status &&
|
|
110
|
+
actual.statusAuthority === 'MANUAL_HOLD' &&
|
|
111
|
+
actual.statusAuthorityEpoch === expected.epoch + 1 &&
|
|
112
|
+
actual.designatedIntegrationId === null &&
|
|
113
|
+
actual.statusBasisEventId === null &&
|
|
114
|
+
actual.statusBasisSourceTime === null &&
|
|
115
|
+
actual.maxSourceAgeSeconds === null &&
|
|
116
|
+
actual.maxFutureSkewSeconds === null
|
|
117
|
+
);
|
|
118
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
fragment ShipmentStatusAuthorityFields on MtwShipment {
|
|
2
|
+
id
|
|
3
|
+
shipmentNumber
|
|
4
|
+
status
|
|
5
|
+
statusRevision
|
|
6
|
+
statusAuthority
|
|
7
|
+
statusAuthorityEpoch
|
|
8
|
+
designatedIntegrationId
|
|
9
|
+
statusBasisEventId
|
|
10
|
+
statusBasisSourceTime
|
|
11
|
+
maxSourceAgeSeconds
|
|
12
|
+
maxFutureSkewSeconds
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
query StatusAuthorityShipments($filter: ShipmentFilterInput, $pagination: PaginationInput!) {
|
|
16
|
+
shipments(filter: $filter, pagination: $pagination) {
|
|
17
|
+
...ShipmentStatusAuthorityFields
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
query StatusAuthorityDetail($id: ID!, $pagination: PaginationInput!, $evidencePagination: PaginationInput!) {
|
|
22
|
+
shipment(id: $id) {
|
|
23
|
+
...ShipmentStatusAuthorityFields
|
|
24
|
+
trackingEvents(pagination: $evidencePagination) {
|
|
25
|
+
id
|
|
26
|
+
eventType
|
|
27
|
+
sourceIntegrationId
|
|
28
|
+
sourceTimestampProvenance
|
|
29
|
+
providerEventTime
|
|
30
|
+
serverReceivedAt
|
|
31
|
+
timestamp
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
shipmentStatusDecisions(shipmentId: $id, pagination: $pagination) {
|
|
35
|
+
id
|
|
36
|
+
origin
|
|
37
|
+
outcome
|
|
38
|
+
heldReason
|
|
39
|
+
observedRevision
|
|
40
|
+
resultRevision
|
|
41
|
+
priorStatus
|
|
42
|
+
resultStatus
|
|
43
|
+
trackingEventId
|
|
44
|
+
proofId
|
|
45
|
+
reason
|
|
46
|
+
recordedAt
|
|
47
|
+
configuredIntegrationId
|
|
48
|
+
configuredMaxSourceAgeSeconds
|
|
49
|
+
configuredMaxFutureSkewSeconds
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
query StatusAuthoritySources($pagination: PaginationInput!) {
|
|
54
|
+
integrations(pagination: $pagination) {
|
|
55
|
+
id
|
|
56
|
+
name
|
|
57
|
+
provider
|
|
58
|
+
status
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
mutation StatusAuthorityConfigure($id: ID!, $input: ConfigureShipmentStatusSourceInput!) {
|
|
63
|
+
configureShipmentStatusSource(id: $id, input: $input) {
|
|
64
|
+
...ShipmentStatusAuthorityFields
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
mutation StatusAuthorityManual($id: ID!, $input: UpdateShipmentInput!) {
|
|
69
|
+
updateShipment(id: $id, input: $input) {
|
|
70
|
+
...ShipmentStatusAuthorityFields
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
query StatusAuthorityOwnedDelivery($deliveryJobId: ID!) {
|
|
75
|
+
myEpodShipmentStatus(deliveryJobId: $deliveryJobId) {
|
|
76
|
+
id
|
|
77
|
+
status
|
|
78
|
+
statusRevision
|
|
79
|
+
}
|
|
80
|
+
}
|