@d19n/youfibre-odin-sdk 2.0.103-beta.8 → 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).
|
|
@@ -53,8 +86,8 @@ export interface AmendAppointmentArgs {
|
|
|
53
86
|
yfWorkOrderId: string;
|
|
54
87
|
supplierAppointmentReference: string;
|
|
55
88
|
}
|
|
56
|
-
export interface SyncWorkOrderToSupplierArgs {
|
|
57
|
-
principal:
|
|
89
|
+
export interface SyncWorkOrderToSupplierArgs<TPrincipal = unknown> {
|
|
90
|
+
principal: TPrincipal;
|
|
58
91
|
yfOrderId: string;
|
|
59
92
|
yfWorkOrderId: string;
|
|
60
93
|
yfChangeReason: {
|
|
@@ -86,26 +119,41 @@ export interface UpdateOrderExternalRefArgs {
|
|
|
86
119
|
* Returns are typed loosely — modules know the return shape via the dep
|
|
87
120
|
* function they wire in.
|
|
88
121
|
*/
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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>;
|
|
99
147
|
/** Pre-install cancel of an in-flight provide order. */
|
|
100
|
-
cancelOrder(yfOrderId: string, reasonCode: CancellationReasonCode): Promise<
|
|
148
|
+
cancelOrder(yfOrderId: string, reasonCode: CancellationReasonCode): Promise<FibreCafeOrderCreate202>;
|
|
101
149
|
/** Active-customer cease (post-Active churn / OTS-losing). */
|
|
102
|
-
ceaseOrder(yfOrderId: string, serviceId: string): Promise<
|
|
150
|
+
ceaseOrder(yfOrderId: string, serviceId: string): Promise<FibreCafeOrderCreate202>;
|
|
103
151
|
/** Inbound supplier KCI / notification handler. */
|
|
104
|
-
receiveKci(principal:
|
|
152
|
+
receiveKci(principal: TPrincipal, dto: FibreCafeKciDto): Promise<void>;
|
|
105
153
|
/** Outbound YF→supplier WO sync (cancel propagation, etc.). */
|
|
106
|
-
syncWorkOrderToSupplier(args: SyncWorkOrderToSupplierArgs): Promise<
|
|
154
|
+
syncWorkOrderToSupplier(args: SyncWorkOrderToSupplierArgs<TPrincipal>): Promise<void>;
|
|
107
155
|
/** Inbound supplier→YF WO change application (post-receiveKci). */
|
|
108
|
-
syncWorkOrderFromSupplier(order:
|
|
156
|
+
syncWorkOrderFromSupplier(order: OrderRecord, dto: FibreCafeKciDto): Promise<void>;
|
|
109
157
|
retrieveServiceIdByUprn(uprn: number): Promise<string | null>;
|
|
110
158
|
updateOrderExternalRef(args: UpdateOrderExternalRefArgs): Promise<void>;
|
|
111
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',
|
|
@@ -117,10 +175,11 @@ function run() {
|
|
|
117
175
|
woProperties: {},
|
|
118
176
|
flow: 'FIRST_TIME_BOOKING',
|
|
119
177
|
};
|
|
120
|
-
yield p.reserveAppointment(args);
|
|
178
|
+
const result = yield p.reserveAppointment(args);
|
|
121
179
|
assert('called once', log.length === 1);
|
|
122
180
|
assert('correct method', log[0].method === 'reserveAppointment');
|
|
123
181
|
assert('args forwarded', log[0].args[0] === args);
|
|
182
|
+
assert('return forwarded', result === stubs.reserveAppointment);
|
|
124
183
|
}
|
|
125
184
|
console.log('Test: scheduleServiceWorkOrder delegates to deps');
|
|
126
185
|
{
|
|
@@ -164,7 +223,7 @@ function run() {
|
|
|
164
223
|
}
|
|
165
224
|
console.log('Test: createOrder delegates to deps with all args (principal, orderId, options)');
|
|
166
225
|
{
|
|
167
|
-
const { deps, log,
|
|
226
|
+
const { deps, log, stubs } = buildDeps();
|
|
168
227
|
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
169
228
|
const principal = { id: 'user-1' };
|
|
170
229
|
const opts = { doNotCreateServiceAppointment: true };
|
|
@@ -174,7 +233,7 @@ function run() {
|
|
|
174
233
|
assert('principal forwarded', log[0].args[0] === principal);
|
|
175
234
|
assert('orderId forwarded', log[0].args[1] === 'ORD-1');
|
|
176
235
|
assert('options forwarded', log[0].args[2] === opts);
|
|
177
|
-
assert('return forwarded', result ===
|
|
236
|
+
assert('return forwarded', result === stubs.createOrder);
|
|
178
237
|
}
|
|
179
238
|
console.log('Test: createOrder forwards undefined options correctly');
|
|
180
239
|
{
|
|
@@ -218,7 +277,13 @@ function run() {
|
|
|
218
277
|
const { deps, log } = buildDeps();
|
|
219
278
|
const p = new netomnia_provider_1.NetomniaProvider(deps);
|
|
220
279
|
const principal = { id: 'user-1' };
|
|
221
|
-
|
|
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
|
+
};
|
|
222
287
|
yield p.receiveKci(principal, dto);
|
|
223
288
|
assert('called once', log.length === 1);
|
|
224
289
|
assert('correct method', log[0].method === 'receiveKci');
|
|
@@ -243,11 +308,22 @@ function run() {
|
|
|
243
308
|
{
|
|
244
309
|
const { deps, log } = buildDeps();
|
|
245
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.
|
|
246
315
|
const order = { id: 'ORD-1' };
|
|
247
|
-
const dto = {
|
|
316
|
+
const dto = {
|
|
317
|
+
id: 'kci-1',
|
|
318
|
+
sequenceNumber: 1,
|
|
319
|
+
issuedOn: '2026-05-09T00:00:00Z',
|
|
320
|
+
reasonCode: 'UPDATE',
|
|
321
|
+
};
|
|
248
322
|
yield p.syncWorkOrderFromSupplier(order, dto);
|
|
249
323
|
assert('called once', log.length === 1);
|
|
250
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);
|
|
251
327
|
}
|
|
252
328
|
console.log('Test: retrieveServiceIdByUprn delegates to deps');
|
|
253
329
|
{
|