@endora-commerce/mod-payments 0.100.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.
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/admin/index.d.ts +32 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +61 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/zones/OrderPaymentsTab.d.ts +42 -0
- package/dist/admin/zones/OrderPaymentsTab.d.ts.map +1 -0
- package/dist/admin/zones/OrderPaymentsTab.js +104 -0
- package/dist/admin/zones/OrderPaymentsTab.js.map +1 -0
- package/dist/backend/adapters/built-in-adapters.d.ts +58 -0
- package/dist/backend/adapters/built-in-adapters.d.ts.map +1 -0
- package/dist/backend/adapters/built-in-adapters.js +83 -0
- package/dist/backend/adapters/built-in-adapters.js.map +1 -0
- package/dist/backend/drivers/bank-transfer-driver.d.ts +28 -0
- package/dist/backend/drivers/bank-transfer-driver.d.ts.map +1 -0
- package/dist/backend/drivers/bank-transfer-driver.js +26 -0
- package/dist/backend/drivers/bank-transfer-driver.js.map +1 -0
- package/dist/backend/drivers/gateway-adapter-port.d.ts +71 -0
- package/dist/backend/drivers/gateway-adapter-port.d.ts.map +1 -0
- package/dist/backend/drivers/gateway-adapter-port.js +18 -0
- package/dist/backend/drivers/gateway-adapter-port.js.map +1 -0
- package/dist/backend/drivers/pickup-driver.d.ts +23 -0
- package/dist/backend/drivers/pickup-driver.d.ts.map +1 -0
- package/dist/backend/drivers/pickup-driver.js +19 -0
- package/dist/backend/drivers/pickup-driver.js.map +1 -0
- package/dist/backend/email-templates/transactional-defaults.d.ts +6 -0
- package/dist/backend/email-templates/transactional-defaults.d.ts.map +1 -0
- package/dist/backend/email-templates/transactional-defaults.js +27 -0
- package/dist/backend/email-templates/transactional-defaults.js.map +1 -0
- package/dist/backend/entities/payment.entity.d.ts +26 -0
- package/dist/backend/entities/payment.entity.d.ts.map +1 -0
- package/dist/backend/entities/payment.entity.js +100 -0
- package/dist/backend/entities/payment.entity.js.map +1 -0
- package/dist/backend/index.d.ts +88 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +318 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.customer.d.ts +20 -0
- package/dist/backend/routes.customer.d.ts.map +1 -0
- package/dist/backend/routes.customer.js +24 -0
- package/dist/backend/routes.customer.js.map +1 -0
- package/dist/backend/routes.d.ts +36 -0
- package/dist/backend/routes.d.ts.map +1 -0
- package/dist/backend/routes.js +44 -0
- package/dist/backend/routes.js.map +1 -0
- package/dist/backend/services/gateway-refund-registry.d.ts +122 -0
- package/dist/backend/services/gateway-refund-registry.d.ts.map +1 -0
- package/dist/backend/services/gateway-refund-registry.js +106 -0
- package/dist/backend/services/gateway-refund-registry.js.map +1 -0
- package/dist/backend/services/payment-email-notifier.d.ts +71 -0
- package/dist/backend/services/payment-email-notifier.d.ts.map +1 -0
- package/dist/backend/services/payment-email-notifier.js +73 -0
- package/dist/backend/services/payment-email-notifier.js.map +1 -0
- package/dist/backend/services/payment-email-renderer.d.ts +22 -0
- package/dist/backend/services/payment-email-renderer.d.ts.map +1 -0
- package/dist/backend/services/payment-email-renderer.js +17 -0
- package/dist/backend/services/payment-email-renderer.js.map +1 -0
- package/dist/backend/services/payment-placement-apply-port.d.ts +33 -0
- package/dist/backend/services/payment-placement-apply-port.d.ts.map +1 -0
- package/dist/backend/services/payment-placement-apply-port.js +68 -0
- package/dist/backend/services/payment-placement-apply-port.js.map +1 -0
- package/dist/backend/services/payment-read-port.d.ts +33 -0
- package/dist/backend/services/payment-read-port.d.ts.map +1 -0
- package/dist/backend/services/payment-read-port.js +64 -0
- package/dist/backend/services/payment-read-port.js.map +1 -0
- package/dist/backend/services/payment-reference-port.d.ts +29 -0
- package/dist/backend/services/payment-reference-port.d.ts.map +1 -0
- package/dist/backend/services/payment-reference-port.js +70 -0
- package/dist/backend/services/payment-reference-port.js.map +1 -0
- package/dist/backend/services/payment-refund.d.ts +55 -0
- package/dist/backend/services/payment-refund.d.ts.map +1 -0
- package/dist/backend/services/payment-refund.js +101 -0
- package/dist/backend/services/payment-refund.js.map +1 -0
- package/dist/backend/services/payment-retry-service.d.ts +45 -0
- package/dist/backend/services/payment-retry-service.d.ts.map +1 -0
- package/dist/backend/services/payment-retry-service.js +187 -0
- package/dist/backend/services/payment-retry-service.js.map +1 -0
- package/dist/backend/services/payment-service.d.ts +62 -0
- package/dist/backend/services/payment-service.d.ts.map +1 -0
- package/dist/backend/services/payment-service.js +134 -0
- package/dist/backend/services/payment-service.js.map +1 -0
- package/dist/backend/services/receive-payment-handler.d.ts +260 -0
- package/dist/backend/services/receive-payment-handler.d.ts.map +1 -0
- package/dist/backend/services/receive-payment-handler.js +356 -0
- package/dist/backend/services/receive-payment-handler.js.map +1 -0
- package/dist/backend/services/registry-singleton.d.ts +16 -0
- package/dist/backend/services/registry-singleton.d.ts.map +1 -0
- package/dist/backend/services/registry-singleton.js +17 -0
- package/dist/backend/services/registry-singleton.js.map +1 -0
- package/dist/manifest.d.ts +210 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +182 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260925T115728_payments_refunded_amount.d.ts +28 -0
- package/dist/migrations/20260925T115728_payments_refunded_amount.d.ts.map +1 -0
- package/dist/migrations/20260925T115728_payments_refunded_amount.js +32 -0
- package/dist/migrations/20260925T115728_payments_refunded_amount.js.map +1 -0
- package/dist/migrations/index.d.ts +27 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +29 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/payments.md +69 -0
- package/i18n/en.json +5 -0
- package/i18n/pl.json +5 -0
- package/package.json +96 -0
- package/tailwind.css +14 -0
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { defineModuleErrorCodes, defineModuleManifest, defineModuleSettingsManifest, } from '@endora-commerce/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* The error codes this module declares (D-182,
|
|
4
|
+
* `specs/090-module-owned-error-codes/`).
|
|
5
|
+
*
|
|
6
|
+
* Branded, so a typo at a raise site is a compile error rather than a code that
|
|
7
|
+
* travels the whole path and renders raw to whoever reads it. They live in this
|
|
8
|
+
* file because it is the one the package publishes at its root subpath: a
|
|
9
|
+
* sibling module under `src/` is reachable through no subpath at all, so the
|
|
10
|
+
* raise sites could name it and a consumer branching on the code could not.
|
|
11
|
+
*
|
|
12
|
+
* Declaring them in `errorCodes` below is a separate act and is what routes the
|
|
13
|
+
* sentence to this package's own `i18n/` bundle; the reasoning for the three is
|
|
14
|
+
* written there.
|
|
15
|
+
*/
|
|
16
|
+
export const paymentsErrorCodes = defineModuleErrorCodes([
|
|
17
|
+
'PAYMENT_NOT_DUE',
|
|
18
|
+
'PAYMENT_ORDER_CLOSED',
|
|
19
|
+
'PAYMENT_ADAPTER_UNAVAILABLE',
|
|
20
|
+
]);
|
|
21
|
+
export const paymentsSettingsManifest = defineModuleSettingsManifest({
|
|
22
|
+
moduleCode: 'payments',
|
|
23
|
+
groups: [{ code: 'payments', name: 'Payments' }],
|
|
24
|
+
settings: [
|
|
25
|
+
{
|
|
26
|
+
code: 'payments.enabled',
|
|
27
|
+
name: 'Payments enabled',
|
|
28
|
+
// The description used to describe the settlement half only, and stopped
|
|
29
|
+
// exactly where an operator most needs it: it never said that this module
|
|
30
|
+
// contributes every built-in payment adapter, so switching it off empties
|
|
31
|
+
// checkout's payment list and the shop stops taking orders. An operator
|
|
32
|
+
// cannot learn a switch's consequence from anywhere but the switch.
|
|
33
|
+
description: 'Switches the whole payment capability on or off. While it is off the platform offers no payment method at all: this module contributes the four built-in payment adapters (bank transfer, in-person pickup, credit limit and the gateway placeholder), so every payment method configured against one of them disappears from checkout and an order naming it is refused. Unless another installed integration supplies a payment method of its own, that means the shop stops taking orders. The settlement lifecycle stops with it: the receive_payment ingress, both retry paths (the operator\'s and the buyer\'s), the per-order payment history and the payment-status e-mail. Nothing is dropped — every payment, its status transitions and its provider references stay in the database, an order mid-settlement keeps its record, and every payment method, permission and setting comes back exactly as configured when you switch it on again. It is not an uninstall, and it is not the way to switch off a single payment provider: a gateway integration depends on this module, so the platform refuses to switch this off while such an integration is still on — switch that integration off instead.',
|
|
34
|
+
groupCode: 'payments',
|
|
35
|
+
valueType: 'boolean',
|
|
36
|
+
defaultValue: true,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Payments module — manifest backfill (Module Lifecycle, feature 018).
|
|
42
|
+
*
|
|
43
|
+
* Predates the lifecycle system; this manifest is the static record
|
|
44
|
+
* required so the module participates in the registry. No install /
|
|
45
|
+
* uninstall hook today — the module's schema is owned by earlier
|
|
46
|
+
* platform-wide migrations.
|
|
47
|
+
*/
|
|
48
|
+
export const manifest = defineModuleManifest({
|
|
49
|
+
id: 'payments',
|
|
50
|
+
name: 'Payments',
|
|
51
|
+
// What renders beside the activation control on `/platform/modules` is this
|
|
52
|
+
// string, not the activation Setting's — the Setting's description is served
|
|
53
|
+
// in the settings DTO and rendered on no screen today. So the consequence has
|
|
54
|
+
// to be legible here too, in one sentence: 'Payment driver abstraction and PSP
|
|
55
|
+
// integrations' told an operator nothing about what flipping the switch does.
|
|
56
|
+
description: 'The platform payment capability: the built-in payment adapters (bank transfer, in-person pickup, credit limit, gateway), the payment record every order carries, and the settlement lifecycle that PSP integrations plug into. Switched off, checkout offers no payment method and the shop takes no orders.',
|
|
57
|
+
version: '1.0.0',
|
|
58
|
+
// Feature 075 Phase C — `customer_accounts` joins the five that were already
|
|
59
|
+
// here: the payment-status e-mail resolves its recipient over
|
|
60
|
+
// `customerAccountReadPort` instead of reading the `CustomerAccount` entity.
|
|
61
|
+
// `orders` was already declared, which D-78 point 2 requires of the one
|
|
62
|
+
// co-transactional seam kept in `receive-payment-handler.ts` — the FK
|
|
63
|
+
// `payments_order_fk` had required it anyway.
|
|
64
|
+
// `organizations` joins for the buyer's retry route (issue #264): a suspended
|
|
65
|
+
// or blocked Organization may not pay an order any more than it may place
|
|
66
|
+
// one, and the guard is `organizationReadPort.assertCanTransact`. It is
|
|
67
|
+
// already transitively before this module through `orders`, so the entry
|
|
68
|
+
// changes no install or migration order — it states the edge.
|
|
69
|
+
dependencies: [
|
|
70
|
+
'auth',
|
|
71
|
+
'customer_accounts',
|
|
72
|
+
'delivery_methods',
|
|
73
|
+
'orders',
|
|
74
|
+
'organizations',
|
|
75
|
+
'payment_methods',
|
|
76
|
+
'transactional_emails',
|
|
77
|
+
],
|
|
78
|
+
// Feature 073 (Constitution XVII) — the operator's activation control. It only
|
|
79
|
+
// became real in T126: until this module registered its own routes there was
|
|
80
|
+
// no seam for a gate to sit on.
|
|
81
|
+
activation: { settingCode: 'payments.enabled', default: true },
|
|
82
|
+
// This module owns its authority. It shipped owning none, enforcing
|
|
83
|
+
// `catalog:read` / `catalog:write` on all three of its admin routes — which
|
|
84
|
+
// meant an operator who could edit a product could read every payment's
|
|
85
|
+
// provider payload and, through the settlement ingress, declare an arbitrary
|
|
86
|
+
// payment successful, moving the order's payment status with no money having
|
|
87
|
+
// moved. Both codes were real, declared and enforced, so the permission
|
|
88
|
+
// inventory's two directions were clean over it, and D-173's `foreign-gate`
|
|
89
|
+
// sweep passes it deliberately (`catalog` is `nonDeactivatable`, so the
|
|
90
|
+
// availability coupling that sweep asks about can never bite).
|
|
91
|
+
//
|
|
92
|
+
// A pair rather than one `payments:manage`: reading an order's payment
|
|
93
|
+
// history is support and finance work, opening a retry and declaring a
|
|
94
|
+
// settlement are money operations, and an operator organisation separates
|
|
95
|
+
// them. No third code for the ingress, though it is the most dangerous of the
|
|
96
|
+
// three routes: `POST /api/v1/payments/receive` is explicitly transitional
|
|
97
|
+
// pending a signed PSP-webhook auth path, and a code minted for it now is one
|
|
98
|
+
// that has to be migrated out of every role later — the situation
|
|
99
|
+
// `PERMISSION_CATALOGUE` records as unfixable-in-place for
|
|
100
|
+
// `integrations:manage` and `audit_log:read`. Revisit the split when that
|
|
101
|
+
// webhook path lands, which is the moment the question is answerable.
|
|
102
|
+
//
|
|
103
|
+
// No manifest `action` goes with these, and that is a decision rather than an
|
|
104
|
+
// omission: this module has no screen. Its only admin surface is a tab on an
|
|
105
|
+
// `orders` route, so a palette action would have to declare `orders:read` as
|
|
106
|
+
// its `requiredPermission` to agree with the gate on its own `targetRoute` —
|
|
107
|
+
// the `ACTION_PERMISSION_DISAGREEMENTS` shape `check:action-route-permissions`
|
|
108
|
+
// exists to refuse. The honest discovery entry for the payment history is
|
|
109
|
+
// `orders`' own.
|
|
110
|
+
permissions: [
|
|
111
|
+
{ code: 'payments:read', label: 'View payments' },
|
|
112
|
+
{ code: 'payments:write', label: 'Record and retry payments' },
|
|
113
|
+
],
|
|
114
|
+
settings: paymentsSettingsManifest,
|
|
115
|
+
// Feature 090 / D-182 — the error codes this module owns, and the first three
|
|
116
|
+
// this package has ever declared. It is not a Phase 3 migration: the prefix
|
|
117
|
+
// chain routes nothing to `payments` and this module held no bundle at all,
|
|
118
|
+
// so these are new codes rather than a family changing hands.
|
|
119
|
+
//
|
|
120
|
+
// All three are the buyer's own payment-retry refusals, and every one of them
|
|
121
|
+
// wore `VALIDATION_FAILED` with a prose sentence. That is the one code
|
|
122
|
+
// `localizeErrorEnvelope` returns *before* translating — the code is
|
|
123
|
+
// overloaded and several services carry machine-readable tokens in its
|
|
124
|
+
// message — so a Polish buyer trying to pay a declined order was answered in
|
|
125
|
+
// the raise site's English, whichever language they asked for. Same defect as
|
|
126
|
+
// the order-cancellation route, one route over: the buyer's *retry* control
|
|
127
|
+
// beside their *cancel* control.
|
|
128
|
+
//
|
|
129
|
+
// **Three codes and not one**, which is the question that had to be answered
|
|
130
|
+
// before any of them was minted. The cancellation repair collapsed four
|
|
131
|
+
// branches into one code because they were one `throw` behind a conjunction
|
|
132
|
+
// and the buyer was told the same sentence either way. These are three
|
|
133
|
+
// separate raise sites behind three orthogonal predicates, and the buyer's
|
|
134
|
+
// next move differs in each:
|
|
135
|
+
//
|
|
136
|
+
// * `PAYMENT_NOT_DUE` — the money is not the buyer's to pay: the order is
|
|
137
|
+
// paid, drawn against a credit limit (`deferred`), or refunded. Nothing
|
|
138
|
+
// to do.
|
|
139
|
+
// * `PAYMENT_ORDER_CLOSED` — the order's lifecycle status is terminal, so
|
|
140
|
+
// somebody cancelled it and the stock is already released. The buyer who
|
|
141
|
+
// still wants the goods places a new order.
|
|
142
|
+
// * `PAYMENT_ADAPTER_UNAVAILABLE` — the order is open and the money is
|
|
143
|
+
// still owed; the shop can no longer *start* a session for the method it
|
|
144
|
+
// was placed with. The buyer contacts the shop, and an operator repairs a
|
|
145
|
+
// configuration.
|
|
146
|
+
//
|
|
147
|
+
// The first two are orthogonal rather than alternative: an order can be
|
|
148
|
+
// unpaid and cancelled, or paid and open, so neither implies the other. The
|
|
149
|
+
// third is reached only once both have passed.
|
|
150
|
+
//
|
|
151
|
+
// `PAYMENT_ADAPTER_UNAVAILABLE` names the adapter rather than the method on
|
|
152
|
+
// purpose. The registry it fails on is this module's; `PAYMENT_METHOD_*` is
|
|
153
|
+
// the family `payment_methods` would reach for, and two modules declaring one
|
|
154
|
+
// code routes it to neither of them (D-182's collision rule).
|
|
155
|
+
//
|
|
156
|
+
// No `tokens`: none of the three raise sites passes a fourth argument, so
|
|
157
|
+
// `refusalToken` has nothing to read, and the bundle keys are flat.
|
|
158
|
+
errorCodes: [
|
|
159
|
+
{ code: paymentsErrorCodes.PAYMENT_NOT_DUE },
|
|
160
|
+
{ code: paymentsErrorCodes.PAYMENT_ORDER_CLOSED },
|
|
161
|
+
{ code: paymentsErrorCodes.PAYMENT_ADAPTER_UNAVAILABLE },
|
|
162
|
+
],
|
|
163
|
+
// The bundle those sentences live in. This module shipped none until now —
|
|
164
|
+
// it has no admin screen of its own — so the directory and this declaration
|
|
165
|
+
// arrive together.
|
|
166
|
+
i18n: { bundlesDir: 'i18n' },
|
|
167
|
+
docs: { dir: 'docs' },
|
|
168
|
+
// Feature 047 — admin-editable transactional email owned by this module.
|
|
169
|
+
transactionalEmails: [
|
|
170
|
+
{
|
|
171
|
+
code: 'payment_status_changed',
|
|
172
|
+
name: 'Payment status changed',
|
|
173
|
+
group: 'payments',
|
|
174
|
+
variables: [
|
|
175
|
+
{ key: 'order.businessId', label: 'Order number', sampleValue: 'ORD-1042' },
|
|
176
|
+
{ key: 'payment.statusLabel', label: 'Payment status', sampleValue: 'Paid' },
|
|
177
|
+
{ key: 'payment.failureReason', label: 'Failure reason', sampleValue: 'Card declined' },
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
});
|
|
182
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/**
|
|
3
|
+
* `payments.refunded_amount` — the cumulative refunded amount the `Payment`
|
|
4
|
+
* entity maps (`refundedAmount`), created by the module that maps it.
|
|
5
|
+
*
|
|
6
|
+
* Until feature 134 (feature 134, research D14) the
|
|
7
|
+
* only migration creating this column was `stripe`'s
|
|
8
|
+
* `Migration20260715T103358StripePaymentRefundedAmount`: an instance without
|
|
9
|
+
* `stripe` could not insert a payment, and `stripe`'s hard uninstall dropped a
|
|
10
|
+
* column this module reads and writes. That migration keeps its class name and
|
|
11
|
+
* has both bodies emptied; this one replaces it.
|
|
12
|
+
*
|
|
13
|
+
* **`if not exists`**, because the column is already present on every database
|
|
14
|
+
* that ran `stripe`'s migration, and there this must be a no-op that keeps
|
|
15
|
+
* every value.
|
|
16
|
+
*
|
|
17
|
+
* **`down()` is deliberately empty.** The `payments` table is created by the
|
|
18
|
+
* platform's frozen `core_commerce_init`, which a hard uninstall of this module
|
|
19
|
+
* never reverts, so the table and its rows outlive this module. Dropping the
|
|
20
|
+
* column would reset every surviving payment's refunded amount to zero on the
|
|
21
|
+
* next install, and nothing would report it: a down that removes one column
|
|
22
|
+
* from rows that survive is data loss, not a revert.
|
|
23
|
+
*/
|
|
24
|
+
export declare class Migration20260925T115728PaymentsRefundedAmount extends Migration {
|
|
25
|
+
up(): Promise<void>;
|
|
26
|
+
down(): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=20260925T115728_payments_refunded_amount.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260925T115728_payments_refunded_amount.d.ts","sourceRoot":"","sources":["../../src/migrations/20260925T115728_payments_refunded_amount.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,8CAA+C,SAAQ,SAAS;IAC5D,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAMnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/**
|
|
3
|
+
* `payments.refunded_amount` — the cumulative refunded amount the `Payment`
|
|
4
|
+
* entity maps (`refundedAmount`), created by the module that maps it.
|
|
5
|
+
*
|
|
6
|
+
* Until feature 134 (feature 134, research D14) the
|
|
7
|
+
* only migration creating this column was `stripe`'s
|
|
8
|
+
* `Migration20260715T103358StripePaymentRefundedAmount`: an instance without
|
|
9
|
+
* `stripe` could not insert a payment, and `stripe`'s hard uninstall dropped a
|
|
10
|
+
* column this module reads and writes. That migration keeps its class name and
|
|
11
|
+
* has both bodies emptied; this one replaces it.
|
|
12
|
+
*
|
|
13
|
+
* **`if not exists`**, because the column is already present on every database
|
|
14
|
+
* that ran `stripe`'s migration, and there this must be a no-op that keeps
|
|
15
|
+
* every value.
|
|
16
|
+
*
|
|
17
|
+
* **`down()` is deliberately empty.** The `payments` table is created by the
|
|
18
|
+
* platform's frozen `core_commerce_init`, which a hard uninstall of this module
|
|
19
|
+
* never reverts, so the table and its rows outlive this module. Dropping the
|
|
20
|
+
* column would reset every surviving payment's refunded amount to zero on the
|
|
21
|
+
* next install, and nothing would report it: a down that removes one column
|
|
22
|
+
* from rows that survive is data loss, not a revert.
|
|
23
|
+
*/
|
|
24
|
+
export class Migration20260925T115728PaymentsRefundedAmount extends Migration {
|
|
25
|
+
async up() {
|
|
26
|
+
this.addSql(`alter table "payments" add column if not exists "refunded_amount" numeric(14,2) not null default '0';`);
|
|
27
|
+
}
|
|
28
|
+
async down() {
|
|
29
|
+
// Intentionally empty — see the class comment.
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=20260925T115728_payments_refunded_amount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260925T115728_payments_refunded_amount.js","sourceRoot":"","sources":["../../src/migrations/20260925T115728_payments_refunded_amount.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,8CAA+C,SAAQ,SAAS;IAClE,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CACT,uGAAuG,CACxG,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,+CAA+C;IACjD,CAAC;CACF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `./migrations` subpath — every migration class this module owns, as one
|
|
3
|
+
* ordered `migrations` array.
|
|
4
|
+
*
|
|
5
|
+
* The array is what the platform reads when this module is **installed**:
|
|
6
|
+
* `src/packages/package-runtime.ts` takes `exported['migrations']` and refuses
|
|
7
|
+
* the package outright when it is absent (D-168).
|
|
8
|
+
*
|
|
9
|
+
* Listed in ascending timestamp, which orders **this module's own** migrations
|
|
10
|
+
* and nothing else (feature 081). Where the block sits relative to every other
|
|
11
|
+
* module's is decided by the manifest `dependencies` graph.
|
|
12
|
+
*
|
|
13
|
+
* The **named** exports stay, and the asymmetry with `./backend` — which
|
|
14
|
+
* publishes an array and no entity class by name (D-168) — is deliberate.
|
|
15
|
+
* `db/migrations-registry.generated.ts` imports each class by name from this
|
|
16
|
+
* specifier, and a migration class name is contract in a way an entity class
|
|
17
|
+
* name is not: `mikro_orm_migrations` persists it, so it is a string every
|
|
18
|
+
* already-migrated database holds.
|
|
19
|
+
*
|
|
20
|
+
* A class that is in neither the array nor the barrel is a migration that does
|
|
21
|
+
* not run: `migration:pending` reports nothing pending and the first symptom
|
|
22
|
+
* is a query against a table nobody created.
|
|
23
|
+
*/
|
|
24
|
+
import { Migration20260925T115728PaymentsRefundedAmount } from './20260925T115728_payments_refunded_amount.js';
|
|
25
|
+
export declare const migrations: (typeof Migration20260925T115728PaymentsRefundedAmount)[];
|
|
26
|
+
export { Migration20260925T115728PaymentsRefundedAmount, };
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,8CAA8C,EAAE,MAAM,+CAA+C,CAAC;AAE/G,eAAO,MAAM,UAAU,2DAEtB,CAAC;AAEF,OAAO,EACL,8CAA8C,GAC/C,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `./migrations` subpath — every migration class this module owns, as one
|
|
3
|
+
* ordered `migrations` array.
|
|
4
|
+
*
|
|
5
|
+
* The array is what the platform reads when this module is **installed**:
|
|
6
|
+
* `src/packages/package-runtime.ts` takes `exported['migrations']` and refuses
|
|
7
|
+
* the package outright when it is absent (D-168).
|
|
8
|
+
*
|
|
9
|
+
* Listed in ascending timestamp, which orders **this module's own** migrations
|
|
10
|
+
* and nothing else (feature 081). Where the block sits relative to every other
|
|
11
|
+
* module's is decided by the manifest `dependencies` graph.
|
|
12
|
+
*
|
|
13
|
+
* The **named** exports stay, and the asymmetry with `./backend` — which
|
|
14
|
+
* publishes an array and no entity class by name (D-168) — is deliberate.
|
|
15
|
+
* `db/migrations-registry.generated.ts` imports each class by name from this
|
|
16
|
+
* specifier, and a migration class name is contract in a way an entity class
|
|
17
|
+
* name is not: `mikro_orm_migrations` persists it, so it is a string every
|
|
18
|
+
* already-migrated database holds.
|
|
19
|
+
*
|
|
20
|
+
* A class that is in neither the array nor the barrel is a migration that does
|
|
21
|
+
* not run: `migration:pending` reports nothing pending and the first symptom
|
|
22
|
+
* is a query against a table nobody created.
|
|
23
|
+
*/
|
|
24
|
+
import { Migration20260925T115728PaymentsRefundedAmount } from './20260925T115728_payments_refunded_amount.js';
|
|
25
|
+
export const migrations = [
|
|
26
|
+
Migration20260925T115728PaymentsRefundedAmount,
|
|
27
|
+
];
|
|
28
|
+
export { Migration20260925T115728PaymentsRefundedAmount, };
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,8CAA8C,EAAE,MAAM,+CAA+C,CAAC;AAE/G,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,8CAA8C;CAC/C,CAAC;AAEF,OAAO,EACL,8CAA8C,GAC/C,CAAC"}
|
package/docs/payments.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: payments
|
|
3
|
+
description: Payment driver dispatch + settlement events
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `payments`
|
|
7
|
+
|
|
8
|
+
Payment driver dispatch + settlement events. The module owns the driver
|
|
9
|
+
port (`gateway-adapter-port.ts`) and concrete in-tree drivers; per-vendor
|
|
10
|
+
adapters live in dedicated integration modules.
|
|
11
|
+
|
|
12
|
+
## Drivers
|
|
13
|
+
|
|
14
|
+
| Driver | Behaviour |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| `bank-transfer-driver.ts` | Returns `NextAction.kind='awaiting_transfer'`; settlement happens out-of-band when the operator marks the order paid |
|
|
17
|
+
| `pickup-driver.ts` | `NextAction.kind='none'` for cash-on-pickup |
|
|
18
|
+
| `credit-limit-driver.ts` | Calls `CreditLimitService.reserve` inside the order-placement transaction |
|
|
19
|
+
| `gateway-adapter-port.ts` | Interface stub for external gateways; per-vendor implementations live outside the core |
|
|
20
|
+
|
|
21
|
+
## Public surface
|
|
22
|
+
|
|
23
|
+
Three admin routes, gated on this module's own permission codes:
|
|
24
|
+
|
|
25
|
+
| Verb + Path | Permission | Purpose |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| `GET /api/v1/admin/orders/:id/payments` | `payments:read` | Full payment history for one order, including each attempt's provider payload |
|
|
28
|
+
| `POST /api/v1/admin/orders/:id/payments/retry` | `payments:write` | Opens the next `Payment` attempt on an order |
|
|
29
|
+
| `POST /api/v1/payments/receive` | `payments:write` | The `receive_payment` settlement ingress: declares a payment succeeded or failed |
|
|
30
|
+
|
|
31
|
+
The pair is deliberate. Reading an order's payment history is support and
|
|
32
|
+
finance work; opening a retry and declaring a settlement are money operations,
|
|
33
|
+
and an operator organisation separates the two. There is no third code for the
|
|
34
|
+
settlement ingress even though it is the most dangerous of the three, because
|
|
35
|
+
that route is transitional pending a signed PSP-webhook auth path — see the
|
|
36
|
+
reasoning in `manifest.ts`.
|
|
37
|
+
|
|
38
|
+
Until `payments` declared these, all three routes were gated on `catalog:read`
|
|
39
|
+
and `catalog:write`, so an operator who could edit a product could read every
|
|
40
|
+
payment's provider payload and mark an arbitrary payment settled. **Upgrading:
|
|
41
|
+
a role that was reading payment data through `catalog:read` must be granted
|
|
42
|
+
`payments:read` explicitly on `/admin-roles`** — there is no migration, because
|
|
43
|
+
one granting `payments:read` to every holder of `catalog:read` would reproduce
|
|
44
|
+
exactly the over-grant this change removes.
|
|
45
|
+
|
|
46
|
+
The ingress body bounds its `providerDetails` to a flat map of scalars
|
|
47
|
+
(`operatorProviderDetailsSchema`): the column is persisted verbatim and served
|
|
48
|
+
back in full, so what an operator may write into it is bounded by our schema
|
|
49
|
+
rather than by the caller's payload. Gateway integrations build the payload in
|
|
50
|
+
code and are not subject to that bound.
|
|
51
|
+
|
|
52
|
+
Beyond the routes, orders consume the drivers via
|
|
53
|
+
`order-service.ts#placeOrder()`, and admin payment-status mutations go through
|
|
54
|
+
`/api/v1/admin/orders/:id/payment-status`, which `orders` owns.
|
|
55
|
+
|
|
56
|
+
The buyer's own retry (`POST /api/v1/orders/:orderId/payments/retry`) is a
|
|
57
|
+
customer route and authorises through `requireCustomer`, not a permission.
|
|
58
|
+
|
|
59
|
+
## Events emitted
|
|
60
|
+
|
|
61
|
+
`payment.settled.v1`, `payment.failed.v1`, `payment.refunded.v1`.
|
|
62
|
+
|
|
63
|
+
## Extension points
|
|
64
|
+
|
|
65
|
+
- **New gateway** — implement `gateway-adapter-port.ts`, register the
|
|
66
|
+
driver in the composition root, expose a configuration through the
|
|
67
|
+
`integrations` module.
|
|
68
|
+
- **Fraud / 3DS hooks** — slot in front of the driver's `reserve` call
|
|
69
|
+
before the order-placement transaction commits.
|
package/i18n/en.json
ADDED
package/i18n/pl.json
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"errors.PAYMENT_NOT_DUE": "To zamówienie nie oczekuje na płatność.",
|
|
3
|
+
"errors.PAYMENT_ORDER_CLOSED": "To zamówienie zostało zamknięte i nie można go już opłacić.",
|
|
4
|
+
"errors.PAYMENT_ADAPTER_UNAVAILABLE": "Metoda płatności wybrana przy składaniu tego zamówienia nie jest już dostępna."
|
|
5
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@endora-commerce/mod-payments",
|
|
3
|
+
"version": "0.100.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"description": "The platform payment capability: the built-in payment adapters (bank transfer, in-person pickup, credit limit, gateway), the payment record every order carries, and the settlement lifecycle that PSP integrations plug into. Switched off, checkout offers no payment method and the shop takes no orders.",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"endora": {
|
|
9
|
+
"type": "module",
|
|
10
|
+
"id": "payments"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/endora-commerce/endora-commerce.git",
|
|
15
|
+
"directory": "packages/modules/payments"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/manifest.d.ts",
|
|
23
|
+
"default": "./dist/manifest.js"
|
|
24
|
+
},
|
|
25
|
+
"./backend": {
|
|
26
|
+
"types": "./dist/backend/index.d.ts",
|
|
27
|
+
"default": "./dist/backend/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./migrations": {
|
|
30
|
+
"types": "./dist/migrations/index.d.ts",
|
|
31
|
+
"default": "./dist/migrations/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./admin": {
|
|
34
|
+
"types": "./dist/admin/index.d.ts",
|
|
35
|
+
"default": "./dist/admin/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./tailwind.css": "./tailwind.css",
|
|
38
|
+
"./package.json": "./package.json"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"i18n",
|
|
43
|
+
"docs",
|
|
44
|
+
"tailwind.css"
|
|
45
|
+
],
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=22.18.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@mikro-orm/core": "^6",
|
|
51
|
+
"@mikro-orm/migrations": "^6",
|
|
52
|
+
"@mikro-orm/postgresql": "^6",
|
|
53
|
+
"fastify": "^5",
|
|
54
|
+
"lucide-react": "^1",
|
|
55
|
+
"react": "^19",
|
|
56
|
+
"@endora-commerce/admin-kit": "0.100.0",
|
|
57
|
+
"@endora-commerce/contracts": "0.100.0",
|
|
58
|
+
"@endora-commerce/email-components": "0.100.0",
|
|
59
|
+
"@endora-commerce/mod-orders": "0.100.0",
|
|
60
|
+
"@endora-commerce/platform": "0.100.0"
|
|
61
|
+
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"@endora-commerce/admin-kit": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"lucide-react": {
|
|
67
|
+
"optional": true
|
|
68
|
+
},
|
|
69
|
+
"react": {
|
|
70
|
+
"optional": true
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@mikro-orm/core": "^6.6.13",
|
|
75
|
+
"@mikro-orm/migrations": "^6.6.13",
|
|
76
|
+
"@mikro-orm/postgresql": "^6.6.13",
|
|
77
|
+
"@types/node": "^22.9.0",
|
|
78
|
+
"@types/react": "^19.2.14",
|
|
79
|
+
"fastify": "^5.12.5",
|
|
80
|
+
"lucide-react": "^1.11.0",
|
|
81
|
+
"react": "^19.2.5",
|
|
82
|
+
"typescript": "^5.9.3",
|
|
83
|
+
"vitest": "^4.1.11",
|
|
84
|
+
"@endora-commerce/admin-kit": "0.100.0",
|
|
85
|
+
"@endora-commerce/email-components": "0.100.0",
|
|
86
|
+
"@endora-commerce/mod-orders": "0.100.0",
|
|
87
|
+
"@endora-commerce/platform": "0.100.0",
|
|
88
|
+
"@endora-commerce/contracts": "0.100.0"
|
|
89
|
+
},
|
|
90
|
+
"scripts": {
|
|
91
|
+
"build": "tsc -p tsconfig.build.json && tsc -p tsconfig.ui.json",
|
|
92
|
+
"typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.ui.json --noEmit",
|
|
93
|
+
"lint": "eslint src",
|
|
94
|
+
"test": "vitest run"
|
|
95
|
+
}
|
|
96
|
+
}
|
package/tailwind.css
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* @endora-commerce/mod-payments — AUTO-GENERATED by `pnpm --filter backend run manifests:generate`.
|
|
2
|
+
*
|
|
3
|
+
* The `@source` directives this package asks its host to scan
|
|
4
|
+
* (`specs/110-instance-repository/contracts/admin-stylesheet-composition.md` R1).
|
|
5
|
+
* They resolve relative to **this file**, so they hold wherever the package is
|
|
6
|
+
* installed — a workspace link here, `node_modules` in a client's instance.
|
|
7
|
+
*
|
|
8
|
+
* The `dist` line is what a published tarball ships and is what an instance
|
|
9
|
+
* scans; the `src` line is inert there and is what keeps `pnpm --filter admin
|
|
10
|
+
* run dev` reading source in this repository. Do not edit: run
|
|
11
|
+
* `pnpm --filter backend run manifests:generate`.
|
|
12
|
+
*/
|
|
13
|
+
@source "./dist/admin";
|
|
14
|
+
@source "./src/admin";
|