@cogenta/commerce 0.2.0

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 (98) hide show
  1. package/LICENSE +373 -0
  2. package/dist/admin/permissions.d.ts +57 -0
  3. package/dist/admin/permissions.d.ts.map +1 -0
  4. package/dist/admin/permissions.js +87 -0
  5. package/dist/admin/permissions.js.map +1 -0
  6. package/dist/admin/router.d.ts +53 -0
  7. package/dist/admin/router.d.ts.map +1 -0
  8. package/dist/admin/router.js +476 -0
  9. package/dist/admin/router.js.map +1 -0
  10. package/dist/cart/store.d.ts +91 -0
  11. package/dist/cart/store.d.ts.map +1 -0
  12. package/dist/cart/store.js +342 -0
  13. package/dist/cart/store.js.map +1 -0
  14. package/dist/cart/totals.d.ts +73 -0
  15. package/dist/cart/totals.d.ts.map +1 -0
  16. package/dist/cart/totals.js +65 -0
  17. package/dist/cart/totals.js.map +1 -0
  18. package/dist/catalog/store.d.ts +53 -0
  19. package/dist/catalog/store.d.ts.map +1 -0
  20. package/dist/catalog/store.js +358 -0
  21. package/dist/catalog/store.js.map +1 -0
  22. package/dist/catalog/types.d.ts +95 -0
  23. package/dist/catalog/types.d.ts.map +1 -0
  24. package/dist/catalog/types.js +5 -0
  25. package/dist/catalog/types.js.map +1 -0
  26. package/dist/coupon/store.d.ts +103 -0
  27. package/dist/coupon/store.d.ts.map +1 -0
  28. package/dist/coupon/store.js +181 -0
  29. package/dist/coupon/store.js.map +1 -0
  30. package/dist/customer/store.d.ts +41 -0
  31. package/dist/customer/store.d.ts.map +1 -0
  32. package/dist/customer/store.js +103 -0
  33. package/dist/customer/store.js.map +1 -0
  34. package/dist/index.d.ts +42 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +23 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/invoice/pdf.d.ts +67 -0
  39. package/dist/invoice/pdf.d.ts.map +1 -0
  40. package/dist/invoice/pdf.js +449 -0
  41. package/dist/invoice/pdf.js.map +1 -0
  42. package/dist/invoice/store.d.ts +96 -0
  43. package/dist/invoice/store.d.ts.map +1 -0
  44. package/dist/invoice/store.js +221 -0
  45. package/dist/invoice/store.js.map +1 -0
  46. package/dist/money.d.ts +55 -0
  47. package/dist/money.d.ts.map +1 -0
  48. package/dist/money.js +146 -0
  49. package/dist/money.js.map +1 -0
  50. package/dist/order/store.d.ts +75 -0
  51. package/dist/order/store.d.ts.map +1 -0
  52. package/dist/order/store.js +301 -0
  53. package/dist/order/store.js.map +1 -0
  54. package/dist/order/types.d.ts +67 -0
  55. package/dist/order/types.d.ts.map +1 -0
  56. package/dist/order/types.js +71 -0
  57. package/dist/order/types.js.map +1 -0
  58. package/dist/payment/manual.d.ts +27 -0
  59. package/dist/payment/manual.d.ts.map +1 -0
  60. package/dist/payment/manual.js +105 -0
  61. package/dist/payment/manual.js.map +1 -0
  62. package/dist/payment/registry.d.ts +23 -0
  63. package/dist/payment/registry.d.ts.map +1 -0
  64. package/dist/payment/registry.js +30 -0
  65. package/dist/payment/registry.js.map +1 -0
  66. package/dist/payment/store.d.ts +38 -0
  67. package/dist/payment/store.d.ts.map +1 -0
  68. package/dist/payment/store.js +253 -0
  69. package/dist/payment/store.js.map +1 -0
  70. package/dist/payment/stripe.d.ts +10 -0
  71. package/dist/payment/stripe.d.ts.map +1 -0
  72. package/dist/payment/stripe.js +419 -0
  73. package/dist/payment/stripe.js.map +1 -0
  74. package/dist/payment/types.d.ts +124 -0
  75. package/dist/payment/types.d.ts.map +1 -0
  76. package/dist/payment/types.js +18 -0
  77. package/dist/payment/types.js.map +1 -0
  78. package/dist/rows.d.ts +26 -0
  79. package/dist/rows.d.ts.map +1 -0
  80. package/dist/rows.js +87 -0
  81. package/dist/rows.js.map +1 -0
  82. package/dist/shipping/store.d.ts +88 -0
  83. package/dist/shipping/store.d.ts.map +1 -0
  84. package/dist/shipping/store.js +165 -0
  85. package/dist/shipping/store.js.map +1 -0
  86. package/dist/subscription/store.d.ts +106 -0
  87. package/dist/subscription/store.d.ts.map +1 -0
  88. package/dist/subscription/store.js +310 -0
  89. package/dist/subscription/store.js.map +1 -0
  90. package/dist/tables.d.ts +41 -0
  91. package/dist/tables.d.ts.map +1 -0
  92. package/dist/tables.js +383 -0
  93. package/dist/tables.js.map +1 -0
  94. package/dist/tax/store.d.ts +68 -0
  95. package/dist/tax/store.d.ts.map +1 -0
  96. package/dist/tax/store.js +126 -0
  97. package/dist/tax/store.js.map +1 -0
  98. package/package.json +42 -0
