@d19n/youfibre-odin-sdk 2.0.103-beta.7 → 2.0.103-beta.9
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.
|
@@ -1,4 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WholesaleProvider — strategy-dispatchable interface for wholesale supplier
|
|
3
|
+
* integrations (Netomnia today, VMO2 from July 2026).
|
|
4
|
+
*
|
|
5
|
+
* **Architecture (T-20260508-009/010 — confirmed with Frank 2026-05-09 as
|
|
6
|
+
* "Path B / first step"):**
|
|
7
|
+
*
|
|
8
|
+
* Methods take YF-context arguments (orderId, principal, etc.) — matching
|
|
9
|
+
* the existing NET module method signatures. Each provider implementation
|
|
10
|
+
* builds the supplier-specific wire request internally from this YF context.
|
|
11
|
+
*
|
|
12
|
+
* Rationale:
|
|
13
|
+
* - Existing NET module methods take YF context, not wire DTOs. The SDK
|
|
14
|
+
* provider abstracts the supplier dispatch layer, not the DTO-building.
|
|
15
|
+
* - Method names align with VMO2 spec where it makes sense (`createOrder`,
|
|
16
|
+
* `cancelOrder`, etc.) so call-site vocabulary doesn't change when the
|
|
17
|
+
* provider switches.
|
|
18
|
+
* - When VMO2 ships, Vmo2Provider implements the same method names with
|
|
19
|
+
* args that may differ slightly. Frank's framing: "we adjust function
|
|
20
|
+
* arguments, nothing beyond that — we map X to Y and get the same result."
|
|
21
|
+
*
|
|
22
|
+
* **Trade-off accepted:** the interface is shaped after NET reality, not
|
|
23
|
+
* VMO2. That keeps Phase 0 a strict drop-in replacement. We can standardize
|
|
24
|
+
* args further once VMO2 ships if a tighter cross-provider abstraction
|
|
25
|
+
* proves valuable.
|
|
26
|
+
*
|
|
27
|
+
* **Type pragmatics:** principal/options/return values use `unknown` /
|
|
28
|
+
* `Record<string, unknown>` so the SDK doesn't need to depend on
|
|
29
|
+
* NestJS-decorated entity types. Modules cast at the wiring boundary (where
|
|
30
|
+
* full types are available).
|
|
31
|
+
*/
|
|
1
32
|
import type { VMO2OrderNotification, VMO2SMRNotification } from './types/vmo2';
|
|
33
|
+
import type { FibreCafeServiceAvailability200, FibreCafeAvailableAppointments200, FibreCafeReserveAppointment201, FibreCafeScheduleServiceWorkOrder201, FibreCafeRescheduleServiceWorkOrder200, FibreCafeOrderCreate202, FibreCafeOrderAmendAccept202, FibreCafeKciDto } from './types/fibrecafe';
|
|
34
|
+
import type { OrderRecord } from '../records-v2/OrderRecord';
|
|
2
35
|
/**
|
|
3
36
|
* Reasons a cancellation request can be made (NET wire-level enum value
|
|
4
37
|
* passed through to the FibreCafe gateway).
|
|
@@ -23,6 +56,7 @@ export interface ReserveAppointmentArgs {
|
|
|
23
56
|
ServiceCallReason?: string;
|
|
24
57
|
WorkOrderExternalReference?: string;
|
|
25
58
|
};
|
|
59
|
+
flow: 'FIRST_TIME_BOOKING' | 'RESCHEDULE';
|
|
26
60
|
}
|
|
27
61
|
export interface ListAppointmentsArgs {
|
|
28
62
|
uprn: number;
|
|
@@ -52,8 +86,8 @@ export interface AmendAppointmentArgs {
|
|
|
52
86
|
yfWorkOrderId: string;
|
|
53
87
|
supplierAppointmentReference: string;
|
|
54
88
|
}
|
|
55
|
-
export interface SyncWorkOrderToSupplierArgs {
|
|
56
|
-
principal:
|
|
89
|
+
export interface SyncWorkOrderToSupplierArgs<TPrincipal = unknown> {
|
|
90
|
+
principal: TPrincipal;
|
|
57
91
|
yfOrderId: string;
|
|
58
92
|
yfWorkOrderId: string;
|
|
59
93
|
yfChangeReason: {
|
|
@@ -63,6 +97,14 @@ export interface SyncWorkOrderToSupplierArgs {
|
|
|
63
97
|
type: unknown;
|
|
64
98
|
properties: unknown;
|
|
65
99
|
};
|
|
100
|
+
yfServiceAppointment: {
|
|
101
|
+
id?: string;
|
|
102
|
+
properties: {
|
|
103
|
+
Date?: string;
|
|
104
|
+
TimeBlock?: string;
|
|
105
|
+
[extra: string]: unknown;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
66
108
|
}
|
|
67
109
|
export interface UpdateOrderExternalRefArgs {
|
|
68
110
|
oldYfId: string;
|
|
@@ -77,26 +119,41 @@ export interface UpdateOrderExternalRefArgs {
|
|
|
77
119
|
* Returns are typed loosely — modules know the return shape via the dep
|
|
78
120
|
* function they wire in.
|
|
79
121
|
*/
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Generic in `TPrincipal` so call sites get full typing on the user/org
|
|
124
|
+
* principal that NestJS injects via the `@Principal()` decorator. Modules
|
|
125
|
+
* specialize at the wiring boundary:
|
|
126
|
+
*
|
|
127
|
+
* ```ts
|
|
128
|
+
* class WholesaleProviderFactory {
|
|
129
|
+
* constructor(@Inject(...) private netomnia: WholesaleProvider<OrganizationUserEntity>) {}
|
|
130
|
+
* get(...): WholesaleProvider<OrganizationUserEntity> { ... }
|
|
131
|
+
* }
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* Default `TPrincipal = unknown` lets the SDK compile standalone without
|
|
135
|
+
* tenant-specific type imports.
|
|
136
|
+
*/
|
|
137
|
+
export interface WholesaleProvider<TPrincipal = unknown> {
|
|
138
|
+
searchAddress(uprn: number): Promise<FibreCafeServiceAvailability200>;
|
|
139
|
+
listAppointments(args: ListAppointmentsArgs): Promise<FibreCafeAvailableAppointments200>;
|
|
140
|
+
reserveAppointment(args: ReserveAppointmentArgs): Promise<FibreCafeReserveAppointment201>;
|
|
141
|
+
scheduleServiceWorkOrder(args: ScheduleServiceWorkOrderArgs): Promise<FibreCafeScheduleServiceWorkOrder201>;
|
|
142
|
+
rescheduleServiceWorkOrder(args: RescheduleServiceWorkOrderArgs): Promise<FibreCafeRescheduleServiceWorkOrder200>;
|
|
143
|
+
amendAppointment(args: AmendAppointmentArgs): Promise<FibreCafeOrderAmendAccept202>;
|
|
144
|
+
createOrder(principal: TPrincipal, orderId: string, options?: CreateOrderOptions): Promise<FibreCafeOrderCreate202>;
|
|
145
|
+
/** Tier-change CoS — wraps `createModifyOrderForYfOrder` style args. Returns null when already at target SKU. */
|
|
146
|
+
amendOrder(principal: TPrincipal, yfOrderId: string): Promise<FibreCafeOrderCreate202 | null>;
|
|
90
147
|
/** Pre-install cancel of an in-flight provide order. */
|
|
91
|
-
cancelOrder(yfOrderId: string, reasonCode: CancellationReasonCode): Promise<
|
|
148
|
+
cancelOrder(yfOrderId: string, reasonCode: CancellationReasonCode): Promise<FibreCafeOrderCreate202>;
|
|
92
149
|
/** Active-customer cease (post-Active churn / OTS-losing). */
|
|
93
|
-
ceaseOrder(yfOrderId: string, serviceId: string): Promise<
|
|
150
|
+
ceaseOrder(yfOrderId: string, serviceId: string): Promise<FibreCafeOrderCreate202>;
|
|
94
151
|
/** Inbound supplier KCI / notification handler. */
|
|
95
|
-
receiveKci(principal:
|
|
152
|
+
receiveKci(principal: TPrincipal, dto: FibreCafeKciDto): Promise<void>;
|
|
96
153
|
/** Outbound YF→supplier WO sync (cancel propagation, etc.). */
|
|
97
|
-
syncWorkOrderToSupplier(args: SyncWorkOrderToSupplierArgs): Promise<
|
|
154
|
+
syncWorkOrderToSupplier(args: SyncWorkOrderToSupplierArgs<TPrincipal>): Promise<void>;
|
|
98
155
|
/** Inbound supplier→YF WO change application (post-receiveKci). */
|
|
99
|
-
syncWorkOrderFromSupplier(order:
|
|
156
|
+
syncWorkOrderFromSupplier(order: OrderRecord, dto: FibreCafeKciDto): Promise<void>;
|
|
100
157
|
retrieveServiceIdByUprn(uprn: number): Promise<string | null>;
|
|
101
158
|
updateOrderExternalRef(args: UpdateOrderExternalRefArgs): Promise<void>;
|
|
102
159
|
/**
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import type { WholesaleProvider, CreateOrderOptions, CancellationReasonCode, ReserveAppointmentArgs, ListAppointmentsArgs, ScheduleServiceWorkOrderArgs, RescheduleServiceWorkOrderArgs, AmendAppointmentArgs, SyncWorkOrderToSupplierArgs, UpdateOrderExternalRefArgs } from '../interface';
|
|
31
31
|
import type { VMO2OrderNotification, VMO2SMRNotification } from '../types/vmo2';
|
|
32
|
+
import type { FibreCafeServiceAvailability200, FibreCafeAvailableAppointments200, FibreCafeReserveAppointment201, FibreCafeScheduleServiceWorkOrder201, FibreCafeRescheduleServiceWorkOrder200, FibreCafeOrderCreate202, FibreCafeOrderAmendAccept202, FibreCafeKciDto } from '../types/fibrecafe';
|
|
33
|
+
import type { OrderRecord } from '../../records-v2/OrderRecord';
|
|
32
34
|
/**
|
|
33
35
|
* Function-bag of dependencies the NetomniaProvider delegates to.
|
|
34
36
|
*
|
|
@@ -48,43 +50,43 @@ import type { VMO2OrderNotification, VMO2SMRNotification } from '../types/vmo2';
|
|
|
48
50
|
* }
|
|
49
51
|
* ```
|
|
50
52
|
*/
|
|
51
|
-
export interface NetomniaProviderDeps {
|
|
52
|
-
searchAddress: (uprn: number) => Promise<
|
|
53
|
-
listAppointments: (args: ListAppointmentsArgs) => Promise<
|
|
54
|
-
reserveAppointment: (args: ReserveAppointmentArgs) => Promise<
|
|
55
|
-
scheduleServiceWorkOrder: (args: ScheduleServiceWorkOrderArgs) => Promise<
|
|
56
|
-
rescheduleServiceWorkOrder: (args: RescheduleServiceWorkOrderArgs) => Promise<
|
|
57
|
-
amendAppointment: (args: AmendAppointmentArgs) => Promise<
|
|
58
|
-
createOrder: (principal:
|
|
59
|
-
amendOrder: (principal:
|
|
60
|
-
cancelOrder: (yfOrderId: string, reasonCode: CancellationReasonCode) => Promise<
|
|
61
|
-
ceaseOrder: (yfOrderId: string, serviceId: string) => Promise<
|
|
62
|
-
receiveKci: (principal:
|
|
63
|
-
syncWorkOrderToSupplier: (args: SyncWorkOrderToSupplierArgs) => Promise<
|
|
64
|
-
syncWorkOrderFromSupplier: (order:
|
|
53
|
+
export interface NetomniaProviderDeps<TPrincipal = unknown> {
|
|
54
|
+
searchAddress: (uprn: number) => Promise<FibreCafeServiceAvailability200>;
|
|
55
|
+
listAppointments: (args: ListAppointmentsArgs) => Promise<FibreCafeAvailableAppointments200>;
|
|
56
|
+
reserveAppointment: (args: ReserveAppointmentArgs) => Promise<FibreCafeReserveAppointment201>;
|
|
57
|
+
scheduleServiceWorkOrder: (args: ScheduleServiceWorkOrderArgs) => Promise<FibreCafeScheduleServiceWorkOrder201>;
|
|
58
|
+
rescheduleServiceWorkOrder: (args: RescheduleServiceWorkOrderArgs) => Promise<FibreCafeRescheduleServiceWorkOrder200>;
|
|
59
|
+
amendAppointment: (args: AmendAppointmentArgs) => Promise<FibreCafeOrderAmendAccept202>;
|
|
60
|
+
createOrder: (principal: TPrincipal, orderId: string, options?: CreateOrderOptions) => Promise<FibreCafeOrderCreate202>;
|
|
61
|
+
amendOrder: (principal: TPrincipal, yfOrderId: string) => Promise<FibreCafeOrderCreate202 | null>;
|
|
62
|
+
cancelOrder: (yfOrderId: string, reasonCode: CancellationReasonCode) => Promise<FibreCafeOrderCreate202>;
|
|
63
|
+
ceaseOrder: (yfOrderId: string, serviceId: string) => Promise<FibreCafeOrderCreate202>;
|
|
64
|
+
receiveKci: (principal: TPrincipal, dto: FibreCafeKciDto) => Promise<void>;
|
|
65
|
+
syncWorkOrderToSupplier: (args: SyncWorkOrderToSupplierArgs<TPrincipal>) => Promise<void>;
|
|
66
|
+
syncWorkOrderFromSupplier: (order: OrderRecord, dto: FibreCafeKciDto) => Promise<void>;
|
|
65
67
|
retrieveServiceIdByUprn: (uprn: number) => Promise<string | null>;
|
|
66
68
|
updateOrderExternalRef: (args: UpdateOrderExternalRefArgs) => Promise<void>;
|
|
67
69
|
}
|
|
68
70
|
declare type OrderNotificationHandler = (n: VMO2OrderNotification) => Promise<void>;
|
|
69
71
|
declare type SMRNotificationHandler = (n: VMO2SMRNotification) => Promise<void>;
|
|
70
|
-
export declare class NetomniaProvider implements WholesaleProvider {
|
|
72
|
+
export declare class NetomniaProvider<TPrincipal = unknown> implements WholesaleProvider<TPrincipal> {
|
|
71
73
|
private readonly deps;
|
|
72
74
|
private readonly orderHandlers;
|
|
73
75
|
private readonly smrHandlers;
|
|
74
|
-
constructor(deps: NetomniaProviderDeps);
|
|
75
|
-
searchAddress(uprn: number): Promise<
|
|
76
|
-
listAppointments(args: ListAppointmentsArgs): Promise<
|
|
77
|
-
reserveAppointment(args: ReserveAppointmentArgs): Promise<
|
|
78
|
-
scheduleServiceWorkOrder(args: ScheduleServiceWorkOrderArgs): Promise<
|
|
79
|
-
rescheduleServiceWorkOrder(args: RescheduleServiceWorkOrderArgs): Promise<
|
|
80
|
-
amendAppointment(args: AmendAppointmentArgs): Promise<
|
|
81
|
-
createOrder(principal:
|
|
82
|
-
amendOrder(principal:
|
|
83
|
-
cancelOrder(yfOrderId: string, reasonCode: CancellationReasonCode): Promise<
|
|
84
|
-
ceaseOrder(yfOrderId: string, serviceId: string): Promise<
|
|
85
|
-
receiveKci(principal:
|
|
86
|
-
syncWorkOrderToSupplier(args: SyncWorkOrderToSupplierArgs): Promise<
|
|
87
|
-
syncWorkOrderFromSupplier(order:
|
|
76
|
+
constructor(deps: NetomniaProviderDeps<TPrincipal>);
|
|
77
|
+
searchAddress(uprn: number): Promise<FibreCafeServiceAvailability200>;
|
|
78
|
+
listAppointments(args: ListAppointmentsArgs): Promise<FibreCafeAvailableAppointments200>;
|
|
79
|
+
reserveAppointment(args: ReserveAppointmentArgs): Promise<FibreCafeReserveAppointment201>;
|
|
80
|
+
scheduleServiceWorkOrder(args: ScheduleServiceWorkOrderArgs): Promise<FibreCafeScheduleServiceWorkOrder201>;
|
|
81
|
+
rescheduleServiceWorkOrder(args: RescheduleServiceWorkOrderArgs): Promise<FibreCafeRescheduleServiceWorkOrder200>;
|
|
82
|
+
amendAppointment(args: AmendAppointmentArgs): Promise<FibreCafeOrderAmendAccept202>;
|
|
83
|
+
createOrder(principal: TPrincipal, orderId: string, options?: CreateOrderOptions): Promise<FibreCafeOrderCreate202>;
|
|
84
|
+
amendOrder(principal: TPrincipal, yfOrderId: string): Promise<FibreCafeOrderCreate202>;
|
|
85
|
+
cancelOrder(yfOrderId: string, reasonCode: CancellationReasonCode): Promise<FibreCafeOrderCreate202>;
|
|
86
|
+
ceaseOrder(yfOrderId: string, serviceId: string): Promise<FibreCafeOrderCreate202>;
|
|
87
|
+
receiveKci(principal: TPrincipal, dto: FibreCafeKciDto): Promise<void>;
|
|
88
|
+
syncWorkOrderToSupplier(args: SyncWorkOrderToSupplierArgs<TPrincipal>): Promise<void>;
|
|
89
|
+
syncWorkOrderFromSupplier(order: OrderRecord, dto: FibreCafeKciDto): Promise<void>;
|
|
88
90
|
retrieveServiceIdByUprn(uprn: number): Promise<string>;
|
|
89
91
|
updateOrderExternalRef(args: UpdateOrderExternalRefArgs): Promise<void>;
|
|
90
92
|
onOrderNotification(handler: OrderNotificationHandler): void;
|
|
@@ -43,69 +43,127 @@ function brand(s) {
|
|
|
43
43
|
return s;
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
46
|
+
* Stubs each dep with a typed canned return so the pass-through pattern
|
|
47
|
+
* can be tested via identity equality (`result === stubs.searchAddress`)
|
|
48
|
+
* without resorting to `as unknown` casts.
|
|
49
49
|
*/
|
|
50
50
|
function buildDeps() {
|
|
51
51
|
const log = [];
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
const stubs = {
|
|
53
|
+
searchAddress: {
|
|
54
|
+
address: { identifier: { id: 'UPRN-1', type: 'UPRN' } },
|
|
55
|
+
serviceSpecifications: [],
|
|
56
|
+
},
|
|
57
|
+
listAppointments: { availableTimeslots: [] },
|
|
58
|
+
reserveAppointment: {
|
|
59
|
+
id: 'A1',
|
|
60
|
+
supplierReference: 'NET-A1',
|
|
61
|
+
address: { id: 'X', type: 'UPRN' },
|
|
62
|
+
serviceSpecification: { id: 'fttp' },
|
|
63
|
+
timeslot: {
|
|
64
|
+
timeslotStartDateTime: '2026-06-01T08:00:00Z',
|
|
65
|
+
timeslotEndDateTime: '2026-06-01T13:00:00Z',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
scheduleServiceWorkOrder: { workOrderId: 'WO-1', appointmentId: 'APT-1' },
|
|
69
|
+
rescheduleServiceWorkOrder: { workOrderId: 'WO-1', appointmentId: 'APT-2' },
|
|
70
|
+
amendAppointment: {},
|
|
71
|
+
createOrder: {},
|
|
72
|
+
amendOrder: {},
|
|
73
|
+
cancelOrder: {},
|
|
74
|
+
ceaseOrder: {},
|
|
60
75
|
};
|
|
61
76
|
const deps = {
|
|
62
|
-
searchAddress:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
searchAddress: (uprn) => {
|
|
78
|
+
log.push({ method: 'searchAddress', args: [uprn] });
|
|
79
|
+
return Promise.resolve(stubs.searchAddress);
|
|
80
|
+
},
|
|
81
|
+
listAppointments: (args) => {
|
|
82
|
+
log.push({ method: 'listAppointments', args: [args] });
|
|
83
|
+
return Promise.resolve(stubs.listAppointments);
|
|
84
|
+
},
|
|
85
|
+
reserveAppointment: (args) => {
|
|
86
|
+
log.push({ method: 'reserveAppointment', args: [args] });
|
|
87
|
+
return Promise.resolve(stubs.reserveAppointment);
|
|
88
|
+
},
|
|
89
|
+
scheduleServiceWorkOrder: (args) => {
|
|
90
|
+
log.push({ method: 'scheduleServiceWorkOrder', args: [args] });
|
|
91
|
+
return Promise.resolve(stubs.scheduleServiceWorkOrder);
|
|
92
|
+
},
|
|
93
|
+
rescheduleServiceWorkOrder: (args) => {
|
|
94
|
+
log.push({ method: 'rescheduleServiceWorkOrder', args: [args] });
|
|
95
|
+
return Promise.resolve(stubs.rescheduleServiceWorkOrder);
|
|
96
|
+
},
|
|
97
|
+
amendAppointment: (args) => {
|
|
98
|
+
log.push({ method: 'amendAppointment', args: [args] });
|
|
99
|
+
return Promise.resolve(stubs.amendAppointment);
|
|
100
|
+
},
|
|
101
|
+
createOrder: (principal, orderId, options) => {
|
|
102
|
+
log.push({ method: 'createOrder', args: [principal, orderId, options] });
|
|
103
|
+
return Promise.resolve(stubs.createOrder);
|
|
104
|
+
},
|
|
105
|
+
amendOrder: (principal, yfOrderId) => {
|
|
106
|
+
log.push({ method: 'amendOrder', args: [principal, yfOrderId] });
|
|
107
|
+
return Promise.resolve(stubs.amendOrder);
|
|
108
|
+
},
|
|
109
|
+
cancelOrder: (yfOrderId, reasonCode) => {
|
|
110
|
+
log.push({ method: 'cancelOrder', args: [yfOrderId, reasonCode] });
|
|
111
|
+
return Promise.resolve(stubs.cancelOrder);
|
|
112
|
+
},
|
|
113
|
+
ceaseOrder: (yfOrderId, serviceId) => {
|
|
114
|
+
log.push({ method: 'ceaseOrder', args: [yfOrderId, serviceId] });
|
|
115
|
+
return Promise.resolve(stubs.ceaseOrder);
|
|
116
|
+
},
|
|
117
|
+
receiveKci: (principal, dto) => {
|
|
118
|
+
log.push({ method: 'receiveKci', args: [principal, dto] });
|
|
119
|
+
return Promise.resolve();
|
|
120
|
+
},
|
|
121
|
+
syncWorkOrderToSupplier: (args) => {
|
|
122
|
+
log.push({ method: 'syncWorkOrderToSupplier', args: [args] });
|
|
123
|
+
return Promise.resolve();
|
|
124
|
+
},
|
|
125
|
+
syncWorkOrderFromSupplier: (order, dto) => {
|
|
126
|
+
log.push({ method: 'syncWorkOrderFromSupplier', args: [order, dto] });
|
|
127
|
+
return Promise.resolve();
|
|
128
|
+
},
|
|
75
129
|
retrieveServiceIdByUprn: (uprn) => {
|
|
76
130
|
log.push({ method: 'retrieveServiceIdByUprn', args: [uprn] });
|
|
77
131
|
return Promise.resolve('NET-SVC-1');
|
|
78
132
|
},
|
|
79
|
-
updateOrderExternalRef:
|
|
133
|
+
updateOrderExternalRef: (args) => {
|
|
134
|
+
log.push({ method: 'updateOrderExternalRef', args: [args] });
|
|
135
|
+
return Promise.resolve();
|
|
136
|
+
},
|
|
80
137
|
};
|
|
81
|
-
return { deps, log,
|
|
138
|
+
return { deps, log, stubs };
|
|
82
139
|
}
|
|
83
140
|
function run() {
|
|
84
141
|
return __awaiter(this, void 0, void 0, function* () {
|
|
85
142
|
console.log('NetomniaProvider — pass-through delegation tests\n');
|
|
86
143
|
console.log('Test: searchAddress delegates to deps');
|
|
87
144
|
{
|
|
88
|
-
const { deps, log,
|
|
145
|
+
const { deps, log, stubs } = buildDeps();
|
|
89
146
|
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
90
147
|
const result = yield p.searchAddress(123);
|
|
91
148
|
assert('called once', log.length === 1);
|
|
92
149
|
assert('correct method', log[0].method === 'searchAddress');
|
|
93
150
|
assert('args forwarded', JSON.stringify(log[0].args) === JSON.stringify([123]));
|
|
94
|
-
assert('return forwarded', result ===
|
|
151
|
+
assert('return forwarded', result === stubs.searchAddress);
|
|
95
152
|
}
|
|
96
153
|
console.log('Test: listAppointments delegates to deps');
|
|
97
154
|
{
|
|
98
|
-
const { deps, log } = buildDeps();
|
|
155
|
+
const { deps, log, stubs } = buildDeps();
|
|
99
156
|
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
100
157
|
const args = { uprn: 123, start: '2026-06-01', appointmentPurpose: 'PROVIDE' };
|
|
101
|
-
yield p.listAppointments(args);
|
|
158
|
+
const result = yield p.listAppointments(args);
|
|
102
159
|
assert('called once', log.length === 1);
|
|
103
160
|
assert('correct method', log[0].method === 'listAppointments');
|
|
104
161
|
assert('args forwarded', log[0].args[0] === args);
|
|
162
|
+
assert('return forwarded', result === stubs.listAppointments);
|
|
105
163
|
}
|
|
106
164
|
console.log('Test: reserveAppointment delegates to deps');
|
|
107
165
|
{
|
|
108
|
-
const { deps, log } = buildDeps();
|
|
166
|
+
const { deps, log, stubs } = buildDeps();
|
|
109
167
|
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
110
168
|
const args = {
|
|
111
169
|
yfAppointmentId: 'APT-1',
|
|
@@ -115,11 +173,13 @@ function run() {
|
|
|
115
173
|
purpose: 'PROVIDE',
|
|
116
174
|
yfOrderId: 'ORD-1',
|
|
117
175
|
woProperties: {},
|
|
176
|
+
flow: 'FIRST_TIME_BOOKING',
|
|
118
177
|
};
|
|
119
|
-
yield p.reserveAppointment(args);
|
|
178
|
+
const result = yield p.reserveAppointment(args);
|
|
120
179
|
assert('called once', log.length === 1);
|
|
121
180
|
assert('correct method', log[0].method === 'reserveAppointment');
|
|
122
181
|
assert('args forwarded', log[0].args[0] === args);
|
|
182
|
+
assert('return forwarded', result === stubs.reserveAppointment);
|
|
123
183
|
}
|
|
124
184
|
console.log('Test: scheduleServiceWorkOrder delegates to deps');
|
|
125
185
|
{
|
|
@@ -163,7 +223,7 @@ function run() {
|
|
|
163
223
|
}
|
|
164
224
|
console.log('Test: createOrder delegates to deps with all args (principal, orderId, options)');
|
|
165
225
|
{
|
|
166
|
-
const { deps, log,
|
|
226
|
+
const { deps, log, stubs } = buildDeps();
|
|
167
227
|
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
168
228
|
const principal = { id: 'user-1' };
|
|
169
229
|
const opts = { doNotCreateServiceAppointment: true };
|
|
@@ -173,7 +233,7 @@ function run() {
|
|
|
173
233
|
assert('principal forwarded', log[0].args[0] === principal);
|
|
174
234
|
assert('orderId forwarded', log[0].args[1] === 'ORD-1');
|
|
175
235
|
assert('options forwarded', log[0].args[2] === opts);
|
|
176
|
-
assert('return forwarded', result ===
|
|
236
|
+
assert('return forwarded', result === stubs.createOrder);
|
|
177
237
|
}
|
|
178
238
|
console.log('Test: createOrder forwards undefined options correctly');
|
|
179
239
|
{
|
|
@@ -217,7 +277,13 @@ function run() {
|
|
|
217
277
|
const { deps, log } = buildDeps();
|
|
218
278
|
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
219
279
|
const principal = { id: 'user-1' };
|
|
220
|
-
|
|
280
|
+
// Minimal valid FibreCafeKciDto fixture.
|
|
281
|
+
const dto = {
|
|
282
|
+
id: 'kci-1',
|
|
283
|
+
sequenceNumber: 1,
|
|
284
|
+
issuedOn: '2026-05-09T00:00:00Z',
|
|
285
|
+
reasonCode: 'ACKNOWLEDGED',
|
|
286
|
+
};
|
|
221
287
|
yield p.receiveKci(principal, dto);
|
|
222
288
|
assert('called once', log.length === 1);
|
|
223
289
|
assert('correct method', log[0].method === 'receiveKci');
|
|
@@ -232,6 +298,7 @@ function run() {
|
|
|
232
298
|
yfOrderId: 'ORD-1',
|
|
233
299
|
yfWorkOrderId: 'WO-1',
|
|
234
300
|
yfChangeReason: { externalId: 'CR-1', entity: 'ChangeReason', type: 'CANCEL', properties: {} },
|
|
301
|
+
yfServiceAppointment: { properties: {} },
|
|
235
302
|
};
|
|
236
303
|
yield p.syncWorkOrderToSupplier(args);
|
|
237
304
|
assert('called once', log.length === 1);
|
|
@@ -241,11 +308,22 @@ function run() {
|
|
|
241
308
|
{
|
|
242
309
|
const { deps, log } = buildDeps();
|
|
243
310
|
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
311
|
+
// Test fixtures: pass-through tests treat these values as opaque; we
|
|
312
|
+
// assert reference equality, not structural equality. Casting a minimal
|
|
313
|
+
// shape to the expected types is acceptable here — the alternative is
|
|
314
|
+
// constructing 80+ OrderRecord properties for no semantic value.
|
|
244
315
|
const order = { id: 'ORD-1' };
|
|
245
|
-
const dto = {
|
|
316
|
+
const dto = {
|
|
317
|
+
id: 'kci-1',
|
|
318
|
+
sequenceNumber: 1,
|
|
319
|
+
issuedOn: '2026-05-09T00:00:00Z',
|
|
320
|
+
reasonCode: 'UPDATE',
|
|
321
|
+
};
|
|
246
322
|
yield p.syncWorkOrderFromSupplier(order, dto);
|
|
247
323
|
assert('called once', log.length === 1);
|
|
248
324
|
assert('correct method', log[0].method === 'syncWorkOrderFromSupplier');
|
|
325
|
+
assert('order reference forwarded', log[0].args[0] === order);
|
|
326
|
+
assert('dto reference forwarded', log[0].args[1] === dto);
|
|
249
327
|
}
|
|
250
328
|
console.log('Test: retrieveServiceIdByUprn delegates to deps');
|
|
251
329
|
{
|