@d19n/youfibre-odin-sdk 2.0.151 → 2.0.157
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/wholesale-provider/change-reason-classifications.d.ts +73 -0
- package/dist/wholesale-provider/change-reason-classifications.js +178 -0
- package/dist/wholesale-provider/index.d.ts +4 -1
- package/dist/wholesale-provider/index.js +20 -1
- package/dist/wholesale-provider/install-stage-kci-spec.d.ts +26 -0
- package/dist/wholesale-provider/install-stage-kci-spec.js +102 -0
- package/dist/wholesale-provider/interface.d.ts +42 -1
- package/dist/wholesale-provider/kci-effect-bridge.d.ts +19 -1
- package/dist/wholesale-provider/kci-effect-bridge.js +42 -8
- package/dist/wholesale-provider/providers/netomnia-provider.d.ts +3 -1
- package/dist/wholesale-provider/providers/netomnia-provider.js +3 -0
- package/dist/wholesale-provider/test/netomnia-provider.spec.js +5 -0
- package/dist/wholesale-provider/types/fibrecafe.d.ts +15 -0
- package/package.json +1 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChangeReason enum classifications — the single source of truth for how
|
|
3
|
+
* the Install Fulfilment digest (and any future audit / detector) interprets
|
|
4
|
+
* `ChangeReasonRescheduleReason` and `ChangeReasonCancelReason` values.
|
|
5
|
+
*
|
|
6
|
+
* Why this lives in the SDK:
|
|
7
|
+
* The values in `entities-v2/ChangeReason.ts` are flat enums — they don't
|
|
8
|
+
* tell a consumer "which of these are tenant-side resolves vs supplier-side
|
|
9
|
+
* escalations vs data hygiene". Without a classification anchor, every
|
|
10
|
+
* downstream consumer (alerts, dashboards, remediation scripts) ends up
|
|
11
|
+
* hand-coding its own predicate.
|
|
12
|
+
*
|
|
13
|
+
* The authoring origin is the agent-os BP knowledge file
|
|
14
|
+
* `business-processes/change-reason-classifications.ts`; this is its
|
|
15
|
+
* published projection so both the agent-os tooling AND deployed services
|
|
16
|
+
* (youfibre-api-connect) consume one source. Keep the two in lockstep.
|
|
17
|
+
*
|
|
18
|
+
* String literals (not the SDK enum) are used so the sets stay decoupled
|
|
19
|
+
* from enum-shape churn; the `unclassified*` helpers below surface drift
|
|
20
|
+
* when a consumer passes `Object.values(ChangeReason*Reason)`.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Billing-blocked reschedules — YF moved the WO because the customer has no
|
|
24
|
+
* active direct-debit mandate. YF does NOT dispatch `amendOrder` to the
|
|
25
|
+
* supplier (held off until billing is set up), so these will NEVER receive
|
|
26
|
+
* an `AMENDED` KCI back. Action lever: chase the customer for the mandate.
|
|
27
|
+
*/
|
|
28
|
+
export declare const BILLING_BLOCKED_RESCHEDULE_REASONS: ReadonlySet<string>;
|
|
29
|
+
/** Alias kept for backward compatibility — prefer the specific category above. */
|
|
30
|
+
export declare const TENANT_PENDING_RESCHEDULE_REASONS: ReadonlySet<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Customer follow-up reschedules — customer unavailable / unaware, so YF
|
|
33
|
+
* moved the appointment and must chase the customer to rebook.
|
|
34
|
+
*/
|
|
35
|
+
export declare const CUSTOMER_FOLLOWUP_RESCHEDULE_REASONS: ReadonlySet<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Misselling-signal reschedules — customer indicates they don't need the
|
|
38
|
+
* service (likely a sales-time misselling artifact).
|
|
39
|
+
*/
|
|
40
|
+
export declare const MISSELLING_RESCHEDULE_REASONS: ReadonlySet<string>;
|
|
41
|
+
/** Reschedules whose root cause is a supplier-side issue. */
|
|
42
|
+
export declare const SUPPLIER_SIDE_CAUSE_RESCHEDULE_REASONS: ReadonlySet<string>;
|
|
43
|
+
/** Intra-today shuffle — `previousDate = today AND currentDate = today`. */
|
|
44
|
+
export declare const INTRA_TODAY_RESCHEDULE_REASONS: ReadonlySet<string>;
|
|
45
|
+
/**
|
|
46
|
+
* Recontract side-effect cancellations — applying an existing-subscriber
|
|
47
|
+
* recontract cancels the PREVIOUS Order with `CancellationReason =
|
|
48
|
+
* CONTRACT_RENEWAL`. The install succeeded; the previous Order is retired.
|
|
49
|
+
* MUST be excluded from cancellation counts.
|
|
50
|
+
*/
|
|
51
|
+
export declare const RECONTRACT_SIDE_EFFECT_CANCEL_REASONS: ReadonlySet<string>;
|
|
52
|
+
/** Data-hygiene cancellations — excluded from "failed installs". */
|
|
53
|
+
export declare const DATA_HYGIENE_CANCEL_REASONS: ReadonlySet<string>;
|
|
54
|
+
/** Customer churn / decision cancellations — real fulfilment loss. */
|
|
55
|
+
export declare const CHURN_CANCEL_REASONS: ReadonlySet<string>;
|
|
56
|
+
/** Supplier-side cause cancellations — install blocked by supplier/network. */
|
|
57
|
+
export declare const SUPPLIER_SIDE_CAUSE_CANCEL_REASONS: ReadonlySet<string>;
|
|
58
|
+
/** Customer-side cause cancellations — premises / billing / engagement. */
|
|
59
|
+
export declare const CUSTOMER_SIDE_CAUSE_CANCEL_REASONS: ReadonlySet<string>;
|
|
60
|
+
/**
|
|
61
|
+
* A cancellation counts as a fulfilment failure iff its CancellationReason
|
|
62
|
+
* is NOT a recontract side-effect AND NOT a data-hygiene cleanup. Customer-
|
|
63
|
+
* and supplier-cause cancellations DO count — the customer didn't get
|
|
64
|
+
* serviced today. Unknown reason → conservative (counts as failure).
|
|
65
|
+
*/
|
|
66
|
+
export declare function isFulfilmentFailureCancel(cancelReason: string | undefined): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Returns enum values from `allKnownValues` not classified into any
|
|
69
|
+
* operational set. Callers pass `Object.values(ChangeReasonRescheduleReason)`
|
|
70
|
+
* so this stays free of a hard enum import while still enabling drift checks.
|
|
71
|
+
*/
|
|
72
|
+
export declare function unclassifiedRescheduleReasons(allKnownValues: readonly string[]): string[];
|
|
73
|
+
export declare function unclassifiedCancelReasons(allKnownValues: readonly string[]): string[];
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ChangeReason enum classifications — the single source of truth for how
|
|
4
|
+
* the Install Fulfilment digest (and any future audit / detector) interprets
|
|
5
|
+
* `ChangeReasonRescheduleReason` and `ChangeReasonCancelReason` values.
|
|
6
|
+
*
|
|
7
|
+
* Why this lives in the SDK:
|
|
8
|
+
* The values in `entities-v2/ChangeReason.ts` are flat enums — they don't
|
|
9
|
+
* tell a consumer "which of these are tenant-side resolves vs supplier-side
|
|
10
|
+
* escalations vs data hygiene". Without a classification anchor, every
|
|
11
|
+
* downstream consumer (alerts, dashboards, remediation scripts) ends up
|
|
12
|
+
* hand-coding its own predicate.
|
|
13
|
+
*
|
|
14
|
+
* The authoring origin is the agent-os BP knowledge file
|
|
15
|
+
* `business-processes/change-reason-classifications.ts`; this is its
|
|
16
|
+
* published projection so both the agent-os tooling AND deployed services
|
|
17
|
+
* (youfibre-api-connect) consume one source. Keep the two in lockstep.
|
|
18
|
+
*
|
|
19
|
+
* String literals (not the SDK enum) are used so the sets stay decoupled
|
|
20
|
+
* from enum-shape churn; the `unclassified*` helpers below surface drift
|
|
21
|
+
* when a consumer passes `Object.values(ChangeReason*Reason)`.
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.unclassifiedCancelReasons = exports.unclassifiedRescheduleReasons = exports.isFulfilmentFailureCancel = exports.CUSTOMER_SIDE_CAUSE_CANCEL_REASONS = exports.SUPPLIER_SIDE_CAUSE_CANCEL_REASONS = exports.CHURN_CANCEL_REASONS = exports.DATA_HYGIENE_CANCEL_REASONS = exports.RECONTRACT_SIDE_EFFECT_CANCEL_REASONS = exports.INTRA_TODAY_RESCHEDULE_REASONS = exports.SUPPLIER_SIDE_CAUSE_RESCHEDULE_REASONS = exports.MISSELLING_RESCHEDULE_REASONS = exports.CUSTOMER_FOLLOWUP_RESCHEDULE_REASONS = exports.TENANT_PENDING_RESCHEDULE_REASONS = exports.BILLING_BLOCKED_RESCHEDULE_REASONS = void 0;
|
|
25
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
26
|
+
// RescheduleReason classification
|
|
27
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
28
|
+
/**
|
|
29
|
+
* Billing-blocked reschedules — YF moved the WO because the customer has no
|
|
30
|
+
* active direct-debit mandate. YF does NOT dispatch `amendOrder` to the
|
|
31
|
+
* supplier (held off until billing is set up), so these will NEVER receive
|
|
32
|
+
* an `AMENDED` KCI back. Action lever: chase the customer for the mandate.
|
|
33
|
+
*/
|
|
34
|
+
exports.BILLING_BLOCKED_RESCHEDULE_REASONS = new Set([
|
|
35
|
+
'MISSING_MANDATE',
|
|
36
|
+
]);
|
|
37
|
+
/** Alias kept for backward compatibility — prefer the specific category above. */
|
|
38
|
+
exports.TENANT_PENDING_RESCHEDULE_REASONS = exports.BILLING_BLOCKED_RESCHEDULE_REASONS;
|
|
39
|
+
/**
|
|
40
|
+
* Customer follow-up reschedules — customer unavailable / unaware, so YF
|
|
41
|
+
* moved the appointment and must chase the customer to rebook.
|
|
42
|
+
*/
|
|
43
|
+
exports.CUSTOMER_FOLLOWUP_RESCHEDULE_REASONS = new Set([
|
|
44
|
+
'PROPERTY_UNOCCUPIED',
|
|
45
|
+
'UNAWARE_OF_APPOINTMENT',
|
|
46
|
+
]);
|
|
47
|
+
/**
|
|
48
|
+
* Misselling-signal reschedules — customer indicates they don't need the
|
|
49
|
+
* service (likely a sales-time misselling artifact).
|
|
50
|
+
*/
|
|
51
|
+
exports.MISSELLING_RESCHEDULE_REASONS = new Set([
|
|
52
|
+
'NO_LONGER_REQUIRED',
|
|
53
|
+
'CANCELLATION_FOR_PERSONAL_REASONS',
|
|
54
|
+
]);
|
|
55
|
+
/** Reschedules whose root cause is a supplier-side issue. */
|
|
56
|
+
exports.SUPPLIER_SIDE_CAUSE_RESCHEDULE_REASONS = new Set([
|
|
57
|
+
'AREA_NOT_RFS_SUPPLIER',
|
|
58
|
+
'ADDITIONAL_WORKS_REQUIRED_APPROVAL_NEEDED',
|
|
59
|
+
'SCHEDULE_CHANGED',
|
|
60
|
+
'SCHEDULE_CONTRACTOR_CHANGED',
|
|
61
|
+
'ENGINEER_DID_NOT_ATTEND',
|
|
62
|
+
'ENGINEER_UNABLE_TO_RESOLVE',
|
|
63
|
+
'ADVERSE_WEATHER_CONDITIONS',
|
|
64
|
+
'UNABLE_TO_ATTEND', // supplier-set slot the customer couldn't make
|
|
65
|
+
]);
|
|
66
|
+
/** Intra-today shuffle — `previousDate = today AND currentDate = today`. */
|
|
67
|
+
exports.INTRA_TODAY_RESCHEDULE_REASONS = new Set([
|
|
68
|
+
'TIME_BLOCK_CHANGED',
|
|
69
|
+
]);
|
|
70
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
71
|
+
// CancelReason classification
|
|
72
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
73
|
+
/**
|
|
74
|
+
* Recontract side-effect cancellations — applying an existing-subscriber
|
|
75
|
+
* recontract cancels the PREVIOUS Order with `CancellationReason =
|
|
76
|
+
* CONTRACT_RENEWAL`. The install succeeded; the previous Order is retired.
|
|
77
|
+
* MUST be excluded from cancellation counts.
|
|
78
|
+
*/
|
|
79
|
+
exports.RECONTRACT_SIDE_EFFECT_CANCEL_REASONS = new Set([
|
|
80
|
+
'CONTRACT_RENEWAL',
|
|
81
|
+
'CONTRACT_RENEWAL_ROLLBACK',
|
|
82
|
+
]);
|
|
83
|
+
/** Data-hygiene cancellations — excluded from "failed installs". */
|
|
84
|
+
exports.DATA_HYGIENE_CANCEL_REASONS = new Set([
|
|
85
|
+
'DUPLICATE_ORDER_OR_WORK_ORDER',
|
|
86
|
+
'REMEDIATION_RAISED_IN_ERROR',
|
|
87
|
+
'PREPULL_CANCELLATION_RAISED_IN_ERROR',
|
|
88
|
+
'REMEDIATION_NOT_REQUIRED',
|
|
89
|
+
'SERVICE_VISIT_NO_LONGER_REQUIRED',
|
|
90
|
+
'PTF_PROCESS_NOT_FOLLOWED',
|
|
91
|
+
'CHANGED_ASSIGNED_CONTRACTOR',
|
|
92
|
+
'PREPULL_CANCELLATION_ACCEPTING_INST_RISK',
|
|
93
|
+
]);
|
|
94
|
+
/** Customer churn / decision cancellations — real fulfilment loss. */
|
|
95
|
+
exports.CHURN_CANCEL_REASONS = new Set([
|
|
96
|
+
'CUSTOMER_CANCELLED',
|
|
97
|
+
'STAYING_WITH_EXISTING_PROVIDER',
|
|
98
|
+
'NO_LONGER_INTERESTED_IN_SERVICE',
|
|
99
|
+
'MULTIPLE_RESCHEDULE_NO_LONGER_WANTS_SERVICE',
|
|
100
|
+
'MOVING_PREMISES',
|
|
101
|
+
'CLAIMING_MISSELING',
|
|
102
|
+
'STILL_IN_CONTRACT',
|
|
103
|
+
'CANCELLATION_FOR_PERSONAL_REASONS',
|
|
104
|
+
]);
|
|
105
|
+
/** Supplier-side cause cancellations — install blocked by supplier/network. */
|
|
106
|
+
exports.SUPPLIER_SIDE_CAUSE_CANCEL_REASONS = new Set([
|
|
107
|
+
'AREA_NOT_RFS_SUPPLIER',
|
|
108
|
+
'MDU_NOT_RFS',
|
|
109
|
+
'CONNECTION_COSTS_UNVIABLE',
|
|
110
|
+
'NO_CLEAR_INSTALLATION_ROUTE',
|
|
111
|
+
'UNABLE_TO_GET_PTD_WAYLEAVE',
|
|
112
|
+
'RFS_QUARANTINED',
|
|
113
|
+
'RFS_REVERSED',
|
|
114
|
+
'ENGINEER_DID_NOT_ATTEND',
|
|
115
|
+
'ADDITIONAL_WORKS_REQUIRED_APPROVAL_NEEDED',
|
|
116
|
+
'ADVERSE_WEATHER_CONDITIONS',
|
|
117
|
+
]);
|
|
118
|
+
/** Customer-side cause cancellations — premises / billing / engagement. */
|
|
119
|
+
exports.CUSTOMER_SIDE_CAUSE_CANCEL_REASONS = new Set([
|
|
120
|
+
'MISSING_MANDATE',
|
|
121
|
+
'HEALTH_AND_SAFETY_CONCERN_CUSTOMER_PREMISE',
|
|
122
|
+
'H_S_CONCERN_CUSTOMER_PREMISE',
|
|
123
|
+
'UNHAPPY_WITH_EXTERNAL_INSTALLATION_ROUTE',
|
|
124
|
+
'UNHAPPY_WITH_INTERNAL_INSTALLATION_ROUTE',
|
|
125
|
+
'INCORRECT_ADDRESS_BOOKED',
|
|
126
|
+
'UNABLE_TO_ATTEND',
|
|
127
|
+
'CUSTOMER_REFUSED_REMEDIATION_WORK',
|
|
128
|
+
'REMEDIATION_REQUIRED_CUSTOMER_UNWILLING_TO_WAIT',
|
|
129
|
+
]);
|
|
130
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
131
|
+
// Convenience predicate
|
|
132
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
133
|
+
/**
|
|
134
|
+
* A cancellation counts as a fulfilment failure iff its CancellationReason
|
|
135
|
+
* is NOT a recontract side-effect AND NOT a data-hygiene cleanup. Customer-
|
|
136
|
+
* and supplier-cause cancellations DO count — the customer didn't get
|
|
137
|
+
* serviced today. Unknown reason → conservative (counts as failure).
|
|
138
|
+
*/
|
|
139
|
+
function isFulfilmentFailureCancel(cancelReason) {
|
|
140
|
+
if (!cancelReason)
|
|
141
|
+
return true;
|
|
142
|
+
if (exports.RECONTRACT_SIDE_EFFECT_CANCEL_REASONS.has(cancelReason))
|
|
143
|
+
return false;
|
|
144
|
+
if (exports.DATA_HYGIENE_CANCEL_REASONS.has(cancelReason))
|
|
145
|
+
return false;
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
exports.isFulfilmentFailureCancel = isFulfilmentFailureCancel;
|
|
149
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
150
|
+
// Coverage helpers — surface drift between the SDK enum and these sets
|
|
151
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
152
|
+
/**
|
|
153
|
+
* Returns enum values from `allKnownValues` not classified into any
|
|
154
|
+
* operational set. Callers pass `Object.values(ChangeReasonRescheduleReason)`
|
|
155
|
+
* so this stays free of a hard enum import while still enabling drift checks.
|
|
156
|
+
*/
|
|
157
|
+
function unclassifiedRescheduleReasons(allKnownValues) {
|
|
158
|
+
const classified = new Set([
|
|
159
|
+
...exports.TENANT_PENDING_RESCHEDULE_REASONS,
|
|
160
|
+
...exports.CUSTOMER_FOLLOWUP_RESCHEDULE_REASONS,
|
|
161
|
+
...exports.MISSELLING_RESCHEDULE_REASONS,
|
|
162
|
+
...exports.SUPPLIER_SIDE_CAUSE_RESCHEDULE_REASONS,
|
|
163
|
+
...exports.INTRA_TODAY_RESCHEDULE_REASONS,
|
|
164
|
+
]);
|
|
165
|
+
return allKnownValues.filter((v) => !classified.has(v));
|
|
166
|
+
}
|
|
167
|
+
exports.unclassifiedRescheduleReasons = unclassifiedRescheduleReasons;
|
|
168
|
+
function unclassifiedCancelReasons(allKnownValues) {
|
|
169
|
+
const classified = new Set([
|
|
170
|
+
...exports.RECONTRACT_SIDE_EFFECT_CANCEL_REASONS,
|
|
171
|
+
...exports.DATA_HYGIENE_CANCEL_REASONS,
|
|
172
|
+
...exports.CHURN_CANCEL_REASONS,
|
|
173
|
+
...exports.SUPPLIER_SIDE_CAUSE_CANCEL_REASONS,
|
|
174
|
+
...exports.CUSTOMER_SIDE_CAUSE_CANCEL_REASONS,
|
|
175
|
+
]);
|
|
176
|
+
return allKnownValues.filter((v) => !classified.has(v));
|
|
177
|
+
}
|
|
178
|
+
exports.unclassifiedCancelReasons = unclassifiedCancelReasons;
|
|
@@ -25,11 +25,14 @@
|
|
|
25
25
|
*
|
|
26
26
|
* Linked: T-20260508-009 / T-20260508-010
|
|
27
27
|
*/
|
|
28
|
-
export type { WholesaleProvider, CreateOrderOptions, CancellationReasonCode, ReserveAppointmentArgs, ListAppointmentsArgs, ScheduleServiceWorkOrderArgs, RescheduleServiceWorkOrderArgs, AmendAppointmentArgs, SyncWorkOrderToSupplierArgs, UpdateOrderExternalRefArgs, } from './interface';
|
|
28
|
+
export type { WholesaleProvider, CreateOrderOptions, CancellationReasonCode, CancelServiceWorkOrderArgs, ReserveAppointmentArgs, ListAppointmentsArgs, ScheduleServiceWorkOrderArgs, RescheduleServiceWorkOrderArgs, AmendAppointmentArgs, SyncWorkOrderToSupplierArgs, UpdateOrderExternalRefArgs, } from './interface';
|
|
29
29
|
export type { WholesaleResult, WholesaleSyncResponse, WholesaleRejectionResponse, WholesaleRejectionMessage, WholesaleBUS, WholesaleSYS, ISO8601DateTime, ISODate, TransactionId, UPRN, UUID, SwitchOrderReference, } from './types/wholesale';
|
|
30
30
|
export { NetomniaProvider, AggregateNotificationError } from './providers/netomnia-provider';
|
|
31
31
|
export type { NetomniaProviderDeps } from './providers/netomnia-provider';
|
|
32
32
|
export { KCI_EFFECT_ROWS, decideKciDispatch, detectKciKind, } from './kci-effect-bridge';
|
|
33
33
|
export type { KciServiceOrderKind, YfKciSemanticOp, YfKciEffectKind, YfKciTargetEntity, YfKciEffect, KciEffectRow, KciDispatchDecision, } from './kci-effect-bridge';
|
|
34
|
+
export { INSTALL_STAGE_KCI_SOURCES, buildInstallStageReasonCodeSpecs, } from './install-stage-kci-spec';
|
|
35
|
+
export type { InstallStageKciSource, InstallStageReasonCodeSpec, } from './install-stage-kci-spec';
|
|
36
|
+
export { BILLING_BLOCKED_RESCHEDULE_REASONS, TENANT_PENDING_RESCHEDULE_REASONS, CUSTOMER_FOLLOWUP_RESCHEDULE_REASONS, MISSELLING_RESCHEDULE_REASONS, SUPPLIER_SIDE_CAUSE_RESCHEDULE_REASONS, INTRA_TODAY_RESCHEDULE_REASONS, RECONTRACT_SIDE_EFFECT_CANCEL_REASONS, DATA_HYGIENE_CANCEL_REASONS, CHURN_CANCEL_REASONS, SUPPLIER_SIDE_CAUSE_CANCEL_REASONS, CUSTOMER_SIDE_CAUSE_CANCEL_REASONS, isFulfilmentFailureCancel, unclassifiedRescheduleReasons, unclassifiedCancelReasons, } from './change-reason-classifications';
|
|
34
37
|
export type { VMO2OrderId, VMO2RequestId, VMO2AppointmentKey, VMO2PremiseId, VMO2OrderNotificationType, VMO2SMRNotificationType, VMO2NotificationEnvelope, VMO2OrderNotification, VMO2SMRNotification, VMO2InboundNotification, } from './types/vmo2';
|
|
35
38
|
export * from './types/fibrecafe';
|
|
@@ -41,7 +41,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
41
41
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
42
42
|
};
|
|
43
43
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
-
exports.detectKciKind = exports.decideKciDispatch = exports.KCI_EFFECT_ROWS = exports.AggregateNotificationError = exports.NetomniaProvider = void 0;
|
|
44
|
+
exports.unclassifiedCancelReasons = exports.unclassifiedRescheduleReasons = exports.isFulfilmentFailureCancel = exports.CUSTOMER_SIDE_CAUSE_CANCEL_REASONS = exports.SUPPLIER_SIDE_CAUSE_CANCEL_REASONS = exports.CHURN_CANCEL_REASONS = exports.DATA_HYGIENE_CANCEL_REASONS = exports.RECONTRACT_SIDE_EFFECT_CANCEL_REASONS = exports.INTRA_TODAY_RESCHEDULE_REASONS = exports.SUPPLIER_SIDE_CAUSE_RESCHEDULE_REASONS = exports.MISSELLING_RESCHEDULE_REASONS = exports.CUSTOMER_FOLLOWUP_RESCHEDULE_REASONS = exports.TENANT_PENDING_RESCHEDULE_REASONS = exports.BILLING_BLOCKED_RESCHEDULE_REASONS = exports.buildInstallStageReasonCodeSpecs = exports.INSTALL_STAGE_KCI_SOURCES = exports.detectKciKind = exports.decideKciDispatch = exports.KCI_EFFECT_ROWS = exports.AggregateNotificationError = exports.NetomniaProvider = void 0;
|
|
45
45
|
// ── Provider implementation ───────────────────────────────────────────
|
|
46
46
|
var netomnia_provider_1 = require("./providers/netomnia-provider");
|
|
47
47
|
Object.defineProperty(exports, "NetomniaProvider", { enumerable: true, get: function () { return netomnia_provider_1.NetomniaProvider; } });
|
|
@@ -51,6 +51,25 @@ var kci_effect_bridge_1 = require("./kci-effect-bridge");
|
|
|
51
51
|
Object.defineProperty(exports, "KCI_EFFECT_ROWS", { enumerable: true, get: function () { return kci_effect_bridge_1.KCI_EFFECT_ROWS; } });
|
|
52
52
|
Object.defineProperty(exports, "decideKciDispatch", { enumerable: true, get: function () { return kci_effect_bridge_1.decideKciDispatch; } });
|
|
53
53
|
Object.defineProperty(exports, "detectKciKind", { enumerable: true, get: function () { return kci_effect_bridge_1.detectKciKind; } });
|
|
54
|
+
// ── Install Fulfilment digest BP inputs (published projections) ───────
|
|
55
|
+
var install_stage_kci_spec_1 = require("./install-stage-kci-spec");
|
|
56
|
+
Object.defineProperty(exports, "INSTALL_STAGE_KCI_SOURCES", { enumerable: true, get: function () { return install_stage_kci_spec_1.INSTALL_STAGE_KCI_SOURCES; } });
|
|
57
|
+
Object.defineProperty(exports, "buildInstallStageReasonCodeSpecs", { enumerable: true, get: function () { return install_stage_kci_spec_1.buildInstallStageReasonCodeSpecs; } });
|
|
58
|
+
var change_reason_classifications_1 = require("./change-reason-classifications");
|
|
59
|
+
Object.defineProperty(exports, "BILLING_BLOCKED_RESCHEDULE_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.BILLING_BLOCKED_RESCHEDULE_REASONS; } });
|
|
60
|
+
Object.defineProperty(exports, "TENANT_PENDING_RESCHEDULE_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.TENANT_PENDING_RESCHEDULE_REASONS; } });
|
|
61
|
+
Object.defineProperty(exports, "CUSTOMER_FOLLOWUP_RESCHEDULE_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.CUSTOMER_FOLLOWUP_RESCHEDULE_REASONS; } });
|
|
62
|
+
Object.defineProperty(exports, "MISSELLING_RESCHEDULE_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.MISSELLING_RESCHEDULE_REASONS; } });
|
|
63
|
+
Object.defineProperty(exports, "SUPPLIER_SIDE_CAUSE_RESCHEDULE_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.SUPPLIER_SIDE_CAUSE_RESCHEDULE_REASONS; } });
|
|
64
|
+
Object.defineProperty(exports, "INTRA_TODAY_RESCHEDULE_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.INTRA_TODAY_RESCHEDULE_REASONS; } });
|
|
65
|
+
Object.defineProperty(exports, "RECONTRACT_SIDE_EFFECT_CANCEL_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.RECONTRACT_SIDE_EFFECT_CANCEL_REASONS; } });
|
|
66
|
+
Object.defineProperty(exports, "DATA_HYGIENE_CANCEL_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.DATA_HYGIENE_CANCEL_REASONS; } });
|
|
67
|
+
Object.defineProperty(exports, "CHURN_CANCEL_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.CHURN_CANCEL_REASONS; } });
|
|
68
|
+
Object.defineProperty(exports, "SUPPLIER_SIDE_CAUSE_CANCEL_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.SUPPLIER_SIDE_CAUSE_CANCEL_REASONS; } });
|
|
69
|
+
Object.defineProperty(exports, "CUSTOMER_SIDE_CAUSE_CANCEL_REASONS", { enumerable: true, get: function () { return change_reason_classifications_1.CUSTOMER_SIDE_CAUSE_CANCEL_REASONS; } });
|
|
70
|
+
Object.defineProperty(exports, "isFulfilmentFailureCancel", { enumerable: true, get: function () { return change_reason_classifications_1.isFulfilmentFailureCancel; } });
|
|
71
|
+
Object.defineProperty(exports, "unclassifiedRescheduleReasons", { enumerable: true, get: function () { return change_reason_classifications_1.unclassifiedRescheduleReasons; } });
|
|
72
|
+
Object.defineProperty(exports, "unclassifiedCancelReasons", { enumerable: true, get: function () { return change_reason_classifications_1.unclassifiedCancelReasons; } });
|
|
54
73
|
// ── Reference types (re-exported — not on WholesaleProvider surface) ──
|
|
55
74
|
//
|
|
56
75
|
// FibreCafe wire-format types — useful for module-level DTO consolidation
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface InstallStageKciSource {
|
|
2
|
+
/** WorkOrder stage key (e.g. 'WorkOrderStageScheduled'). */
|
|
3
|
+
readonly stageKey: string;
|
|
4
|
+
/** Human-readable stage name (e.g. 'Scheduled'). */
|
|
5
|
+
readonly stageName: string;
|
|
6
|
+
/** Bridge row ids whose KCI drives entry into this stage. */
|
|
7
|
+
readonly kciSourceRowIds: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Frozen projection of INSTALL_PROCESS.stages (install.ts) — only stages
|
|
11
|
+
* with at least one kciSource-bearing entryAction. Verified against the
|
|
12
|
+
* live BP on 2026-05-20.
|
|
13
|
+
*/
|
|
14
|
+
export declare const INSTALL_STAGE_KCI_SOURCES: readonly InstallStageKciSource[];
|
|
15
|
+
export interface InstallStageReasonCodeSpec {
|
|
16
|
+
readonly stageKey: string;
|
|
17
|
+
readonly stageName: string;
|
|
18
|
+
/** Distinct supplier KCI reasonCodes that drive entry into this stage. */
|
|
19
|
+
readonly expectedReasonCodes: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve `INSTALL_STAGE_KCI_SOURCES` rowIds → distinct reasonCodes via
|
|
23
|
+
* `KCI_EFFECT_ROWS`. Stages whose rowIds resolve to no reasonCode are
|
|
24
|
+
* dropped (matches the digest's `reasonSet.size === 0` skip).
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildInstallStageReasonCodeSpecs(): InstallStageReasonCodeSpec[];
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildInstallStageReasonCodeSpecs = exports.INSTALL_STAGE_KCI_SOURCES = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* INSTALL work-order stage → expected supplier-KCI reasonCode spec.
|
|
6
|
+
*
|
|
7
|
+
* The Install Fulfilment digest's "KCI audit by stage" needs, per INSTALL
|
|
8
|
+
* WO stage, the set of supplier KCI `reasonCode`s that legitimately drive
|
|
9
|
+
* entry into that stage. That mapping is a projection of the typed BP
|
|
10
|
+
* template `business-processes/install.ts` (agent-os authoring origin):
|
|
11
|
+
* for each stage, its `entryActions[].kciSource.rowId` resolved against
|
|
12
|
+
* `KCI_EFFECT_ROWS` (the canonical bridge catalog, already in this SDK).
|
|
13
|
+
*
|
|
14
|
+
* `INSTALL_STAGE_KCI_SOURCES` below is the frozen projection of
|
|
15
|
+
* `INSTALL_PROCESS.stages[].entryActions[].kciSource.rowId`, extracted
|
|
16
|
+
* mechanically from install.ts. If the BP rewires a stage's kciSource,
|
|
17
|
+
* regenerate this array (it is the published copy, not a re-derivation).
|
|
18
|
+
*
|
|
19
|
+
* `buildInstallStageReasonCodeSpecs()` resolves the rowIds → reasonCodes via
|
|
20
|
+
* `KCI_EFFECT_ROWS` so consumers never hand-map rowId→reasonCode themselves.
|
|
21
|
+
*/
|
|
22
|
+
const kci_effect_bridge_1 = require("./kci-effect-bridge");
|
|
23
|
+
/**
|
|
24
|
+
* Frozen projection of INSTALL_PROCESS.stages (install.ts) — only stages
|
|
25
|
+
* with at least one kciSource-bearing entryAction. Verified against the
|
|
26
|
+
* live BP on 2026-05-20.
|
|
27
|
+
*/
|
|
28
|
+
exports.INSTALL_STAGE_KCI_SOURCES = [
|
|
29
|
+
{
|
|
30
|
+
stageKey: 'WorkOrderStageScheduled',
|
|
31
|
+
stageName: 'Scheduled',
|
|
32
|
+
kciSourceRowIds: ['provide-reappointed', 'provide-amended'],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
stageKey: 'WorkOrderStageEnRoute',
|
|
36
|
+
stageName: 'En Route',
|
|
37
|
+
kciSourceRowIds: ['provide-update-install-en-route'],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
stageKey: 'WorkOrderStageInProgress',
|
|
41
|
+
stageName: 'In Progress',
|
|
42
|
+
kciSourceRowIds: ['provide-update-install-in-progress', 'provide-resolved'],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
stageKey: 'WorkOrderRemediationRequired',
|
|
46
|
+
stageName: 'Remediation Required',
|
|
47
|
+
kciSourceRowIds: ['provide-delay'],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
stageKey: 'CustomerWorkOrdersStagePending',
|
|
51
|
+
stageName: 'Pending',
|
|
52
|
+
kciSourceRowIds: [
|
|
53
|
+
'provide-information-required',
|
|
54
|
+
'provide-contact-customer',
|
|
55
|
+
'provide-contact-reappoint',
|
|
56
|
+
'provide-reappoint',
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
stageKey: 'WorkOrderStageDone',
|
|
61
|
+
stageName: 'Done',
|
|
62
|
+
kciSourceRowIds: ['provide-completed', 'provide-partial'],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
stageKey: 'WorkOrderStageCancelled',
|
|
66
|
+
stageName: 'Cancelled',
|
|
67
|
+
kciSourceRowIds: [
|
|
68
|
+
'provide-cancelled',
|
|
69
|
+
'provide-failed',
|
|
70
|
+
'provide-rejected',
|
|
71
|
+
'provide-order-rejected',
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
/**
|
|
76
|
+
* Resolve `INSTALL_STAGE_KCI_SOURCES` rowIds → distinct reasonCodes via
|
|
77
|
+
* `KCI_EFFECT_ROWS`. Stages whose rowIds resolve to no reasonCode are
|
|
78
|
+
* dropped (matches the digest's `reasonSet.size === 0` skip).
|
|
79
|
+
*/
|
|
80
|
+
function buildInstallStageReasonCodeSpecs() {
|
|
81
|
+
const rowIdToReason = new Map();
|
|
82
|
+
for (const r of kci_effect_bridge_1.KCI_EFFECT_ROWS)
|
|
83
|
+
rowIdToReason.set(r.id, r.reasonCode);
|
|
84
|
+
const out = [];
|
|
85
|
+
for (const stage of exports.INSTALL_STAGE_KCI_SOURCES) {
|
|
86
|
+
const reasonSet = new Set();
|
|
87
|
+
for (const rowId of stage.kciSourceRowIds) {
|
|
88
|
+
const rc = rowIdToReason.get(rowId);
|
|
89
|
+
if (rc)
|
|
90
|
+
reasonSet.add(rc);
|
|
91
|
+
}
|
|
92
|
+
if (reasonSet.size === 0)
|
|
93
|
+
continue;
|
|
94
|
+
out.push({
|
|
95
|
+
stageKey: stage.stageKey,
|
|
96
|
+
stageName: stage.stageName,
|
|
97
|
+
expectedReasonCodes: [...reasonSet],
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
exports.buildInstallStageReasonCodeSpecs = buildInstallStageReasonCodeSpecs;
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* full types are available).
|
|
31
31
|
*/
|
|
32
32
|
import type { VMO2OrderNotification, VMO2SMRNotification } from './types/vmo2';
|
|
33
|
-
import type { FibreCafeServiceAvailability200, FibreCafeAvailableAppointments200, FibreCafeReserveAppointment201, FibreCafeScheduleServiceWorkOrder201, FibreCafeRescheduleServiceWorkOrder200, FibreCafeOrderCreate202, FibreCafeOrderAmendAccept202, FibreCafeKciDto } from './types/fibrecafe';
|
|
33
|
+
import type { FibreCafeServiceAvailability200, FibreCafeAvailableAppointments200, FibreCafeReserveAppointment201, FibreCafeScheduleServiceWorkOrder201, FibreCafeRescheduleServiceWorkOrder200, FibreCafeOrderCreate202, FibreCafeOrderAmendAccept202, FibreCafeKciDto, FibreCafeServiceProblemCancellationReasonCode } from './types/fibrecafe';
|
|
34
34
|
/**
|
|
35
35
|
* Reasons a cancellation request can be made (NET wire-level enum value
|
|
36
36
|
* passed through to the FibreCafe gateway).
|
|
@@ -107,6 +107,33 @@ export interface UpdateOrderExternalRefArgs {
|
|
|
107
107
|
oldYfId: string;
|
|
108
108
|
newYfId: string;
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Args for the tenant-initiated cancellation of an inflight SERVICE WO
|
|
112
|
+
* (REPAIR). Structurally identical to `RescheduleServiceWorkOrderArgs` —
|
|
113
|
+
* cancel is the same action shape as reschedule, just a terminal
|
|
114
|
+
* transition instead of a slot move. Same flat primitive fields; only
|
|
115
|
+
* delta is `reasonCode` in place of the timeslot fields (mirrors how
|
|
116
|
+
* `cancelOrder` carries a `reasonCode` while `createOrder` doesn't).
|
|
117
|
+
*
|
|
118
|
+
* The provider impl posts to
|
|
119
|
+
* `POST /WholesaleGateway/v1.0/gateway/service-work-orders/cancel`. NET
|
|
120
|
+
* looks up its SERVICE WO by `externalId = yfWorkOrderId` (NET stamps
|
|
121
|
+
* the YF WO uuid as externalId at create time per
|
|
122
|
+
* `scheduleServiceWorkOrder`), then drives the NET WO to Cancelled via
|
|
123
|
+
* NET field-service `/cancel-action-apply` with a tenant-originated
|
|
124
|
+
* ChangeReason. The existing SERVICE WO stage-update handler emits the
|
|
125
|
+
* UPDATE+`NETOMNIA_SERVICE_WORK_ORDER_CANCELLED` KCI back to YF.
|
|
126
|
+
*
|
|
127
|
+
* YF only commits its own SERVICE WO → Cancelled transition after this
|
|
128
|
+
* call resolves successfully (NET-first semantics — see
|
|
129
|
+
* `CancelServiceWorkOrderTenantService` in field-service module).
|
|
130
|
+
*/
|
|
131
|
+
export interface CancelServiceWorkOrderArgs {
|
|
132
|
+
yfWorkOrderId: string;
|
|
133
|
+
uprn: number;
|
|
134
|
+
yfOrderId: string;
|
|
135
|
+
reasonCode: FibreCafeServiceProblemCancellationReasonCode;
|
|
136
|
+
}
|
|
110
137
|
/**
|
|
111
138
|
* Capability-shaped interface to a wholesale supplier. Method NAMES align
|
|
112
139
|
* with VMO2 spec where it makes sense; ARGS match existing NET module
|
|
@@ -154,6 +181,20 @@ export interface WholesaleProvider<TPrincipal = unknown> {
|
|
|
154
181
|
cancelOrder(yfOrderId: string, reasonCode: CancellationReasonCode): Promise<FibreCafeOrderCreate202>;
|
|
155
182
|
/** Active-customer cease (post-Active churn / OTS-losing). */
|
|
156
183
|
ceaseOrder(yfOrderId: string, serviceId: string): Promise<FibreCafeOrderCreate202>;
|
|
184
|
+
/**
|
|
185
|
+
* Tenant-initiated cancel of an inflight SERVICE WO. Structurally
|
|
186
|
+
* parallel to `rescheduleServiceWorkOrder` — same flat-primitive args,
|
|
187
|
+
* same response envelope shape, just a terminal transition instead of
|
|
188
|
+
* a slot move.
|
|
189
|
+
*
|
|
190
|
+
* **YF must NOT transition its SERVICE WO to Cancelled until this call
|
|
191
|
+
* resolves successfully** — the call site (`CancelServiceWorkOrderTenant
|
|
192
|
+
* Service` in field-service module) is responsible for gating the YF
|
|
193
|
+
* stage change on the response. The inbound UPDATE+CANCELLED KCI from
|
|
194
|
+
* NET (walker row `repair-update-service-cancelled`) is the secondary
|
|
195
|
+
* cure when YF didn't already advance.
|
|
196
|
+
*/
|
|
197
|
+
cancelServiceWorkOrder(args: CancelServiceWorkOrderArgs): Promise<FibreCafeRescheduleServiceWorkOrder200>;
|
|
157
198
|
/**
|
|
158
199
|
* Inbound supplier KCI handler — the ONE inbound channel from supplier
|
|
159
200
|
* to YF. KCIs drive (a) OrderKci persistence and (b) WO state changes
|
|
@@ -24,7 +24,25 @@
|
|
|
24
24
|
* Linked: T-20260508-010 Step 3 followup (receiveKci 100% typed + handled).
|
|
25
25
|
*/
|
|
26
26
|
import type { FibreCafeKciDto, FibreCafeKciReasonCode } from './types/fibrecafe';
|
|
27
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Discriminator for the BUSINESS KIND of a KCI — not the wire envelope shape.
|
|
29
|
+
*
|
|
30
|
+
* PROVIDE / CEASE / MODIFY / UNSOLICITED_CEASE — typed by the populated
|
|
31
|
+
* sub-body field on the FibreCafe envelope (`provideServiceOrder` etc.).
|
|
32
|
+
*
|
|
33
|
+
* REPAIR — SERVICE WorkOrder state changes. NET emits these on the parent
|
|
34
|
+
* PROVIDE envelope (the SERVICE WO is a child of the PROVIDE order in
|
|
35
|
+
* the data model) but the semantic kind is REPAIR, discriminated by a
|
|
36
|
+
* `NETOMNIA_SERVICE_WORK_ORDER_*` value in `supplierCodes[]`. The
|
|
37
|
+
* envelope wire shape is a data-model artifact; the BP vocabulary is
|
|
38
|
+
* what consumers reason about (SERVICE WO = repair / service visit).
|
|
39
|
+
*
|
|
40
|
+
* `detectKciKind()` returns REPAIR when ANY supplier code matches the
|
|
41
|
+
* `NETOMNIA_SERVICE_WORK_ORDER_*` prefix, taking precedence over the
|
|
42
|
+
* envelope-field-based PROVIDE detection so service-WO KCIs route to the
|
|
43
|
+
* REPAIR-marked bridge rows.
|
|
44
|
+
*/
|
|
45
|
+
export declare type KciServiceOrderKind = 'PROVIDE' | 'CEASE' | 'MODIFY' | 'UNSOLICITED_CEASE' | 'REPAIR';
|
|
28
46
|
export declare type YfKciEffectKind = 'LOG_KCI_ONLY' | 'WO_FLOW_ACTION' | 'WO_SCHEDULE_APPOINTMENT' | 'PROPERTY_WRITE' | 'NO_OP_DOCUMENTED';
|
|
29
47
|
export declare type YfKciTargetEntity = 'OrderModule:Order' | 'CrmModule:Address' | 'FieldServiceModule:WorkOrder';
|
|
30
48
|
/**
|
|
@@ -321,11 +321,19 @@ exports.KCI_EFFECT_ROWS = [
|
|
|
321
321
|
},
|
|
322
322
|
logAgainstOrder: true,
|
|
323
323
|
},
|
|
324
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
324
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
325
|
+
// REPAIR — SERVICE WO state changes (post-install fault / service visit)
|
|
326
|
+
//
|
|
327
|
+
// NET emits these on the parent PROVIDE envelope (data-model artifact:
|
|
328
|
+
// SERVICE WO is a child of the PROVIDE order). The semantic kind is
|
|
329
|
+
// REPAIR — discriminated by a `NETOMNIA_SERVICE_WORK_ORDER_*` value in
|
|
330
|
+
// `supplierCodes[]`. `detectKciKind()` recognises that prefix and
|
|
331
|
+
// returns REPAIR ahead of the envelope-field-based PROVIDE detection.
|
|
332
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
333
|
+
{
|
|
334
|
+
id: 'repair-update-service-scheduled',
|
|
327
335
|
reasonCode: 'UPDATE',
|
|
328
|
-
serviceOrderKind: '
|
|
336
|
+
serviceOrderKind: 'REPAIR',
|
|
329
337
|
supplierCodes: ['NETOMNIA_SERVICE_WORK_ORDER_SCHEDULED'],
|
|
330
338
|
yfEffect: {
|
|
331
339
|
kind: 'LOG_KCI_ONLY',
|
|
@@ -334,9 +342,9 @@ exports.KCI_EFFECT_ROWS = [
|
|
|
334
342
|
logAgainstOrder: true,
|
|
335
343
|
},
|
|
336
344
|
{
|
|
337
|
-
id: '
|
|
345
|
+
id: 'repair-update-service-en-route',
|
|
338
346
|
reasonCode: 'UPDATE',
|
|
339
|
-
serviceOrderKind: '
|
|
347
|
+
serviceOrderKind: 'REPAIR',
|
|
340
348
|
supplierCodes: ['NETOMNIA_SERVICE_WORK_ORDER_EN_ROUTE'],
|
|
341
349
|
yfEffect: {
|
|
342
350
|
kind: 'WO_FLOW_ACTION',
|
|
@@ -346,9 +354,9 @@ exports.KCI_EFFECT_ROWS = [
|
|
|
346
354
|
logAgainstOrder: true,
|
|
347
355
|
},
|
|
348
356
|
{
|
|
349
|
-
id: '
|
|
357
|
+
id: 'repair-update-service-in-progress',
|
|
350
358
|
reasonCode: 'UPDATE',
|
|
351
|
-
serviceOrderKind: '
|
|
359
|
+
serviceOrderKind: 'REPAIR',
|
|
352
360
|
supplierCodes: ['NETOMNIA_SERVICE_WORK_ORDER_IN_PROGRESS'],
|
|
353
361
|
yfEffect: {
|
|
354
362
|
kind: 'WO_FLOW_ACTION',
|
|
@@ -448,12 +456,38 @@ exports.KCI_EFFECT_ROWS = [
|
|
|
448
456
|
},
|
|
449
457
|
logAgainstOrder: true,
|
|
450
458
|
},
|
|
459
|
+
// SERVICE-WO cancel — same REPAIR-kind UPDATE-with-supplierCode pattern
|
|
460
|
+
// as the scheduled / en-route / in-progress rows above. NET enum value:
|
|
461
|
+
// NETOMNIA_SERVICE_WORK_ORDER_CANCELLED (netomnia-supplier-code.enum.ts).
|
|
462
|
+
// Dispatcher resolves the cancel semanticOp per WO.type —
|
|
463
|
+
// SERVICE → CancelServiceWorkOrderFlowSupplier.
|
|
464
|
+
{
|
|
465
|
+
id: 'repair-update-service-cancelled',
|
|
466
|
+
reasonCode: 'UPDATE',
|
|
467
|
+
serviceOrderKind: 'REPAIR',
|
|
468
|
+
supplierCodes: ['NETOMNIA_SERVICE_WORK_ORDER_CANCELLED'],
|
|
469
|
+
yfEffect: {
|
|
470
|
+
kind: 'WO_FLOW_ACTION',
|
|
471
|
+
semanticOp: 'cancel',
|
|
472
|
+
notes: 'SERVICE WO cancelled by supplier — advance YF SERVICE WO Accepted/Scheduled/EnRoute/InProgress → Cancelled via CancelServiceWorkOrderFlowSupplier. Also the inbound confirmation when YF tenant-initiated the cancel via /WholesaleGateway/v1.0/gateway/service-work-orders/cancel; YF WO usually already at Cancelled, action is idempotent on the WO stage.',
|
|
473
|
+
},
|
|
474
|
+
logAgainstOrder: true,
|
|
475
|
+
},
|
|
451
476
|
];
|
|
452
477
|
/**
|
|
453
478
|
* Determine which serviceOrder kind the KCI is about by inspecting which
|
|
454
479
|
* sub-body field is populated.
|
|
455
480
|
*/
|
|
456
481
|
function detectKciKind(dto) {
|
|
482
|
+
var _a;
|
|
483
|
+
// REPAIR check first — SERVICE WO state changes use the NETOMNIA_SERVICE_
|
|
484
|
+
// WORK_ORDER_* supplier-code discriminator, regardless of which sub-body
|
|
485
|
+
// field is populated (it's typically `provideServiceOrder` because the
|
|
486
|
+
// SERVICE WO is a child of a PROVIDE order in the data model).
|
|
487
|
+
const codes = (_a = dto.supplierCodes) !== null && _a !== void 0 ? _a : [];
|
|
488
|
+
if (codes.some((c) => c.startsWith('NETOMNIA_SERVICE_WORK_ORDER_'))) {
|
|
489
|
+
return 'REPAIR';
|
|
490
|
+
}
|
|
457
491
|
if (dto.provideServiceOrder)
|
|
458
492
|
return 'PROVIDE';
|
|
459
493
|
if (dto.ceaseServiceOrder)
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* invokes `dispatchOrderNotification` / `dispatchSMRNotification` after
|
|
28
28
|
* envelope-mapping; registered handlers are fanned out.
|
|
29
29
|
*/
|
|
30
|
-
import type { WholesaleProvider, CreateOrderOptions, CancellationReasonCode, ReserveAppointmentArgs, ListAppointmentsArgs, ScheduleServiceWorkOrderArgs, RescheduleServiceWorkOrderArgs, AmendAppointmentArgs, SyncWorkOrderToSupplierArgs, UpdateOrderExternalRefArgs } from '../interface';
|
|
30
|
+
import type { WholesaleProvider, CreateOrderOptions, CancellationReasonCode, CancelServiceWorkOrderArgs, ReserveAppointmentArgs, ListAppointmentsArgs, ScheduleServiceWorkOrderArgs, RescheduleServiceWorkOrderArgs, AmendAppointmentArgs, SyncWorkOrderToSupplierArgs, UpdateOrderExternalRefArgs } from '../interface';
|
|
31
31
|
import type { VMO2OrderNotification, VMO2SMRNotification } from '../types/vmo2';
|
|
32
32
|
import type { FibreCafeServiceAvailability200, FibreCafeAvailableAppointments200, FibreCafeReserveAppointment201, FibreCafeScheduleServiceWorkOrder201, FibreCafeRescheduleServiceWorkOrder200, FibreCafeOrderCreate202, FibreCafeOrderAmendAccept202, FibreCafeKciDto } from '../types/fibrecafe';
|
|
33
33
|
/**
|
|
@@ -60,6 +60,7 @@ export interface NetomniaProviderDeps<TPrincipal = unknown, TKci = FibreCafeKciD
|
|
|
60
60
|
amendOrder: (principal: TPrincipal, yfOrderId: string) => Promise<FibreCafeOrderCreate202 | null>;
|
|
61
61
|
cancelOrder: (yfOrderId: string, reasonCode: CancellationReasonCode) => Promise<FibreCafeOrderCreate202>;
|
|
62
62
|
ceaseOrder: (yfOrderId: string, serviceId: string) => Promise<FibreCafeOrderCreate202>;
|
|
63
|
+
cancelServiceWorkOrder: (args: CancelServiceWorkOrderArgs) => Promise<FibreCafeRescheduleServiceWorkOrder200>;
|
|
63
64
|
receiveKci: (principal: TPrincipal, dto: FibreCafeKciDto) => Promise<void>;
|
|
64
65
|
syncWorkOrderToSupplier: (args: SyncWorkOrderToSupplierArgs<TPrincipal>) => Promise<void>;
|
|
65
66
|
retrieveServiceIdByUprn: (uprn: number) => Promise<string | null>;
|
|
@@ -82,6 +83,7 @@ export declare class NetomniaProvider<TPrincipal = unknown> implements Wholesale
|
|
|
82
83
|
amendOrder(principal: TPrincipal, yfOrderId: string): Promise<FibreCafeOrderCreate202>;
|
|
83
84
|
cancelOrder(yfOrderId: string, reasonCode: CancellationReasonCode): Promise<FibreCafeOrderCreate202>;
|
|
84
85
|
ceaseOrder(yfOrderId: string, serviceId: string): Promise<FibreCafeOrderCreate202>;
|
|
86
|
+
cancelServiceWorkOrder(args: CancelServiceWorkOrderArgs): Promise<FibreCafeRescheduleServiceWorkOrder200>;
|
|
85
87
|
receiveKci(principal: TPrincipal, dto: FibreCafeKciDto): Promise<void>;
|
|
86
88
|
syncWorkOrderToSupplier(args: SyncWorkOrderToSupplierArgs<TPrincipal>): Promise<void>;
|
|
87
89
|
retrieveServiceIdByUprn(uprn: number): Promise<string>;
|
|
@@ -47,6 +47,9 @@ class NetomniaProvider {
|
|
|
47
47
|
ceaseOrder(yfOrderId, serviceId) {
|
|
48
48
|
return this.deps.ceaseOrder(yfOrderId, serviceId);
|
|
49
49
|
}
|
|
50
|
+
cancelServiceWorkOrder(args) {
|
|
51
|
+
return this.deps.cancelServiceWorkOrder(args);
|
|
52
|
+
}
|
|
50
53
|
receiveKci(principal, dto) {
|
|
51
54
|
return this.deps.receiveKci(principal, dto);
|
|
52
55
|
}
|
|
@@ -71,6 +71,7 @@ function buildDeps() {
|
|
|
71
71
|
amendOrder: {},
|
|
72
72
|
cancelOrder: {},
|
|
73
73
|
ceaseOrder: {},
|
|
74
|
+
cancelServiceWorkOrder: { workOrderId: 'WO-CANC-1', appointmentId: '' },
|
|
74
75
|
};
|
|
75
76
|
const deps = {
|
|
76
77
|
searchAddress: (uprn) => {
|
|
@@ -113,6 +114,10 @@ function buildDeps() {
|
|
|
113
114
|
log.push({ method: 'ceaseOrder', args: [yfOrderId, serviceId] });
|
|
114
115
|
return Promise.resolve(stubs.ceaseOrder);
|
|
115
116
|
},
|
|
117
|
+
cancelServiceWorkOrder: (args) => {
|
|
118
|
+
log.push({ method: 'cancelServiceWorkOrder', args: [args] });
|
|
119
|
+
return Promise.resolve(stubs.cancelServiceWorkOrder);
|
|
120
|
+
},
|
|
116
121
|
receiveKci: (principal, dto) => {
|
|
117
122
|
log.push({ method: 'receiveKci', args: [principal, dto] });
|
|
118
123
|
return Promise.resolve();
|
|
@@ -430,6 +430,21 @@ export interface FibreCafeModifyServiceOrder {
|
|
|
430
430
|
serviceOrderCancellationId?: string | number;
|
|
431
431
|
serviceOrderCancellationReference?: string;
|
|
432
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Codes representing the reason for cancelling an inflight service problem
|
|
435
|
+
* (FibreCafe `POST /service-problem-cancellations` request body). Used on
|
|
436
|
+
* the OUTBOUND (YF → NET) side for the tenant-initiated SERVICE WO cancel.
|
|
437
|
+
*
|
|
438
|
+
* The corresponding INBOUND state-change (NET → YF) confirming the
|
|
439
|
+
* cancellation is emitted by NET as an `UPDATE` KCI with
|
|
440
|
+
* `supplierCodes: [NETOMNIA_SERVICE_WORK_ORDER_CANCELLED]` — see the
|
|
441
|
+
* `provide-update-service-cancelled` row in kci-effect-bridge.ts.
|
|
442
|
+
*
|
|
443
|
+
* Mirrors NET's `ServiceProblemCancellationReasonCode` enum verbatim.
|
|
444
|
+
*
|
|
445
|
+
* @see {@link https://docs.thefibrecafe.net/openapi/supplier/operation/handleCancelProblem/#!path=reasonCode&t=request | FibreCafe ServiceProblemCancellationReasonCode}
|
|
446
|
+
*/
|
|
447
|
+
export declare type FibreCafeServiceProblemCancellationReasonCode = 'ISSUE_RESOLVED' | 'CUSTOMER_NETWORK_ISSUE' | 'NO_LONGER_REQUIRED' | 'OTHER';
|
|
433
448
|
/** Unsolicited cease — supplier-initiated, surfaced via KCI. */
|
|
434
449
|
export interface FibreCafeUnsolicitedCeaseServiceOrder {
|
|
435
450
|
orderType?: FibreCafeCeaseOrderType;
|