@@ -0,0 +1,301 @@
1
+ import { CogentaError, identifier, limit, newId, sql, } from '@cogenta/core';
2
+ import { couponRefusal } from '../cart/store.js';
3
+ import { toInt, toNullableText, toText } from '../rows.js';
4
+ import { TABLES } from '../tables.js';
5
+ import { assertTransition, holdsStock } from './types.js';
6
+ /**
7
+ * A short, unambiguous order reference.
8
+ *
9
+ * Not the UUID: a person reads this aloud on the phone and types it into a
10
+ * bank transfer. Crockford's alphabet without I, L, O and U — the four that
11
+ * get misread as 1, 1, 0 and V, and the one that makes accidental words.
12
+ */
13
+ const REFERENCE_ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
14
+ export function referenceFrom(id) {
15
+ let hash = 0x811c9dc5;
16
+ for (const character of id) {
17
+ hash ^= character.codePointAt(0) ?? 0;
18
+ hash = Math.imul(hash, 0x01000193) >>> 0;
19
+ }
20
+ let out = '';
21
+ let value = hash;
22
+ for (let index = 0; index < 8; index += 1) {
23
+ out += REFERENCE_ALPHABET[value % REFERENCE_ALPHABET.length];
24
+ value = Math.floor(value / REFERENCE_ALPHABET.length);
25
+ if (value === 0)
26
+ value = hash + index + 1;
27
+ }
28
+ return out;
29
+ }
30
+ export function createOrderStore(db, dependencies, now = Date.now) {
31
+ const d = db.dialect;
32
+ const orders = identifier(TABLES.orders, d);
33
+ const orderLines = identifier(TABLES.orderLines, d);
34
+ const orderEvents = identifier(TABLES.orderEvents, d);
35
+ const carts = identifier(TABLES.carts, d);
36
+ const stamp = () => new Date(now()).toISOString();
37
+ async function linesOf(orderId, executor = db) {
38
+ const result = await executor.query(sql `select * from ${orderLines} where order_id = ${orderId} order by position asc, id asc`);
39
+ return result.rows.map((row) => ({
40
+ id: toText(row.id, 'order_line.id'),
41
+ variantId: toText(row.variant_id, 'order_line.variant_id'),
42
+ sku: toText(row.sku, 'order_line.sku'),
43
+ title: toText(row.title, 'order_line.title'),
44
+ quantity: toInt(row.quantity, 'order_line.quantity'),
45
+ unitPriceMinor: toInt(row.unit_price_minor, 'order_line.unit_price_minor'),
46
+ subtotalMinor: toInt(row.subtotal_minor, 'order_line.subtotal_minor'),
47
+ discountMinor: toInt(row.discount_minor, 'order_line.discount_minor'),
48
+ taxMinor: toInt(row.tax_minor, 'order_line.tax_minor'),
49
+ taxRateBp: toInt(row.tax_rate_bp, 'order_line.tax_rate_bp'),
50
+ totalMinor: toInt(row.total_minor, 'order_line.total_minor'),
51
+ position: toInt(row.position, 'order_line.position'),
52
+ }));
53
+ }
54
+ async function decode(row, executor = db) {
55
+ const id = toText(row.id, 'order.id');
56
+ return {
57
+ id,
58
+ reference: toText(row.reference, 'order.reference'),
59
+ customerId: toNullableText(row.customer_id),
60
+ email: toText(row.email, 'order.email'),
61
+ status: toText(row.status, 'order.status'),
62
+ currency: toText(row.currency, 'order.currency'),
63
+ subtotalMinor: toInt(row.subtotal_minor, 'order.subtotal_minor'),
64
+ discountMinor: toInt(row.discount_minor, 'order.discount_minor'),
65
+ shippingMinor: toInt(row.shipping_minor, 'order.shipping_minor'),
66
+ taxMinor: toInt(row.tax_minor, 'order.tax_minor'),
67
+ totalMinor: toInt(row.total_minor, 'order.total_minor'),
68
+ couponCode: toNullableText(row.coupon_code),
69
+ shippingCountry: toNullableText(row.shipping_country),
70
+ shippingRegion: toNullableText(row.shipping_region),
71
+ shippingMethodId: toNullableText(row.shipping_method_id),
72
+ shippingMethodLabel: toNullableText(row.shipping_method_label),
73
+ subscriptionId: toNullableText(row.subscription_id),
74
+ lines: await linesOf(id, executor),
75
+ placedAt: toText(row.placed_at, 'order.placed_at'),
76
+ updatedAt: toText(row.updated_at, 'order.updated_at'),
77
+ };
78
+ }
79
+ async function read(id, executor = db) {
80
+ const result = await executor.query(sql `select * from ${orders} where id = ${id}`);
81
+ const row = result.rows[0];
82
+ return row === undefined ? null : decode(row, executor);
83
+ }
84
+ async function load(id) {
85
+ const order = await read(id);
86
+ if (order === null) {
87
+ throw new CogentaError({
88
+ code: 'COMMERCE_ORDER_NOT_FOUND',
89
+ message: 'This order does not exist.',
90
+ hint: 'Check the order reference, or refresh the order list.',
91
+ });
92
+ }
93
+ return order;
94
+ }
95
+ async function appendEvent(executor, orderId, kind, fields = {}) {
96
+ await executor.query(sql `
97
+ insert into ${orderEvents} (id, order_id, at, kind, from_status, to_status, actor_id, note)
98
+ values (${newId(now)}, ${orderId}, ${stamp()}, ${kind},
99
+ ${fields.fromStatus ?? null}, ${fields.toStatus ?? null},
100
+ ${fields.actorId ?? null}, ${fields.note ?? null})`);
101
+ }
102
+ return {
103
+ place: async (input) => {
104
+ const priced = await dependencies.carts.price(input.cartId);
105
+ const { cart, totals } = priced;
106
+ if (cart.status !== 'open') {
107
+ throw new CogentaError({
108
+ code: 'COMMERCE_CART_CLOSED',
109
+ message: 'This basket has already been ordered.',
110
+ hint: 'Look at the order it produced rather than the basket.',
111
+ });
112
+ }
113
+ if (totals.lines.length === 0)
114
+ return { kind: 'empty' };
115
+ const customer = await dependencies.customers.ensure(input.email, input.customerName);
116
+ // Re-checked here, at the last possible moment, against the *final*
117
+ // subtotal. The check the cart did was for the shopper's benefit; this
118
+ // one is the one that decides, because a coupon can expire or be
119
+ // exhausted between adding it and paying.
120
+ if (cart.couponCode !== null) {
121
+ const check = await dependencies.coupons.check(cart.couponCode, totals.subtotalMinor, cart.currency);
122
+ if (check.kind !== 'ok') {
123
+ return { kind: 'coupon_refused', reason: couponRefusal(check).message };
124
+ }
125
+ }
126
+ const id = newId(now);
127
+ const reference = referenceFrom(id);
128
+ const at = stamp();
129
+ try {
130
+ // ONE transaction, taken immediate. Everything below is either all
131
+ // true or none of it happened.
132
+ return await db.transaction(async (tx) => {
133
+ const taken = await dependencies.catalog.takeStock(totals.lines.map((line) => ({
134
+ variantId: line.variantId,
135
+ quantity: line.quantity,
136
+ })), tx);
137
+ if (taken.kind === 'short') {
138
+ throw new PlacementRefused({
139
+ kind: 'out_of_stock',
140
+ shortfalls: taken.shortfalls,
141
+ });
142
+ }
143
+ if (cart.couponCode !== null) {
144
+ const claimed = await dependencies.coupons.redeem(cart.couponCode, id, customer.id, tx);
145
+ if (!claimed) {
146
+ // Lost the last redemption to somebody else between the check
147
+ // above and here. The whole transaction unwinds, so the stock
148
+ // that was just taken goes back too.
149
+ throw new PlacementRefused({
150
+ kind: 'coupon_refused',
151
+ reason: 'This discount code was fully used a moment ago.',
152
+ });
153
+ }
154
+ }
155
+ await tx.query(sql `
156
+ insert into ${orders} (id, reference, customer_id, email, status, currency,
157
+ subtotal_minor, discount_minor, shipping_minor, tax_minor, total_minor,
158
+ coupon_code, shipping_country, shipping_region,
159
+ shipping_method_id, shipping_method_label,
160
+ placed_at, updated_at, subscription_id)
161
+ values (${id}, ${reference}, ${customer.id}, ${customer.email}, ${'pending'}, ${cart.currency},
162
+ ${totals.subtotalMinor}, ${totals.discountMinor}, ${totals.shippingMinor},
163
+ ${totals.taxMinor}, ${totals.totalMinor},
164
+ ${cart.couponCode}, ${cart.shippingCountry}, ${cart.shippingRegion},
165
+ ${cart.shippingMethodId}, ${null}, ${at}, ${at}, ${null})`);
166
+ for (const [position, line] of totals.lines.entries()) {
167
+ await tx.query(sql `
168
+ insert into ${orderLines} (id, order_id, variant_id, sku, title, quantity,
169
+ unit_price_minor, subtotal_minor, discount_minor,
170
+ tax_minor, tax_rate_bp, total_minor, position)
171
+ values (${newId(now)}, ${id}, ${line.variantId}, ${line.sku}, ${line.title},
172
+ ${line.quantity}, ${line.unitPriceMinor}, ${line.subtotalMinor},
173
+ ${line.discountMinor}, ${line.taxMinor}, ${line.taxRateBp},
174
+ ${line.totalMinor}, ${position})`);
175
+ }
176
+ await tx.query(sql `
177
+ update ${carts} set status = ${'ordered'}, order_id = ${id}, updated_at = ${at}
178
+ where id = ${cart.id} and status = ${'open'}`);
179
+ await appendEvent(tx, id, 'placed', {
180
+ toStatus: 'pending',
181
+ actorId: input.actorId ?? null,
182
+ note: `Order ${reference} placed.`,
183
+ });
184
+ const order = await read(id, tx);
185
+ if (order === null) {
186
+ throw new CogentaError({
187
+ code: 'INTERNAL',
188
+ message: 'The order was not stored.',
189
+ hint: 'Check that the commerce tables exist (ensureCommerceTables).',
190
+ });
191
+ }
192
+ return { kind: 'placed', order };
193
+ }, { immediate: true });
194
+ }
195
+ catch (error) {
196
+ if (error instanceof PlacementRefused)
197
+ return error.outcome;
198
+ throw error;
199
+ }
200
+ },
201
+ read: async (id) => read(id),
202
+ readByReference: async (reference) => {
203
+ const result = await db.query(sql `select * from ${orders} where reference = ${reference.trim().toUpperCase()}`);
204
+ const row = result.rows[0];
205
+ return row === undefined ? null : decode(row);
206
+ },
207
+ list: async (options) => {
208
+ let statement = sql `select * from ${orders}`;
209
+ if (options?.status !== undefined && options.customerId !== undefined) {
210
+ statement = sql `${statement} where status = ${options.status} and customer_id = ${options.customerId}`;
211
+ }
212
+ else if (options?.status !== undefined) {
213
+ statement = sql `${statement} where status = ${options.status}`;
214
+ }
215
+ else if (options?.customerId !== undefined) {
216
+ statement = sql `${statement} where customer_id = ${options.customerId}`;
217
+ }
218
+ statement = sql `${statement} order by placed_at desc, id desc limit ${limit(options?.limit ?? 100)} offset ${limit(options?.offset ?? 0)}`;
219
+ const result = await db.query(statement);
220
+ const decoded = [];
221
+ for (const row of result.rows)
222
+ decoded.push(await decode(row));
223
+ return decoded;
224
+ },
225
+ transition: async (id, to, options) => {
226
+ return db.transaction(async (tx) => {
227
+ const current = await read(id, tx);
228
+ if (current === null) {
229
+ throw new CogentaError({
230
+ code: 'COMMERCE_ORDER_NOT_FOUND',
231
+ message: 'This order does not exist.',
232
+ hint: 'Check the order reference, or refresh the order list.',
233
+ });
234
+ }
235
+ assertTransition(current.status, to);
236
+ // Goods that are no longer promised go back on the shelf, in the
237
+ // same transaction as the status change. Doing it afterwards is how
238
+ // a crash between the two leaves stock permanently lost.
239
+ if (holdsStock(current.status) && !holdsStock(to)) {
240
+ await dependencies.catalog.restock(current.lines.map((line) => ({
241
+ variantId: line.variantId,
242
+ quantity: line.quantity,
243
+ })), tx);
244
+ }
245
+ // A cancellation before payment hands the coupon back. A refund does
246
+ // not: the code was genuinely used, and a shop that returns a
247
+ // one-shot code on every refund has given away two discounts.
248
+ if (to === 'cancelled' && current.couponCode !== null) {
249
+ await dependencies.coupons.release(id, tx);
250
+ }
251
+ await tx.query(sql `update ${orders} set status = ${to}, updated_at = ${stamp()} where id = ${id}`);
252
+ await appendEvent(tx, id, 'status_changed', {
253
+ fromStatus: current.status,
254
+ toStatus: to,
255
+ actorId: options?.actorId ?? null,
256
+ note: options?.note ?? null,
257
+ });
258
+ const updated = await read(id, tx);
259
+ if (updated === null) {
260
+ throw new CogentaError({
261
+ code: 'COMMERCE_ORDER_NOT_FOUND',
262
+ message: 'This order disappeared while it was being updated.',
263
+ hint: 'Refresh the order list.',
264
+ });
265
+ }
266
+ return updated;
267
+ }, { immediate: true });
268
+ },
269
+ history: async (id) => {
270
+ const result = await db.query(sql `select * from ${orderEvents} where order_id = ${id} order by at asc, id asc`);
271
+ return result.rows.map((row) => ({
272
+ id: toText(row.id, 'order_event.id'),
273
+ orderId: toText(row.order_id, 'order_event.order_id'),
274
+ at: toText(row.at, 'order_event.at'),
275
+ kind: toText(row.kind, 'order_event.kind'),
276
+ fromStatus: toNullableText(row.from_status),
277
+ toStatus: toNullableText(row.to_status),
278
+ actorId: toNullableText(row.actor_id),
279
+ note: toNullableText(row.note),
280
+ }));
281
+ },
282
+ record: async (id, kind, options, tx) => {
283
+ if (tx === undefined)
284
+ await load(id);
285
+ await appendEvent(tx ?? db, id, kind, {
286
+ actorId: options?.actorId ?? null,
287
+ note: options?.note ?? null,
288
+ });
289
+ },
290
+ };
291
+ }
292
+ /** Internal. Unwinds the placement transaction with a caller-facing outcome. */
293
+ class PlacementRefused extends Error {
294
+ outcome;
295
+ constructor(outcome) {
296
+ super(`order placement refused: ${outcome.kind}`);
297
+ this.name = 'PlacementRefused';
298
+ this.outcome = outcome;
299
+ }
300
+ }
301
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/order/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * What can happen to an order, and in what order.
3
+ *
4
+ * A closed union with an explicit transition table, rather than a free string
5
+ * and a hope. Two things follow from that and both matter: an impossible
6
+ * transition ("delivered" back to "pending") is refused rather than recorded,
7
+ * and every screen that switches on a status is forced by the compiler to
8
+ * handle a new one the day it is added.
9
+ */
10
+ export declare const ORDER_STATUSES: readonly ['pending', 'paid', 'shipped', 'delivered', 'cancelled', 'refunded'];
11
+ export type OrderStatus = (typeof ORDER_STATUSES)[number];
12
+ export declare function canTransition(from: OrderStatus, to: OrderStatus): boolean;
13
+ export declare function assertTransition(from: OrderStatus, to: OrderStatus): void;
14
+ /** Statuses in which the goods are still promised, so stock stays taken. */
15
+ export declare function holdsStock(status: OrderStatus): boolean;
16
+ export interface OrderLine {
17
+ readonly id: string;
18
+ readonly variantId: string;
19
+ /** Copied at placement. A product renamed next year must not rewrite history. */
20
+ readonly sku: string;
21
+ readonly title: string;
22
+ readonly quantity: number;
23
+ readonly unitPriceMinor: number;
24
+ readonly subtotalMinor: number;
25
+ readonly discountMinor: number;
26
+ readonly taxMinor: number;
27
+ readonly taxRateBp: number;
28
+ readonly totalMinor: number;
29
+ readonly position: number;
30
+ }
31
+ export interface Order {
32
+ readonly id: string;
33
+ /** Human-facing, unique, unrelated to any invoice number. */
34
+ readonly reference: string;
35
+ readonly customerId: string | null;
36
+ readonly email: string;
37
+ readonly status: OrderStatus;
38
+ readonly currency: string;
39
+ readonly subtotalMinor: number;
40
+ readonly discountMinor: number;
41
+ readonly shippingMinor: number;
42
+ readonly taxMinor: number;
43
+ readonly totalMinor: number;
44
+ readonly couponCode: string | null;
45
+ readonly shippingCountry: string | null;
46
+ readonly shippingRegion: string | null;
47
+ readonly shippingMethodId: string | null;
48
+ readonly shippingMethodLabel: string | null;
49
+ readonly subscriptionId: string | null;
50
+ readonly lines: readonly OrderLine[];
51
+ readonly placedAt: string;
52
+ readonly updatedAt: string;
53
+ }
54
+ export declare const ORDER_EVENT_KINDS: readonly ['placed', 'status_changed', 'payment_started', 'payment_settled', 'payment_failed', 'refunded', 'invoiced', 'note'];
55
+ export type OrderEventKind = (typeof ORDER_EVENT_KINDS)[number];
56
+ /** One line of an order's history. Append-only: nothing here is ever edited. */
57
+ export interface OrderEvent {
58
+ readonly id: string;
59
+ readonly orderId: string;
60
+ readonly at: string;
61
+ readonly kind: OrderEventKind;
62
+ readonly fromStatus: OrderStatus | null;
63
+ readonly toStatus: OrderStatus | null;
64
+ readonly actorId: string | null;
65
+ readonly note: string | null;
66
+ }
67
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/order/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { CogentaError } from '@cogenta/core';
2
+ /**
3
+ * What can happen to an order, and in what order.
4
+ *
5
+ * A closed union with an explicit transition table, rather than a free string
6
+ * and a hope. Two things follow from that and both matter: an impossible
7
+ * transition ("delivered" back to "pending") is refused rather than recorded,
8
+ * and every screen that switches on a status is forced by the compiler to
9
+ * handle a new one the day it is added.
10
+ */
11
+ export const ORDER_STATUSES = [
12
+ 'pending',
13
+ 'paid',
14
+ 'shipped',
15
+ 'delivered',
16
+ 'cancelled',
17
+ 'refunded',
18
+ ];
19
+ /**
20
+ * The transitions a shop actually performs.
21
+ *
22
+ * Deliberately not a full graph. Notably absent:
23
+ *
24
+ * - nothing leaves `delivered` except `refunded`. Goods that arrived did
25
+ * arrive; the remedy is a refund, not a rewind.
26
+ * - nothing leaves `cancelled` or `refunded` at all. Both are ends. Reviving a
27
+ * cancelled order would mean re-taking stock that was already put back,
28
+ * which is a second sale wearing the first one's number.
29
+ * - `pending → shipped` is not allowed. Sending goods before payment is a
30
+ * decision a person makes deliberately, by marking the order paid first, so
31
+ * that the reason is recorded rather than implied.
32
+ */
33
+ const TRANSITIONS = {
34
+ pending: ['paid', 'cancelled'],
35
+ paid: ['shipped', 'cancelled', 'refunded'],
36
+ shipped: ['delivered', 'refunded'],
37
+ delivered: ['refunded'],
38
+ cancelled: [],
39
+ refunded: [],
40
+ };
41
+ export function canTransition(from, to) {
42
+ return (TRANSITIONS[from] ?? []).includes(to);
43
+ }
44
+ export function assertTransition(from, to) {
45
+ if (canTransition(from, to))
46
+ return;
47
+ const allowed = TRANSITIONS[from] ?? [];
48
+ throw new CogentaError({
49
+ code: 'COMMERCE_ORDER_TRANSITION_INVALID',
50
+ message: `An order that is ${from} cannot become ${to}.`,
51
+ hint: allowed.length === 0
52
+ ? `${from} is a final state. Nothing follows it.`
53
+ : `From ${from}, an order can become: ${allowed.join(', ')}.`,
54
+ details: { from, to },
55
+ });
56
+ }
57
+ /** Statuses in which the goods are still promised, so stock stays taken. */
58
+ export function holdsStock(status) {
59
+ return status === 'pending' || status === 'paid' || status === 'shipped' || status === 'delivered';
60
+ }
61
+ export const ORDER_EVENT_KINDS = [
62
+ 'placed',
63
+ 'status_changed',
64
+ 'payment_started',
65
+ 'payment_settled',
66
+ 'payment_failed',
67
+ 'refunded',
68
+ 'invoiced',
69
+ 'note',
70
+ ];
71
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/order/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAE5C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,SAAS;IACT,MAAM;IACN,SAAS;IACT,WAAW;IACX,WAAW;IACX,UAAU;CACF,CAAA;AAGV;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,GAA0D;IACzE,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC;IAC9B,IAAI,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,CAAC;IAC1C,OAAO,EAAE,CAAC,WAAW,EAAE,UAAU,CAAC;IAClC,SAAS,EAAE,CAAC,UAAU,CAAC;IACvB,SAAS,EAAE,EAAE;IACb,QAAQ,EAAE,EAAE;CACb,CAAA;AAED,MAAM,UAAU,aAAa,CAAC,IAAiB,EAAE,EAAe;IAC9D,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;AAC/C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAiB,EAAE,EAAe;IACjE,IAAI,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC;QAAE,OAAM;IAEnC,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IACvC,MAAM,IAAI,YAAY,CAAC;QACrB,IAAI,EAAE,mCAAmC;QACzC,OAAO,EAAE,oBAAoB,IAAI,kBAAkB,EAAE,GAAG;QACxD,IAAI,EACF,OAAO,CAAC,MAAM,KAAK,CAAC;YAClB,CAAC,CAAC,GAAG,IAAI,wCAAwC;YACjD,CAAC,CAAC,QAAQ,IAAI,0BAA0B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;QACjE,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;KACtB,CAAC,CAAA;AACJ,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CAAC,MAAmB;IAC5C,OAAO,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,WAAW,CAAA;AACpG,CAAC;AA0CD,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,QAAQ;IACR,gBAAgB;IAChB,iBAAiB;IACjB,iBAAiB;IACjB,gBAAgB;IAChB,UAAU;IACV,UAAU;IACV,MAAM;CACE,CAAA"}
@@ -0,0 +1,27 @@
1
+ import type { PaymentConfig, PaymentDriver, PaymentGateway } from './types.js';
2
+ /**
3
+ * Payment by bank transfer. The degraded driver, and a real way to be paid.
4
+ *
5
+ * R1 and R2 are not negotiable: a shop must work end to end with no Stripe
6
+ * account, no API key and no outbound network. This is what makes that true.
7
+ * It is emphatically **not** a stub — a great many businesses invoice and are
8
+ * paid by transfer, and nothing else. The difference from Stripe is not
9
+ * "pretend" versus "real", it is *who confirms the money arrived*: a gateway
10
+ * says so over an API, and here a human says so, by marking the payment
11
+ * received once they have seen it on the statement.
12
+ *
13
+ * That is why it holds no state of its own. There is nothing to poll: the
14
+ * truth lives in the payment row that `PaymentStore` owns, and a driver that
15
+ * kept a second copy would only be able to disagree with it.
16
+ */
17
+ /** The reference a shopper is asked to put on the transfer. */
18
+ export declare function transferReference(orderReference: string): string;
19
+ export declare function createManualPaymentGateway(config?: PaymentConfig): PaymentGateway;
20
+ /**
21
+ * The degraded tier, and therefore the last one the registry tries — and the
22
+ * one it always finds. `available()` is unconditionally true because there is
23
+ * nothing that could be unavailable, which is precisely the property R1 asks a
24
+ * degraded driver to have.
25
+ */
26
+ export declare function manualPaymentDriver(): PaymentDriver;
27
+ //# sourceMappingURL=manual.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manual.d.ts","sourceRoot":"","sources":["../../src/payment/manual.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,aAAa,EACb,aAAa,EACb,cAAc,EAEf,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;GAcG;AAEH,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAEhE;AAkBD,wBAAgB,0BAA0B,CAAC,MAAM,GAAE,aAAkB,GAAG,cAAc,CA6CrF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,CAwBnD"}
@@ -0,0 +1,105 @@
1
+ import { CogentaError } from '@cogenta/core';
2
+ import { assertCurrency, assertMinor, formatMoney } from '../money.js';
3
+ /**
4
+ * Payment by bank transfer. The degraded driver, and a real way to be paid.
5
+ *
6
+ * R1 and R2 are not negotiable: a shop must work end to end with no Stripe
7
+ * account, no API key and no outbound network. This is what makes that true.
8
+ * It is emphatically **not** a stub — a great many businesses invoice and are
9
+ * paid by transfer, and nothing else. The difference from Stripe is not
10
+ * "pretend" versus "real", it is *who confirms the money arrived*: a gateway
11
+ * says so over an API, and here a human says so, by marking the payment
12
+ * received once they have seen it on the statement.
13
+ *
14
+ * That is why it holds no state of its own. There is nothing to poll: the
15
+ * truth lives in the payment row that `PaymentStore` owns, and a driver that
16
+ * kept a second copy would only be able to disagree with it.
17
+ */
18
+ /** The reference a shopper is asked to put on the transfer. */
19
+ export function transferReference(orderReference) {
20
+ return orderReference.toUpperCase();
21
+ }
22
+ const DEFAULT_INSTRUCTIONS = 'Pay by bank transfer. Your order is reserved and will be prepared once the transfer arrives.';
23
+ function instructionsFor(config, request) {
24
+ const amount = formatMoney({
25
+ amountMinor: request.amountMinor,
26
+ currency: request.currency,
27
+ });
28
+ const preamble = config.transferInstructions ?? DEFAULT_INSTRUCTIONS;
29
+ return [
30
+ preamble,
31
+ `Amount: ${amount}`,
32
+ `Reference to quote: ${transferReference(request.orderReference)}`,
33
+ ].join('\n');
34
+ }
35
+ export function createManualPaymentGateway(config = {}) {
36
+ return {
37
+ name: 'manual',
38
+ settlesOffline: true,
39
+ start: async (request) => {
40
+ assertMinor(request.amountMinor, 'A payment amount');
41
+ assertCurrency(request.currency);
42
+ return {
43
+ // The order's own reference *is* the external id here: it is what the
44
+ // shopper types into their bank, and what the operator matches against
45
+ // the statement. Inventing a second identifier would only give a human
46
+ // two numbers to reconcile instead of one.
47
+ externalId: transferReference(request.orderReference),
48
+ status: 'pending',
49
+ instructions: instructionsFor(config, request),
50
+ };
51
+ },
52
+ fetch: async (externalId) => ({
53
+ externalId,
54
+ // Deliberately unchanged. There is nothing to ask: no API knows whether
55
+ // this transfer landed, and returning anything else would be a guess
56
+ // dressed up as a fact.
57
+ status: 'pending',
58
+ instructions: null,
59
+ }),
60
+ refund: async (request) => {
61
+ assertMinor(request.amountMinor, 'A refund amount');
62
+ assertCurrency(request.currency);
63
+ // A transfer back is made by a human too. `pending` is honest: the money
64
+ // has not moved yet, and only the operator can say when it has.
65
+ return { externalId: request.externalId, status: 'pending' };
66
+ },
67
+ verifyEvent: async () => {
68
+ throw new CogentaError({
69
+ code: 'COMMERCE_PAYMENT_UNSUPPORTED',
70
+ message: 'Bank transfer has no inbound notification to verify.',
71
+ hint: 'A transfer is confirmed by a person marking the payment received, not by a webhook.',
72
+ });
73
+ },
74
+ };
75
+ }
76
+ /**
77
+ * The degraded tier, and therefore the last one the registry tries — and the
78
+ * one it always finds. `available()` is unconditionally true because there is
79
+ * nothing that could be unavailable, which is precisely the property R1 asks a
80
+ * degraded driver to have.
81
+ */
82
+ export function manualPaymentDriver() {
83
+ let gateway;
84
+ return {
85
+ name: 'manual',
86
+ tier: 'degraded',
87
+ available: async () => true,
88
+ init: async (config) => {
89
+ gateway = createManualPaymentGateway(config);
90
+ return gateway;
91
+ },
92
+ dispose: async () => {
93
+ gateway = undefined;
94
+ },
95
+ health: async () => ({
96
+ status: 'ok',
97
+ driver: 'manual',
98
+ tier: 'degraded',
99
+ message: gateway === undefined
100
+ ? 'Not started yet. Bank transfer needs no external service.'
101
+ : 'Bank transfer needs no external service, so it is never down.',
102
+ }),
103
+ };
104
+ }
105
+ //# sourceMappingURL=manual.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manual.js","sourceRoot":"","sources":["../../src/payment/manual.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { type DriverRegistry, type Logger } from '@cogenta/core';
2
+ import type { PaymentConfig, PaymentGateway } from './types.js';
3
+ export interface PaymentRegistryOptions {
4
+ readonly logger?: Logger;
5
+ }
6
+ /**
7
+ * The payment gateways Cogenta ships.
8
+ *
9
+ * Registered in tier order, exactly like cache, queue, storage and database:
10
+ * Stripe is `optimal` and answers only when a key is configured and the API
11
+ * responds; bank transfer is `degraded` and always answers. So a site with no
12
+ * Stripe account does not fail to start and does not fall over at checkout —
13
+ * it takes bank transfers, which is a real way to be paid, not a placeholder.
14
+ *
15
+ * The registry's two rules apply here with more force than anywhere else in
16
+ * the project. If the configuration **names** Stripe, a Stripe outage is fatal
17
+ * rather than a silent downgrade: quietly switching a shop that expects card
18
+ * payments over to "please make a transfer" would change what customers are
19
+ * asked to do without anybody deciding to. If the configuration names nothing,
20
+ * the fall-through is the point.
21
+ */
22
+ export declare function createPaymentRegistry(options?: PaymentRegistryOptions): DriverRegistry<PaymentGateway, PaymentConfig>;
23
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/payment/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAA;AAGtF,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE/D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,sBAA2B,GACnC,cAAc,CAAC,cAAc,EAAE,aAAa,CAAC,CAW/C"}