@powerhousedao/contributor-billing 0.0.33 → 0.0.34

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.
Files changed (95) hide show
  1. package/dist/document-models/invoice/gen/actions.d.ts +3 -1
  2. package/dist/document-models/invoice/gen/actions.d.ts.map +1 -1
  3. package/dist/document-models/invoice/gen/actions.js +1 -0
  4. package/dist/document-models/invoice/gen/creators.d.ts +1 -0
  5. package/dist/document-models/invoice/gen/creators.d.ts.map +1 -1
  6. package/dist/document-models/invoice/gen/creators.js +1 -0
  7. package/dist/document-models/invoice/gen/document-model.d.ts.map +1 -1
  8. package/dist/document-models/invoice/gen/document-model.js +167 -50
  9. package/dist/document-models/invoice/gen/general/actions.d.ts +4 -6
  10. package/dist/document-models/invoice/gen/general/actions.d.ts.map +1 -1
  11. package/dist/document-models/invoice/gen/general/creators.d.ts +4 -6
  12. package/dist/document-models/invoice/gen/general/creators.d.ts.map +1 -1
  13. package/dist/document-models/invoice/gen/general/creators.js +2 -4
  14. package/dist/document-models/invoice/gen/general/object.d.ts +3 -5
  15. package/dist/document-models/invoice/gen/general/object.d.ts.map +1 -1
  16. package/dist/document-models/invoice/gen/general/object.js +6 -12
  17. package/dist/document-models/invoice/gen/general/operations.d.ts +3 -5
  18. package/dist/document-models/invoice/gen/general/operations.d.ts.map +1 -1
  19. package/dist/document-models/invoice/gen/object.d.ts +3 -1
  20. package/dist/document-models/invoice/gen/object.d.ts.map +1 -1
  21. package/dist/document-models/invoice/gen/object.js +8 -1
  22. package/dist/document-models/invoice/gen/reducer.d.ts.map +1 -1
  23. package/dist/document-models/invoice/gen/reducer.js +56 -15
  24. package/dist/document-models/invoice/gen/schema/types.d.ts +89 -23
  25. package/dist/document-models/invoice/gen/schema/types.d.ts.map +1 -1
  26. package/dist/document-models/invoice/gen/schema/zod.d.ts +21 -7
  27. package/dist/document-models/invoice/gen/schema/zod.d.ts.map +1 -1
  28. package/dist/document-models/invoice/gen/schema/zod.js +124 -28
  29. package/dist/document-models/invoice/gen/transitions/actions.d.ts +16 -0
  30. package/dist/document-models/invoice/gen/transitions/actions.d.ts.map +1 -0
  31. package/dist/document-models/invoice/gen/transitions/actions.js +1 -0
  32. package/dist/document-models/invoice/gen/transitions/creators.d.ts +15 -0
  33. package/dist/document-models/invoice/gen/transitions/creators.d.ts.map +1 -0
  34. package/dist/document-models/invoice/gen/transitions/creators.js +14 -0
  35. package/dist/document-models/invoice/gen/transitions/error.d.ts +2 -0
  36. package/dist/document-models/invoice/gen/transitions/error.d.ts.map +1 -0
  37. package/dist/document-models/invoice/gen/transitions/error.js +1 -0
  38. package/dist/document-models/invoice/gen/transitions/object.d.ts +18 -0
  39. package/dist/document-models/invoice/gen/transitions/object.d.ts.map +1 -0
  40. package/dist/document-models/invoice/gen/transitions/object.js +40 -0
  41. package/dist/document-models/invoice/gen/transitions/operations.d.ts +18 -0
  42. package/dist/document-models/invoice/gen/transitions/operations.d.ts.map +1 -0
  43. package/dist/document-models/invoice/gen/transitions/operations.js +1 -0
  44. package/dist/document-models/invoice/gen/utils.d.ts.map +1 -1
  45. package/dist/document-models/invoice/gen/utils.js +10 -6
  46. package/dist/document-models/invoice/index.d.ts +14 -4
  47. package/dist/document-models/invoice/index.d.ts.map +1 -1
  48. package/dist/document-models/invoice/src/reducers/general.d.ts.map +1 -1
  49. package/dist/document-models/invoice/src/reducers/general.js +26 -42
  50. package/dist/document-models/invoice/src/reducers/transitions.d.ts +8 -0
  51. package/dist/document-models/invoice/src/reducers/transitions.d.ts.map +1 -0
  52. package/dist/document-models/invoice/src/reducers/transitions.js +162 -0
  53. package/dist/document-models/invoice/src/tests/general.test.js +10 -31
  54. package/dist/document-models/invoice/src/tests/transitions.test.d.ts +6 -0
  55. package/dist/document-models/invoice/src/tests/transitions.test.d.ts.map +1 -0
  56. package/dist/document-models/invoice/src/tests/transitions.test.js +506 -0
  57. package/dist/document-models/invoice/utils/statusTransitions.d.ts +13 -0
  58. package/dist/document-models/invoice/utils/statusTransitions.d.ts.map +1 -0
  59. package/dist/document-models/invoice/utils/statusTransitions.js +13 -0
  60. package/dist/editors/billing-statement/lineItemTags/tagMapping.js +64 -64
  61. package/dist/editors/contributor-billing/components/DriveExplorer.js +1 -1
  62. package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.d.ts +3 -2
  63. package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.d.ts.map +1 -1
  64. package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.js +26 -3
  65. package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.d.ts.map +1 -1
  66. package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.js +11 -3
  67. package/dist/editors/invoice/components/confirmationModal.d.ts +14 -0
  68. package/dist/editors/invoice/components/confirmationModal.d.ts.map +1 -0
  69. package/dist/editors/invoice/components/confirmationModal.js +7 -0
  70. package/dist/editors/invoice/components/selectField.d.ts.map +1 -1
  71. package/dist/editors/invoice/components/selectField.js +109 -112
  72. package/dist/editors/invoice/components/statusModalComponents.d.ts +52 -0
  73. package/dist/editors/invoice/components/statusModalComponents.d.ts.map +1 -0
  74. package/dist/editors/invoice/components/statusModalComponents.js +78 -0
  75. package/dist/editors/invoice/editor.d.ts +1 -1
  76. package/dist/editors/invoice/editor.d.ts.map +1 -1
  77. package/dist/editors/invoice/editor.js +153 -158
  78. package/dist/editors/invoice/ingestUBL.d.ts.map +1 -1
  79. package/dist/editors/invoice/ingestUBL.js +0 -3
  80. package/dist/editors/invoice/invoiceToGnosis.d.ts.map +1 -1
  81. package/dist/editors/invoice/invoiceToGnosis.js +4 -3
  82. package/dist/editors/invoice/lineItemTags/tagMapping.d.ts.map +1 -1
  83. package/dist/editors/invoice/lineItemTags/tagMapping.js +65 -64
  84. package/dist/editors/invoice/validation/validationHandler.d.ts +4 -0
  85. package/dist/editors/invoice/validation/validationHandler.d.ts.map +1 -0
  86. package/dist/editors/invoice/validation/validationHandler.js +117 -0
  87. package/dist/scripts/contributor-billing/createXeroCsv.d.ts +8 -0
  88. package/dist/scripts/contributor-billing/createXeroCsv.d.ts.map +1 -0
  89. package/dist/scripts/contributor-billing/createXeroCsv.js +206 -0
  90. package/dist/style.css +181 -18
  91. package/dist/subgraphs/invoice/resolvers.d.ts.map +1 -1
  92. package/dist/subgraphs/invoice/resolvers.js +92 -22
  93. package/dist/subgraphs/invoice/schema.d.ts.map +1 -1
  94. package/dist/subgraphs/invoice/schema.js +181 -57
  95. package/package.json +1 -1
@@ -0,0 +1,506 @@
1
+ /**
2
+ * This is a scaffold file meant for customization:
3
+ * - change it by adding new tests or modifying the existing ones
4
+ */
5
+ import utils from "../../gen/utils.js";
6
+ import { reducer } from "../../gen/reducer.js";
7
+ import * as creators from "../../gen/transitions/creators.js";
8
+ describe("Transitions Operations", () => {
9
+ let document;
10
+ beforeEach(() => {
11
+ document = utils.createDocument();
12
+ });
13
+ describe("DRAFT status transitions", () => {
14
+ beforeEach(() => {
15
+ // Ensure document starts in DRAFT status
16
+ document.state.global.status = "DRAFT";
17
+ });
18
+ it("should handle DRAFT -> CANCELLED transition", () => {
19
+ const input = {
20
+ _placeholder: "cancel_placeholder"
21
+ };
22
+ const updatedDocument = reducer(document, creators.cancel(input));
23
+ expect(updatedDocument.state.global.status).toBe("CANCELLED");
24
+ expect(updatedDocument.operations.global).toHaveLength(1);
25
+ expect(updatedDocument.operations.global[0].type).toBe("CANCEL");
26
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
27
+ });
28
+ it("should handle DRAFT -> ISSUED transition", () => {
29
+ const input = {
30
+ invoiceNo: "INV-2024-001",
31
+ dateIssued: "2024-01-15"
32
+ };
33
+ const updatedDocument = reducer(document, creators.issue(input));
34
+ expect(updatedDocument.state.global.status).toBe("ISSUED");
35
+ expect(updatedDocument.state.global.invoiceNo).toBe("INV-2024-001");
36
+ expect(updatedDocument.state.global.dateIssued).toBe("2024-01-15");
37
+ expect(updatedDocument.operations.global).toHaveLength(1);
38
+ expect(updatedDocument.operations.global[0].type).toBe("ISSUE");
39
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
40
+ });
41
+ });
42
+ describe("CANCELLED status transitions", () => {
43
+ beforeEach(() => {
44
+ document.state.global.status = "CANCELLED";
45
+ });
46
+ it("should handle CANCELLED -> DRAFT transition", () => {
47
+ const input = {
48
+ _placeholder: "reset_placeholder"
49
+ };
50
+ const updatedDocument = reducer(document, creators.reset(input));
51
+ expect(updatedDocument.state.global.status).toBe("DRAFT");
52
+ expect(updatedDocument.operations.global).toHaveLength(1);
53
+ expect(updatedDocument.operations.global[0].type).toBe("RESET");
54
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
55
+ });
56
+ });
57
+ describe("ISSUED status transitions", () => {
58
+ beforeEach(() => {
59
+ document.state.global.status = "ISSUED";
60
+ document.state.global.invoiceNo = "INV-2024-001";
61
+ document.state.global.dateIssued = "2024-01-15";
62
+ });
63
+ it("should handle ISSUED -> REJECTED transition", () => {
64
+ const input = {
65
+ id: "rejection-1",
66
+ reason: "Incorrect pricing information",
67
+ final: false
68
+ };
69
+ const updatedDocument = reducer(document, creators.reject(input));
70
+ expect(updatedDocument.state.global.status).toBe("REJECTED");
71
+ expect(updatedDocument.state.global.rejections).toHaveLength(1);
72
+ expect(updatedDocument.state.global.rejections[0].reason).toBe("Incorrect pricing information");
73
+ expect(updatedDocument.state.global.rejections[0].final).toBe(false);
74
+ expect(updatedDocument.operations.global).toHaveLength(1);
75
+ expect(updatedDocument.operations.global[0].type).toBe("REJECT");
76
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
77
+ });
78
+ it("should handle ISSUED -> ACCEPTED transition", () => {
79
+ const input = {
80
+ payAfter: "2024-02-15T00:00:00Z"
81
+ };
82
+ const updatedDocument = reducer(document, creators.accept(input));
83
+ expect(updatedDocument.state.global.status).toBe("ACCEPTED");
84
+ expect(updatedDocument.state.global.payAfter).toBe("2024-02-15T00:00:00Z");
85
+ expect(updatedDocument.operations.global).toHaveLength(1);
86
+ expect(updatedDocument.operations.global[0].type).toBe("ACCEPT");
87
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
88
+ });
89
+ });
90
+ describe("REJECTED status transitions", () => {
91
+ beforeEach(() => {
92
+ document.state.global.status = "REJECTED";
93
+ document.state.global.rejections = [{
94
+ id: "rejection-1",
95
+ reason: "Incorrect pricing",
96
+ final: false
97
+ }];
98
+ });
99
+ it("should handle REJECTED -> ISSUED transition", () => {
100
+ const input = {
101
+ _placeholder: "reinstate_placeholder"
102
+ };
103
+ const updatedDocument = reducer(document, creators.reinstate(input));
104
+ expect(updatedDocument.state.global.status).toBe("ISSUED");
105
+ expect(updatedDocument.operations.global).toHaveLength(1);
106
+ expect(updatedDocument.operations.global[0].type).toBe("REINSTATE");
107
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
108
+ });
109
+ it("should not allow REJECTED -> ISSUED transition when final rejection exists", () => {
110
+ document.state.global.rejections = [{
111
+ id: "rejection-1",
112
+ reason: "Final rejection",
113
+ final: true
114
+ }];
115
+ const input = {
116
+ _placeholder: "reinstate_placeholder"
117
+ };
118
+ const updatedDocument = reducer(document, creators.reinstate(input));
119
+ expect(updatedDocument.operations.global[0].error).toBe("Cannot reinstate an invoice that has been rejected");
120
+ });
121
+ });
122
+ describe("ACCEPTED status transitions", () => {
123
+ beforeEach(() => {
124
+ document.state.global.status = "ACCEPTED";
125
+ });
126
+ it("should handle ACCEPTED -> PAYMENTSCHEDULED transition", () => {
127
+ const input = {
128
+ id: "payment-1",
129
+ processorRef: "stripe_pi_123456"
130
+ };
131
+ const updatedDocument = reducer(document, creators.schedulePayment(input));
132
+ expect(updatedDocument.state.global.status).toBe("PAYMENTSCHEDULED");
133
+ expect(updatedDocument.state.global.payments).toHaveLength(1);
134
+ expect(updatedDocument.state.global.payments[0].id).toBe("payment-1");
135
+ expect(updatedDocument.state.global.payments[0].processorRef).toBe("stripe_pi_123456");
136
+ expect(updatedDocument.state.global.payments[0].confirmed).toBe(false);
137
+ expect(updatedDocument.operations.global).toHaveLength(1);
138
+ expect(updatedDocument.operations.global[0].type).toBe("SCHEDULE_PAYMENT");
139
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
140
+ });
141
+ it("should handle ACCEPTED -> PAYMENTCLOSED transition", () => {
142
+ const input = {
143
+ closureReason: "CANCELLED"
144
+ };
145
+ const updatedDocument = reducer(document, creators.closePayment(input));
146
+ expect(updatedDocument.state.global.status).toBe("PAYMENTCLOSED");
147
+ expect(updatedDocument.state.global.closureReason).toBe("CANCELLED");
148
+ expect(updatedDocument.operations.global).toHaveLength(1);
149
+ expect(updatedDocument.operations.global[0].type).toBe("CLOSE_PAYMENT");
150
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
151
+ });
152
+ });
153
+ describe("PAYMENTSCHEDULED status transitions", () => {
154
+ beforeEach(() => {
155
+ document.state.global.status = "PAYMENTSCHEDULED";
156
+ document.state.global.payments = [{
157
+ id: "payment-1",
158
+ processorRef: "stripe_pi_123456",
159
+ paymentDate: "",
160
+ txnRef: "",
161
+ confirmed: false,
162
+ issue: "",
163
+ amount: 0
164
+ }];
165
+ });
166
+ it("should handle PAYMENTSCHEDULED -> PAYMENTSENT transition", () => {
167
+ const input = {
168
+ id: "payment-1",
169
+ timestamp: "2024-01-20T10:30:00Z",
170
+ txRef: "txn_789012"
171
+ };
172
+ const updatedDocument = reducer(document, creators.registerPaymentTx(input));
173
+ expect(updatedDocument.state.global.status).toBe("PAYMENTSENT");
174
+ expect(updatedDocument.state.global.payments[0].txnRef).toBe("txn_789012");
175
+ expect(updatedDocument.state.global.payments[0].paymentDate).toBe("2024-01-20T10:30:00Z");
176
+ expect(updatedDocument.operations.global).toHaveLength(1);
177
+ expect(updatedDocument.operations.global[0].type).toBe("REGISTER_PAYMENT_TX");
178
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
179
+ });
180
+ it("should handle PAYMENTSCHEDULED -> PAYMENTISSUE transition", () => {
181
+ const input = {
182
+ id: "payment-1",
183
+ issue: "Payment processor timeout"
184
+ };
185
+ const updatedDocument = reducer(document, creators.reportPaymentIssue(input));
186
+ expect(updatedDocument.state.global.status).toBe("PAYMENTISSUE");
187
+ expect(updatedDocument.state.global.payments[0].issue).toBe("Payment processor timeout");
188
+ expect(updatedDocument.operations.global).toHaveLength(1);
189
+ expect(updatedDocument.operations.global[0].type).toBe("REPORT_PAYMENT_ISSUE");
190
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
191
+ });
192
+ it("should handle PAYMENTSCHEDULED -> PAYMENTCLOSED transition", () => {
193
+ const input = {
194
+ closureReason: "CANCELLED"
195
+ };
196
+ const updatedDocument = reducer(document, creators.closePayment(input));
197
+ expect(updatedDocument.state.global.status).toBe("PAYMENTCLOSED");
198
+ expect(updatedDocument.state.global.closureReason).toBe("CANCELLED");
199
+ expect(updatedDocument.operations.global).toHaveLength(1);
200
+ expect(updatedDocument.operations.global[0].type).toBe("CLOSE_PAYMENT");
201
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
202
+ });
203
+ });
204
+ describe("PAYMENTSENT status transitions", () => {
205
+ beforeEach(() => {
206
+ document.state.global.status = "PAYMENTSENT";
207
+ document.state.global.payments = [{
208
+ id: "payment-1",
209
+ processorRef: "stripe_pi_123456",
210
+ paymentDate: "2024-01-20T10:30:00Z",
211
+ txnRef: "txn_789012",
212
+ confirmed: false,
213
+ issue: "",
214
+ amount: 0
215
+ }];
216
+ });
217
+ it("should handle PAYMENTSENT -> PAYMENTISSUE transition", () => {
218
+ const input = {
219
+ id: "payment-1",
220
+ issue: "Transaction failed"
221
+ };
222
+ const updatedDocument = reducer(document, creators.reportPaymentIssue(input));
223
+ expect(updatedDocument.state.global.status).toBe("PAYMENTISSUE");
224
+ expect(updatedDocument.state.global.payments[0].issue).toBe("Transaction failed");
225
+ expect(updatedDocument.operations.global).toHaveLength(1);
226
+ expect(updatedDocument.operations.global[0].type).toBe("REPORT_PAYMENT_ISSUE");
227
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
228
+ });
229
+ it("should handle PAYMENTSENT -> PAYMENTRECEIVED transition", () => {
230
+ const input = {
231
+ id: "payment-1",
232
+ amount: 1500.00
233
+ };
234
+ const updatedDocument = reducer(document, creators.confirmPayment(input));
235
+ expect(updatedDocument.state.global.status).toBe("PAYMENTRECEIVED");
236
+ expect(updatedDocument.state.global.payments[0].confirmed).toBe(true);
237
+ expect(updatedDocument.state.global.payments[0].amount).toBe(1500.00);
238
+ expect(updatedDocument.operations.global).toHaveLength(1);
239
+ expect(updatedDocument.operations.global[0].type).toBe("CONFIRM_PAYMENT");
240
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
241
+ });
242
+ });
243
+ describe("PAYMENTISSUE status transitions", () => {
244
+ beforeEach(() => {
245
+ document.state.global.status = "PAYMENTISSUE";
246
+ document.state.global.payments = [{
247
+ id: "payment-1",
248
+ processorRef: "stripe_pi_123456",
249
+ paymentDate: "",
250
+ txnRef: "",
251
+ confirmed: false,
252
+ issue: "Payment processor timeout",
253
+ amount: 0
254
+ }];
255
+ });
256
+ it("should handle PAYMENTISSUE -> ACCEPTED transition", () => {
257
+ const input = {
258
+ _placeholder: "reapprove_placeholder"
259
+ };
260
+ const updatedDocument = reducer(document, creators.reapprovePayment(input));
261
+ expect(updatedDocument.state.global.status).toBe("ACCEPTED");
262
+ expect(updatedDocument.operations.global).toHaveLength(1);
263
+ expect(updatedDocument.operations.global[0].type).toBe("REAPPROVE_PAYMENT");
264
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
265
+ });
266
+ it("should handle PAYMENTISSUE -> PAYMENTCLOSED transition", () => {
267
+ const input = {
268
+ closureReason: "CANCELLED"
269
+ };
270
+ const updatedDocument = reducer(document, creators.closePayment(input));
271
+ expect(updatedDocument.state.global.status).toBe("PAYMENTCLOSED");
272
+ expect(updatedDocument.state.global.closureReason).toBe("CANCELLED");
273
+ expect(updatedDocument.operations.global).toHaveLength(1);
274
+ expect(updatedDocument.operations.global[0].type).toBe("CLOSE_PAYMENT");
275
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
276
+ });
277
+ });
278
+ describe("PAYMENTRECEIVED status transitions", () => {
279
+ beforeEach(() => {
280
+ document.state.global.status = "PAYMENTRECEIVED";
281
+ document.state.global.payments = [{
282
+ id: "payment-1",
283
+ processorRef: "stripe_pi_123456",
284
+ paymentDate: "2024-01-20T10:30:00Z",
285
+ txnRef: "txn_789012",
286
+ confirmed: true,
287
+ issue: "",
288
+ amount: 1500.00
289
+ }];
290
+ });
291
+ it("should handle PAYMENTRECEIVED -> PAYMENTISSUE transition", () => {
292
+ const input = {
293
+ id: "payment-1",
294
+ issue: "Payment amount discrepancy"
295
+ };
296
+ const updatedDocument = reducer(document, creators.reportPaymentIssue(input));
297
+ expect(updatedDocument.state.global.status).toBe("PAYMENTISSUE");
298
+ expect(updatedDocument.state.global.payments[0].issue).toBe("Payment amount discrepancy");
299
+ expect(updatedDocument.operations.global).toHaveLength(1);
300
+ expect(updatedDocument.operations.global[0].type).toBe("REPORT_PAYMENT_ISSUE");
301
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
302
+ });
303
+ });
304
+ describe("PAYMENTCLOSED status transitions", () => {
305
+ beforeEach(() => {
306
+ document.state.global.status = "PAYMENTCLOSED";
307
+ document.state.global.closureReason = "CANCELLED";
308
+ });
309
+ it("should handle PAYMENTCLOSED -> ACCEPTED transition", () => {
310
+ const input = {
311
+ _placeholder: "reapprove_placeholder"
312
+ };
313
+ const updatedDocument = reducer(document, creators.reapprovePayment(input));
314
+ expect(updatedDocument.state.global.status).toBe("ACCEPTED");
315
+ expect(updatedDocument.operations.global).toHaveLength(1);
316
+ expect(updatedDocument.operations.global[0].type).toBe("REAPPROVE_PAYMENT");
317
+ expect(updatedDocument.operations.global[0].input).toStrictEqual(input);
318
+ });
319
+ });
320
+ describe("Error cases", () => {
321
+ it("should throw error for invalid DRAFT -> ACCEPTED transition", () => {
322
+ document.state.global.status = "DRAFT";
323
+ const input = {
324
+ payAfter: "2024-02-15T00:00:00Z"
325
+ };
326
+ const updatedDocument = reducer(document, creators.accept(input));
327
+ expect(updatedDocument.operations.global[0].error).toBe("Invalid transition from DRAFT to ACCEPTED");
328
+ });
329
+ it("should throw error for invalid ISSUED -> PAYMENTSCHEDULED transition", () => {
330
+ document.state.global.status = "ISSUED";
331
+ const input = {
332
+ id: "payment-1",
333
+ processorRef: "stripe_pi_123456"
334
+ };
335
+ const updatedDocument = reducer(document, creators.schedulePayment(input));
336
+ expect(updatedDocument.operations.global[0].error).toBe("Invalid transition from ISSUED to PAYMENTSCHEDULED");
337
+ });
338
+ it("should throw error for missing required fields in issue operation", () => {
339
+ document.state.global.status = "DRAFT";
340
+ const input = {
341
+ invoiceNo: "",
342
+ dateIssued: ""
343
+ };
344
+ const updatedDocument = reducer(document, creators.issue(input));
345
+ expect(updatedDocument.operations.global[0].error).toBe("Invoice number and date issued are required");
346
+ });
347
+ it("should throw error for missing required fields in reject operation", () => {
348
+ document.state.global.status = "ISSUED";
349
+ const input = {
350
+ id: "",
351
+ reason: "",
352
+ final: false
353
+ };
354
+ const updatedDocument = reducer(document, creators.reject(input));
355
+ expect(updatedDocument.operations.global[0].error).toBe("Reason, ID and final are required");
356
+ });
357
+ it("should throw error for missing required fields in schedulePayment operation", () => {
358
+ document.state.global.status = "ACCEPTED";
359
+ const input = {
360
+ id: "",
361
+ processorRef: ""
362
+ };
363
+ const updatedDocument = reducer(document, creators.schedulePayment(input));
364
+ expect(updatedDocument.operations.global[0].error).toBe("ID and processorRef are required");
365
+ });
366
+ it("should throw error when payment not found in registerPaymentTx operation", () => {
367
+ document.state.global.status = "PAYMENTSCHEDULED";
368
+ document.state.global.payments = [{
369
+ id: "payment-1",
370
+ processorRef: "stripe_pi_123456",
371
+ paymentDate: "",
372
+ txnRef: "",
373
+ confirmed: false,
374
+ issue: "",
375
+ amount: 0
376
+ }];
377
+ const input = {
378
+ id: "non-existent-payment",
379
+ timestamp: "2024-01-20T10:30:00Z",
380
+ txRef: "txn_789012"
381
+ };
382
+ const updatedDocument = reducer(document, creators.registerPaymentTx(input));
383
+ expect(updatedDocument.operations.global[0].error).toBe("Payment not found");
384
+ });
385
+ it("should throw schema validation error for invalid datetime in registerPaymentTx operation", () => {
386
+ document.state.global.status = "PAYMENTSCHEDULED";
387
+ document.state.global.payments = [{
388
+ id: "payment-1",
389
+ processorRef: "stripe_pi_123456",
390
+ paymentDate: "",
391
+ txnRef: "",
392
+ confirmed: false,
393
+ issue: "",
394
+ amount: 0
395
+ }];
396
+ // This should fail at the schema level due to invalid datetime format
397
+ expect(() => {
398
+ const input = {
399
+ id: "payment-1",
400
+ timestamp: "invalid-datetime",
401
+ txRef: "txn_789012"
402
+ };
403
+ reducer(document, creators.registerPaymentTx(input));
404
+ }).toThrow();
405
+ });
406
+ it("should throw error for missing required fields in reportPaymentIssue operation", () => {
407
+ document.state.global.status = "PAYMENTSCHEDULED";
408
+ document.state.global.payments = [{
409
+ id: "payment-1",
410
+ processorRef: "stripe_pi_123456",
411
+ paymentDate: "",
412
+ txnRef: "",
413
+ confirmed: false,
414
+ issue: "",
415
+ amount: 0
416
+ }];
417
+ const input = {
418
+ id: "",
419
+ issue: ""
420
+ };
421
+ const updatedDocument = reducer(document, creators.reportPaymentIssue(input));
422
+ expect(updatedDocument.operations.global[0].error).toBe("ID and issue are required");
423
+ });
424
+ it("should throw error for missing required fields in confirmPayment operation", () => {
425
+ document.state.global.status = "PAYMENTSENT";
426
+ document.state.global.payments = [{
427
+ id: "payment-1",
428
+ processorRef: "stripe_pi_123456",
429
+ paymentDate: "2024-01-20T10:30:00Z",
430
+ txnRef: "txn_789012",
431
+ confirmed: false,
432
+ issue: "",
433
+ amount: 0
434
+ }];
435
+ const input = {
436
+ id: "",
437
+ amount: 0
438
+ };
439
+ const updatedDocument = reducer(document, creators.confirmPayment(input));
440
+ expect(updatedDocument.operations.global[0].error).toBe("ID and amount are required");
441
+ });
442
+ it("should throw error for missing required fields in closePayment operation", () => {
443
+ document.state.global.status = "ACCEPTED";
444
+ const input = {
445
+ closureReason: undefined
446
+ };
447
+ const updatedDocument = reducer(document, creators.closePayment(input));
448
+ expect(updatedDocument.operations.global[0].error).toBe("Closure reason is required");
449
+ });
450
+ it("should throw error when payment not found in registerPaymentTx", () => {
451
+ document.state.global.status = "PAYMENTSCHEDULED";
452
+ document.state.global.payments = [{
453
+ id: "payment-1",
454
+ processorRef: "stripe_pi_123456",
455
+ paymentDate: "",
456
+ txnRef: "",
457
+ confirmed: false,
458
+ issue: "",
459
+ amount: 0
460
+ }];
461
+ const input = {
462
+ id: "non-existent-payment",
463
+ timestamp: "2024-01-20T10:30:00Z",
464
+ txRef: "txn_789012"
465
+ };
466
+ const updatedDocument = reducer(document, creators.registerPaymentTx(input));
467
+ expect(updatedDocument.operations.global[0].error).toBe("Payment not found");
468
+ });
469
+ it("should throw error when payment not found in reportPaymentIssue", () => {
470
+ document.state.global.status = "PAYMENTSCHEDULED";
471
+ document.state.global.payments = [{
472
+ id: "payment-1",
473
+ processorRef: "stripe_pi_123456",
474
+ paymentDate: "",
475
+ txnRef: "",
476
+ confirmed: false,
477
+ issue: "",
478
+ amount: 0
479
+ }];
480
+ const input = {
481
+ id: "non-existent-payment",
482
+ issue: "Payment issue"
483
+ };
484
+ const updatedDocument = reducer(document, creators.reportPaymentIssue(input));
485
+ expect(updatedDocument.operations.global[0].error).toBe("Payment not found");
486
+ });
487
+ it("should throw error when payment not found in confirmPayment", () => {
488
+ document.state.global.status = "PAYMENTSENT";
489
+ document.state.global.payments = [{
490
+ id: "payment-1",
491
+ processorRef: "stripe_pi_123456",
492
+ paymentDate: "2024-01-20T10:30:00Z",
493
+ txnRef: "txn_789012",
494
+ confirmed: false,
495
+ issue: "",
496
+ amount: 0
497
+ }];
498
+ const input = {
499
+ id: "non-existent-payment",
500
+ amount: 1500.00
501
+ };
502
+ const updatedDocument = reducer(document, creators.confirmPayment(input));
503
+ expect(updatedDocument.operations.global[0].error).toBe("Payment not found");
504
+ });
505
+ });
506
+ });
@@ -0,0 +1,13 @@
1
+ export declare const permittedTransitions: {
2
+ DRAFT: string[];
3
+ CANCELLED: string[];
4
+ ISSUED: string[];
5
+ REJECTED: string[];
6
+ ACCEPTED: string[];
7
+ PAYMENTSCHEDULED: string[];
8
+ PAYMENTSENT: string[];
9
+ PAYMENTISSUE: string[];
10
+ PAYMENTRECEIVED: string[];
11
+ PAYMENTCLOSED: string[];
12
+ };
13
+ //# sourceMappingURL=statusTransitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statusTransitions.d.ts","sourceRoot":"","sources":["../../../../document-models/invoice/utils/statusTransitions.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,oBAAoB;;;;;;;;;;;CAWhC,CAAA"}
@@ -0,0 +1,13 @@
1
+ // Status transitions mapping
2
+ export const permittedTransitions = {
3
+ DRAFT: ['CANCELLED', 'ISSUED'],
4
+ CANCELLED: ['DRAFT'],
5
+ ISSUED: ['REJECTED', 'ACCEPTED'],
6
+ REJECTED: ['ISSUED'],
7
+ ACCEPTED: ['PAYMENTSCHEDULED', 'PAYMENTCLOSED'],
8
+ PAYMENTSCHEDULED: ['PAYMENTSENT', 'PAYMENTISSUE', 'PAYMENTCLOSED'],
9
+ PAYMENTSENT: ['PAYMENTISSUE', 'PAYMENTRECEIVED'],
10
+ PAYMENTISSUE: ['ACCEPTED', 'PAYMENTCLOSED'],
11
+ PAYMENTRECEIVED: ['PAYMENTISSUE'],
12
+ PAYMENTCLOSED: ['ACCEPTED'],
13
+ };