@owlmeans/server-payment 0.1.18-rc.20 → 0.1.18-rc.21
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/README.md +1 -1
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-payment/SKILL.md +402 -260
- package/build/config.d.ts +15 -1
- package/build/config.d.ts.map +1 -1
- package/build/config.js +99 -3
- package/build/config.js.map +1 -1
- package/build/consts.d.ts +27 -0
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +27 -0
- package/build/consts.js.map +1 -1
- package/build/consumer/capture.d.ts +74 -0
- package/build/consumer/capture.d.ts.map +1 -0
- package/build/consumer/capture.js +291 -0
- package/build/consumer/capture.js.map +1 -0
- package/build/consumer/format.d.ts +27 -0
- package/build/consumer/format.d.ts.map +1 -0
- package/build/consumer/format.js +81 -0
- package/build/consumer/format.js.map +1 -0
- package/build/consumer/handlers.d.ts +28 -0
- package/build/consumer/handlers.d.ts.map +1 -0
- package/build/consumer/handlers.js +173 -0
- package/build/consumer/handlers.js.map +1 -0
- package/build/consumer/index.d.ts +7 -0
- package/build/consumer/index.d.ts.map +1 -0
- package/build/consumer/index.js +6 -0
- package/build/consumer/index.js.map +1 -0
- package/build/consumer/mail.d.ts +27 -0
- package/build/consumer/mail.d.ts.map +1 -0
- package/build/consumer/mail.js +314 -0
- package/build/consumer/mail.js.map +1 -0
- package/build/consumer/origin.d.ts +14 -0
- package/build/consumer/origin.d.ts.map +1 -0
- package/build/consumer/origin.js +47 -0
- package/build/consumer/origin.js.map +1 -0
- package/build/consumer/reconcile.d.ts +12 -0
- package/build/consumer/reconcile.d.ts.map +1 -0
- package/build/consumer/reconcile.js +317 -0
- package/build/consumer/reconcile.js.map +1 -0
- package/build/consumer/records.d.ts +78 -0
- package/build/consumer/records.d.ts.map +1 -0
- package/build/consumer/records.js +296 -0
- package/build/consumer/records.js.map +1 -0
- package/build/consumer/service.d.ts +51 -0
- package/build/consumer/service.d.ts.map +1 -0
- package/build/consumer/service.js +760 -0
- package/build/consumer/service.js.map +1 -0
- package/build/consumer/withdrawal.d.ts +57 -0
- package/build/consumer/withdrawal.d.ts.map +1 -0
- package/build/consumer/withdrawal.js +247 -0
- package/build/consumer/withdrawal.js.map +1 -0
- package/build/index.d.ts +4 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -2
- package/build/index.js.map +1 -1
- package/build/model.d.ts +6 -1
- package/build/model.d.ts.map +1 -1
- package/build/model.js +134 -4
- package/build/model.js.map +1 -1
- package/build/observer.d.ts +4 -0
- package/build/observer.d.ts.map +1 -1
- package/build/observer.js +13 -0
- package/build/observer.js.map +1 -1
- package/build/plugins/checkout-plugins.d.ts +49 -0
- package/build/plugins/checkout-plugins.d.ts.map +1 -0
- package/build/plugins/checkout-plugins.js +124 -0
- package/build/plugins/checkout-plugins.js.map +1 -0
- package/build/plugins/estimate.d.ts.map +1 -1
- package/build/plugins/estimate.js +41 -8
- package/build/plugins/estimate.js.map +1 -1
- package/build/plugins/events.d.ts +2 -0
- package/build/plugins/events.d.ts.map +1 -1
- package/build/plugins/events.js +126 -9
- package/build/plugins/events.js.map +1 -1
- package/build/plugins/fx.d.ts +5 -0
- package/build/plugins/fx.d.ts.map +1 -1
- package/build/plugins/fx.js +25 -0
- package/build/plugins/fx.js.map +1 -1
- package/build/plugins/portal.d.ts.map +1 -1
- package/build/plugins/portal.js +11 -1
- package/build/plugins/portal.js.map +1 -1
- package/build/plugins/stripe.d.ts +21 -2
- package/build/plugins/stripe.d.ts.map +1 -1
- package/build/plugins/stripe.js +397 -61
- package/build/plugins/stripe.js.map +1 -1
- package/build/resource.d.ts +8 -1
- package/build/resource.d.ts.map +1 -1
- package/build/resource.js +59 -2
- package/build/resource.js.map +1 -1
- package/build/service.d.ts +2 -1
- package/build/service.d.ts.map +1 -1
- package/build/service.js +28 -5
- package/build/service.js.map +1 -1
- package/build/subscription.d.ts +6 -0
- package/build/subscription.d.ts.map +1 -1
- package/build/subscription.js +1 -0
- package/build/subscription.js.map +1 -1
- package/build/sync.d.ts +7 -0
- package/build/sync.d.ts.map +1 -1
- package/build/sync.js +108 -15
- package/build/sync.js.map +1 -1
- package/build/types.d.ts +707 -4
- package/build/types.d.ts.map +1 -1
- package/build/utils.d.ts +22 -1
- package/build/utils.d.ts.map +1 -1
- package/build/utils.js +27 -1
- package/build/utils.js.map +1 -1
- package/package.json +14 -13
- package/src/config.ts +111 -7
- package/src/consts.ts +34 -0
- package/src/consumer/capture.ts +362 -0
- package/src/consumer/format.ts +90 -0
- package/src/consumer/handlers.ts +211 -0
- package/src/consumer/index.ts +6 -0
- package/src/consumer/mail.ts +368 -0
- package/src/consumer/origin.ts +63 -0
- package/src/consumer/reconcile.ts +329 -0
- package/src/consumer/records.ts +374 -0
- package/src/consumer/service.ts +868 -0
- package/src/consumer/withdrawal.ts +302 -0
- package/src/index.ts +6 -4
- package/src/model.ts +148 -6
- package/src/observer.ts +15 -2
- package/src/plugins/checkout-plugins.ts +155 -0
- package/src/plugins/estimate.ts +49 -9
- package/src/plugins/events.ts +135 -11
- package/src/plugins/fx.ts +29 -0
- package/src/plugins/portal.ts +11 -1
- package/src/plugins/stripe.ts +476 -60
- package/src/resource.ts +87 -4
- package/src/service.ts +28 -6
- package/src/subscription.ts +7 -0
- package/src/sync.ts +124 -17
- package/src/types.ts +756 -6
- package/src/utils.ts +56 -7
- package/tests/checkout-consumer.spec.ts +348 -0
- package/tests/checkout-plugins.spec.ts +164 -0
- package/tests/consumer-events.spec.ts +218 -0
- package/tests/consumer-fixtures.ts +132 -0
- package/tests/consumer-ops.spec.ts +351 -0
- package/tests/consumer-rights.integration.spec.ts +150 -0
- package/tests/consumer-rights.spec.ts +501 -0
- package/tests/context.ts +20 -2
- package/tests/fake-stripe.ts +188 -18
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { billingLanguageOf, chargeCurrencyOf, ConsumerRegion, ConsumerRightsError, ENTITLING_STATUSES, inScope, PurchaseKind, regionOf, withdrawalOpen, } from '@owlmeans/payment';
|
|
2
|
+
import { PURCHASE_ID_PREFIX, STRIPE_PAYGATE_ALIAS } from '../consts.js';
|
|
3
|
+
import { billingProfiles, compact, conditionalDelete, consumerEvents, fulfillments, isDuplicateKey, paygateCustomers, purchases, stripePricingConfig, subscriptions, } from '../utils.js';
|
|
4
|
+
import { makeContractRef, normalizeEmail } from './format.js';
|
|
5
|
+
export const purchaseIdOf = (externalId) => `${PURCHASE_ID_PREFIX}:${externalId}`;
|
|
6
|
+
/** A locked profile as the wire sees it. */
|
|
7
|
+
export const profileViewOf = (record, policy) => ({
|
|
8
|
+
country: record.country,
|
|
9
|
+
region: record.region,
|
|
10
|
+
currency: record.currency,
|
|
11
|
+
locked: true,
|
|
12
|
+
lockedAt: new Date(record.lockedAt),
|
|
13
|
+
language: record.language,
|
|
14
|
+
inScope: inScope(record.region, record.country, policy),
|
|
15
|
+
});
|
|
16
|
+
/** No profile yet: nothing locked, the default legal language, an unknown buyer (protected by default). */
|
|
17
|
+
export const unlockedProfileView = (policy) => ({
|
|
18
|
+
country: null,
|
|
19
|
+
region: null,
|
|
20
|
+
currency: null,
|
|
21
|
+
locked: false,
|
|
22
|
+
language: policy?.defaultLanguage ?? 'en',
|
|
23
|
+
inScope: inScope(null, null, policy),
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* Append one audit step. A failure to write it is logged and never fails the act it describes —
|
|
27
|
+
* the act's own record (consent, declaration, purchase) is already written.
|
|
28
|
+
*/
|
|
29
|
+
export const recordEvent = async (ctx, event) => {
|
|
30
|
+
try {
|
|
31
|
+
await consumerEvents(ctx).create(compact({ ...event, at: event.at ?? new Date() }));
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.error(`[payment] consumer event "${event.action}" of "${event.recordId}" not recorded`, error);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/** Whether a step already succeeded (or a mail was deliberately skipped) for a record. */
|
|
38
|
+
export const hasEvent = async (ctx, recordId, action, step, ok) => await consumerEvents(ctx).load(compact({
|
|
39
|
+
recordId, action, ...(step != null ? { step } : {}), ...(ok != null ? { ok } : {}),
|
|
40
|
+
})) != null;
|
|
41
|
+
/** The currency of the entity's entitling Stripe subscription — two of one customer cannot differ. */
|
|
42
|
+
export const activeSubscriptionCurrency = async (ctx, entityId) => {
|
|
43
|
+
const row = await entitlingStripeSubscription(ctx, entityId);
|
|
44
|
+
return row?.currency ?? undefined;
|
|
45
|
+
};
|
|
46
|
+
/** The entity's highest-ranked entitling Stripe subscription, or `null`. */
|
|
47
|
+
export const entitlingStripeSubscription = async (ctx, entityId) => await subscriptions(ctx).load({ entityId, paygate: STRIPE_PAYGATE_ALIAS, status: [...ENTITLING_STATUSES] }, { sort: [{ field: 'rank', order: 'desc' }, { field: 'createdAt', order: 'desc' }] });
|
|
48
|
+
/** Whether the entity ever paid through the paygate (a fulfilled checkout or a propagated subscription). */
|
|
49
|
+
export const hasPaid = async (ctx, entityId) => await fulfillments(ctx).load({ entityId, paygate: STRIPE_PAYGATE_ALIAS, fulfilledAt: { $exists: true } }) != null
|
|
50
|
+
|| await subscriptions(ctx).load({ entityId, paygate: STRIPE_PAYGATE_ALIAS, initialPropagatedAt: { $exists: true } }) != null;
|
|
51
|
+
/**
|
|
52
|
+
* Fix an entity's billing country — the FIRST write wins (a unique index on `entityId` settles a
|
|
53
|
+
* race). A later, different country is only a `lock-mismatch` event; only a `manual` lock with
|
|
54
|
+
* `force` replaces the country, audited as `relock`. The charge currency is fixed with it: the
|
|
55
|
+
* currency of an entitling paygate subscription when one exists (a customer's subscriptions share
|
|
56
|
+
* one currency), else the region's (`policy.currencies`), else the given one.
|
|
57
|
+
*/
|
|
58
|
+
export const lockProfile = async (ctx, policy, input) => {
|
|
59
|
+
const country = input.country.trim().toUpperCase();
|
|
60
|
+
if (!/^[A-Z]{2}$/.test(country)) {
|
|
61
|
+
throw new ConsumerRightsError(`lock:country:${input.country}`);
|
|
62
|
+
}
|
|
63
|
+
const resource = billingProfiles(ctx);
|
|
64
|
+
const now = new Date();
|
|
65
|
+
const existing = await resource.byEntity(input.entityId);
|
|
66
|
+
if (existing != null) {
|
|
67
|
+
return await compareLock(ctx, policy, existing, input, country, now);
|
|
68
|
+
}
|
|
69
|
+
const region = regionOf(country, policy) ?? ConsumerRegion.Other;
|
|
70
|
+
const settlement = (await stripePricingConfig(ctx))?.settlementCurrency?.toLowerCase();
|
|
71
|
+
const currency = (await activeSubscriptionCurrency(ctx, input.entityId))
|
|
72
|
+
?? (policy?.currencies != null && Object.keys(policy.currencies).length > 0
|
|
73
|
+
? chargeCurrencyOf(region, policy, input.currency ?? settlement ?? 'usd')
|
|
74
|
+
: input.currency ?? settlement ?? 'usd');
|
|
75
|
+
const record = compact({
|
|
76
|
+
entityId: input.entityId,
|
|
77
|
+
country,
|
|
78
|
+
region,
|
|
79
|
+
currency: currency.toLowerCase(),
|
|
80
|
+
language: input.language ?? billingLanguageOf(country, policy),
|
|
81
|
+
source: input.source,
|
|
82
|
+
paygate: STRIPE_PAYGATE_ALIAS,
|
|
83
|
+
customerId: input.customerId,
|
|
84
|
+
sessionId: input.sessionId,
|
|
85
|
+
ipCountry: input.ipCountry?.toUpperCase(),
|
|
86
|
+
email: input.email,
|
|
87
|
+
name: input.name,
|
|
88
|
+
business: input.business,
|
|
89
|
+
lockedAt: now,
|
|
90
|
+
createdAt: now,
|
|
91
|
+
});
|
|
92
|
+
try {
|
|
93
|
+
const created = await resource.create(record);
|
|
94
|
+
await recordEvent(ctx, {
|
|
95
|
+
recordId: input.entityId, recordKind: 'profile', entityId: input.entityId, action: 'lock', ok: true,
|
|
96
|
+
detail: JSON.stringify(compact({
|
|
97
|
+
source: input.source, country, currency: created.currency, sessionId: input.sessionId,
|
|
98
|
+
ipCountry: input.ipCountry?.toUpperCase(),
|
|
99
|
+
ipMismatch: input.ipCountry != null ? input.ipCountry.toUpperCase() !== country : undefined,
|
|
100
|
+
by: input.by, reason: input.reason,
|
|
101
|
+
})),
|
|
102
|
+
});
|
|
103
|
+
return { record: created, created: true, mismatch: false };
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (!isDuplicateKey(error)) {
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
const winner = await resource.byEntity(input.entityId);
|
|
110
|
+
if (winner == null) {
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
return await compareLock(ctx, policy, winner, input, country, now);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const compareLock = async (ctx, policy, existing, input, country, now) => {
|
|
117
|
+
if (input.source === 'manual' && input.force === true) {
|
|
118
|
+
const region = regionOf(country, policy) ?? ConsumerRegion.Other;
|
|
119
|
+
const updated = await billingProfiles(ctx).update(compact({
|
|
120
|
+
...existing,
|
|
121
|
+
country,
|
|
122
|
+
region,
|
|
123
|
+
currency: (input.currency ?? (country === existing.country ? existing.currency
|
|
124
|
+
: chargeCurrencyOf(region, policy, existing.currency))).toLowerCase(),
|
|
125
|
+
language: input.language ?? (country === existing.country ? existing.language : billingLanguageOf(country, policy)),
|
|
126
|
+
source: 'manual',
|
|
127
|
+
updatedAt: now,
|
|
128
|
+
}));
|
|
129
|
+
await recordEvent(ctx, {
|
|
130
|
+
recordId: existing.entityId, recordKind: 'profile', entityId: existing.entityId, action: 'relock', ok: true,
|
|
131
|
+
detail: JSON.stringify(compact({
|
|
132
|
+
from: existing.country, to: country, currency: updated.currency, by: input.by, reason: input.reason,
|
|
133
|
+
})),
|
|
134
|
+
});
|
|
135
|
+
return { record: updated, created: false, mismatch: false };
|
|
136
|
+
}
|
|
137
|
+
const mismatch = existing.country !== country;
|
|
138
|
+
if (mismatch) {
|
|
139
|
+
await recordEvent(ctx, {
|
|
140
|
+
recordId: existing.entityId, recordKind: 'profile', entityId: existing.entityId, action: 'lock-mismatch',
|
|
141
|
+
ok: true,
|
|
142
|
+
detail: JSON.stringify(compact({
|
|
143
|
+
locked: existing.country, observed: country, source: input.source, sessionId: input.sessionId,
|
|
144
|
+
ipCountry: input.ipCountry,
|
|
145
|
+
})),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return { record: existing, created: false, mismatch };
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* An operator removes an entity's lock: the profile row is deleted (only while it still holds the
|
|
152
|
+
* country read — a concurrent relock survives) and an `unlock` event keeps the whole row, `by` and
|
|
153
|
+
* `reason`. `null` when nothing was locked.
|
|
154
|
+
*/
|
|
155
|
+
export const unlockProfile = async (ctx, entityId, opts = {}) => {
|
|
156
|
+
const resource = billingProfiles(ctx);
|
|
157
|
+
const existing = await resource.byEntity(entityId);
|
|
158
|
+
if (existing == null) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
if (!await conditionalDelete(resource, { entityId, country: existing.country })) {
|
|
162
|
+
throw new ConsumerRightsError(`unlock:changed:${entityId}`);
|
|
163
|
+
}
|
|
164
|
+
const { id: _id, ...row } = existing;
|
|
165
|
+
await recordEvent(ctx, {
|
|
166
|
+
recordId: entityId, recordKind: 'profile', entityId, action: 'unlock', ok: true,
|
|
167
|
+
detail: JSON.stringify(compact({ from: existing.country, by: opts.by, reason: opts.reason, profile: row })),
|
|
168
|
+
});
|
|
169
|
+
return existing;
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Whether an operator unlocked the entity — then no lock is taken from its paygate customer's saved
|
|
173
|
+
* address (at checkout or in reconcile): its next completed purchase locks it.
|
|
174
|
+
*/
|
|
175
|
+
export const wasUnlocked = async (ctx, entityId) => await hasEvent(ctx, entityId, 'unlock');
|
|
176
|
+
/** Inside its window at `at`: in scope, before the deadline, neither withdrawn from nor refunded. */
|
|
177
|
+
export const windowOpen = (purchase, at = new Date()) => purchase.inScope && withdrawalOpen({
|
|
178
|
+
deadline: purchase.deadline != null ? new Date(purchase.deadline) : null,
|
|
179
|
+
withdrawnAt: purchase.withdrawnAt ?? null,
|
|
180
|
+
refundedAt: purchase.refundedAt ?? null,
|
|
181
|
+
}, at);
|
|
182
|
+
export const purchaseViewOf = (purchase, withdrawable) => compact({
|
|
183
|
+
purchaseId: purchase.purchaseId,
|
|
184
|
+
contractRef: purchase.contractRef,
|
|
185
|
+
kind: purchase.kind,
|
|
186
|
+
purchasedAt: new Date(purchase.purchasedAt),
|
|
187
|
+
deadline: purchase.deadline != null ? new Date(purchase.deadline) : undefined,
|
|
188
|
+
productSku: purchase.productSku,
|
|
189
|
+
planSku: purchase.planSku ?? undefined,
|
|
190
|
+
amountTotalMinor: purchase.amountTotalMinor,
|
|
191
|
+
currency: purchase.currency,
|
|
192
|
+
consentedAt: purchase.consentedAt != null ? new Date(purchase.consentedAt) : undefined,
|
|
193
|
+
withdrawnAt: purchase.withdrawnAt != null ? new Date(purchase.withdrawnAt) : undefined,
|
|
194
|
+
withdrawable,
|
|
195
|
+
});
|
|
196
|
+
export const purchaseRefOf = (purchase) => compact({
|
|
197
|
+
purchaseId: purchase.purchaseId,
|
|
198
|
+
kind: purchase.kind,
|
|
199
|
+
entityId: purchase.entityId,
|
|
200
|
+
contractRef: purchase.contractRef,
|
|
201
|
+
productSku: purchase.productSku,
|
|
202
|
+
planSku: purchase.planSku ?? undefined,
|
|
203
|
+
sessionId: purchase.sessionId ?? undefined,
|
|
204
|
+
subscriptionId: purchase.subscriptionId ?? undefined,
|
|
205
|
+
invoiceId: purchase.invoiceId ?? undefined,
|
|
206
|
+
purchasedAt: new Date(purchase.purchasedAt),
|
|
207
|
+
});
|
|
208
|
+
/** The open, unconsented top-up windows of an entity — what a performance consent covers. */
|
|
209
|
+
export const unconsentedWindows = async (ctx, entityId, at = new Date()) => (await purchases(ctx).list({
|
|
210
|
+
entityId, inScope: true, kind: PurchaseKind.TopUp, consentedAt: null, withdrawnAt: null, refundedAt: null,
|
|
211
|
+
deadline: { $gt: at },
|
|
212
|
+
}, { size: 100, sort: [{ field: 'deadline', order: 'desc' }] })).items;
|
|
213
|
+
const CONTRACT_REF_ATTEMPTS = 6;
|
|
214
|
+
/**
|
|
215
|
+
* Write a purchase once: an existing row for the same purchase (or the same checkout session) is
|
|
216
|
+
* returned as it is. A contract-reference collision retries with a fresh reference.
|
|
217
|
+
*/
|
|
218
|
+
export const createPurchase = async (ctx, draft) => {
|
|
219
|
+
const resource = purchases(ctx);
|
|
220
|
+
const existing = await resource.byPurchaseId(draft.purchaseId)
|
|
221
|
+
?? (draft.sessionId != null ? await resource.load({ sessionId: draft.sessionId }) : null);
|
|
222
|
+
if (existing != null) {
|
|
223
|
+
return { record: existing, created: false };
|
|
224
|
+
}
|
|
225
|
+
let last = null;
|
|
226
|
+
for (let attempt = 0; attempt < CONTRACT_REF_ATTEMPTS; attempt++) {
|
|
227
|
+
try {
|
|
228
|
+
const record = await resource.create(compact({
|
|
229
|
+
...draft, contractRef: makeContractRef(new Date(draft.purchasedAt)), createdAt: new Date(),
|
|
230
|
+
}));
|
|
231
|
+
return { record, created: true };
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
if (!isDuplicateKey(error)) {
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
last = error;
|
|
238
|
+
const winner = await resource.byPurchaseId(draft.purchaseId)
|
|
239
|
+
?? (draft.sessionId != null ? await resource.load({ sessionId: draft.sessionId }) : null);
|
|
240
|
+
if (winner != null) {
|
|
241
|
+
return { record: winner, created: false };
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
console.error('[payment] no free contract reference after retries', last);
|
|
246
|
+
throw new ConsumerRightsError('contract-ref');
|
|
247
|
+
};
|
|
248
|
+
/** Set fields on a purchase without replacing it (a concurrent conditional write survives). */
|
|
249
|
+
export const patchPurchase = async (ctx, purchaseId, fields) => {
|
|
250
|
+
const set = Object.fromEntries(Object.entries({ ...fields, updatedAt: new Date() }).filter(([, value]) => value !== undefined));
|
|
251
|
+
const resource = purchases(ctx);
|
|
252
|
+
const collection = resource.collection;
|
|
253
|
+
if (collection?.updateOne != null) {
|
|
254
|
+
await collection.updateOne({ purchaseId }, { $set: set });
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const current = await resource.byPurchaseId(purchaseId);
|
|
258
|
+
if (current != null) {
|
|
259
|
+
await resource.update({ ...current, ...set });
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
/** The e-mail a consumer-rights mail reaches the organization at when no person named one. */
|
|
263
|
+
export const contactEmailOf = async (ctx, entityId) => {
|
|
264
|
+
const profile = await billingProfiles(ctx).byEntity(entityId);
|
|
265
|
+
if (profile?.email != null && profile.email !== '') {
|
|
266
|
+
return profile.email;
|
|
267
|
+
}
|
|
268
|
+
const latest = await purchases(ctx).load({ entityId, email: { $exists: true } }, {
|
|
269
|
+
sort: [{ field: 'purchasedAt', order: 'desc' }],
|
|
270
|
+
});
|
|
271
|
+
if (latest?.email != null && latest.email !== '') {
|
|
272
|
+
return latest.email;
|
|
273
|
+
}
|
|
274
|
+
const customer = await paygateCustomers(ctx).byEntity(entityId, STRIPE_PAYGATE_ALIAS);
|
|
275
|
+
return customer?.email ?? undefined;
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Whether an e-mail address belongs to a purchase: its checkout e-mail, the organization's
|
|
279
|
+
* profile e-mail or its paygate customer's — compared case-insensitively.
|
|
280
|
+
*/
|
|
281
|
+
export const emailMatches = async (ctx, purchase, email) => {
|
|
282
|
+
const wanted = normalizeEmail(email);
|
|
283
|
+
if (wanted === '') {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
if (normalizeEmail(purchase.email) === wanted) {
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
const profile = await billingProfiles(ctx).byEntity(purchase.entityId);
|
|
290
|
+
if (normalizeEmail(profile?.email) === wanted) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
const customer = await paygateCustomers(ctx).byEntity(purchase.entityId, STRIPE_PAYGATE_ALIAS);
|
|
294
|
+
return normalizeEmail(customer?.email) === wanted;
|
|
295
|
+
};
|
|
296
|
+
//# sourceMappingURL=records.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"records.js","sourceRoot":"","sources":["../../src/consumer/records.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type Stripe from 'stripe';
|
|
2
|
+
import { CancellationStatus, WithdrawalStatus } from '@owlmeans/payment';
|
|
3
|
+
import type { Context as ApiContext } from '@owlmeans/server-api';
|
|
4
|
+
import type { WithdrawalComputation, WithdrawalExecution } from './withdrawal.js';
|
|
5
|
+
import type { Config, ConsumerConsentRecord, ConsumerDeclarationRecord, ConsumerRightsOptions, ConsumerRightsService, Context, PaymentSubscriptionRecord, PurchaseRecord, UsageMeter } from '../types.js';
|
|
6
|
+
export interface ConsumerRightsInternals {
|
|
7
|
+
readonly managed: boolean;
|
|
8
|
+
meter: () => UsageMeter | null;
|
|
9
|
+
stripe: (ctx: ApiContext) => Promise<Stripe>;
|
|
10
|
+
}
|
|
11
|
+
/** Who hands a registration its options: the application itself, or the gateway on its behalf. */
|
|
12
|
+
export type ConsumerRightsRegistrar = 'application' | 'gateway';
|
|
13
|
+
/** Run the consumer-rights observers of one act; a throw is recorded for `reconcile` to retry. */
|
|
14
|
+
export declare const runConsumerObservers: (ctx: ApiContext, family: 'consent' | 'withdrawal' | 'cancellation', recordId: string, entityId: string | undefined, run: () => Promise<void>) => Promise<boolean>;
|
|
15
|
+
/** Tell the withdrawal observers — after the records and the paygate steps. */
|
|
16
|
+
export declare const notifyWithdrawal: (ctx: ApiContext, declaration: ConsumerDeclarationRecord, purchase: PurchaseRecord, status: WithdrawalStatus, computation: Pick<WithdrawalComputation, 'reading' | 'deducted' | 'unitsReturned' | 'netMinor' | 'refundMinor'> | null, execution: WithdrawalExecution | null) => Promise<boolean>;
|
|
17
|
+
/** Tell the cancellation observers. */
|
|
18
|
+
export declare const notifyCancellation: (ctx: ApiContext, declaration: ConsumerDeclarationRecord, status: CancellationStatus) => Promise<boolean>;
|
|
19
|
+
/** Tell the consent observers. */
|
|
20
|
+
export declare const notifyConsent: (ctx: ApiContext, consent: ConsumerConsentRecord) => Promise<boolean>;
|
|
21
|
+
/**
|
|
22
|
+
* Schedule an ordinary cancellation at the paygate: at the period end (`cancel_at_period_end`), or
|
|
23
|
+
* at a later boundary (`cancel_at`, no proration). Recorded as a `cancel-scheduled` event.
|
|
24
|
+
*/
|
|
25
|
+
export declare const scheduleCancellation: (ctx: ApiContext, stripe: Stripe, declaration: ConsumerDeclarationRecord, row: PaymentSubscriptionRecord, attempt?: number) => Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* The consumer-rights service (`CONSUMER_RIGHTS_SERVICE`): the billing profile and its lock,
|
|
28
|
+
* purchases and their withdrawal windows, performance consent and subscription start requests,
|
|
29
|
+
* the withdrawal and cancellation functions with their paygate steps, the durable-medium mails,
|
|
30
|
+
* and `reconcile`. Unmanaged (`manage: false`) it still reads, records consents and asserts them;
|
|
31
|
+
* withdrawing and cancelling need the paygate.
|
|
32
|
+
*
|
|
33
|
+
* A lazy service, like the completion observer: `useMeter` / `useMailRenderer` work while the
|
|
34
|
+
* application is still being wired, before the context initializes.
|
|
35
|
+
*/
|
|
36
|
+
export declare const makeConsumerRightsService: (alias?: string, opts?: ConsumerRightsOptions) => ConsumerRightsService;
|
|
37
|
+
/**
|
|
38
|
+
* Register the consumer-rights resources and service (each only when absent), or configure the
|
|
39
|
+
* service already registered — `from` says who asks. The order of the application's call and the
|
|
40
|
+
* gateway's is free: `usage` and `stripe` are installed whenever they come, and the application's
|
|
41
|
+
* explicit `manage` wins over the gateway's. The resources keep the first registration's aliases.
|
|
42
|
+
*/
|
|
43
|
+
export declare const registerConsumerRights: <C extends Config, T extends Context<C>>(ctx: T, opts?: ConsumerRightsOptions, from?: ConsumerRightsRegistrar) => T;
|
|
44
|
+
/**
|
|
45
|
+
* Register the consumer-rights resources and service, each only when absent — the gateway
|
|
46
|
+
* registration does too. Called before or after the gateway, it installs `usage` and `stripe` on
|
|
47
|
+
* the service and its explicit `manage` wins over the gateway's; `useMeter` and `useMailRenderer`
|
|
48
|
+
* work on the service at any time.
|
|
49
|
+
*/
|
|
50
|
+
export declare const appendConsumerRights: <C extends Config, T extends Context<C>>(ctx: T, opts?: ConsumerRightsOptions) => T;
|
|
51
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/consumer/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAA;AAGhC,OAAO,EACsC,kBAAkB,EAI7D,gBAAgB,EACjB,MAAM,mBAAmB,CAAA;AAK1B,OAAO,KAAK,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAiBjE,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACjF,OAAO,KAAK,EACV,MAAM,EAAE,qBAAqB,EAAE,yBAAyB,EAAwB,qBAAqB,EACrG,qBAAqB,EAAE,OAAO,EAAE,yBAAyB,EAAE,cAAc,EAAE,UAAU,EACtF,MAAM,aAAa,CAAA;AAmEpB,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,KAAK,EAAE,MAAM,UAAU,GAAG,IAAI,CAAA;IAC9B,MAAM,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAC7C;AAED,kGAAkG;AAClG,MAAM,MAAM,uBAAuB,GAAG,aAAa,GAAG,SAAS,CAAA;AAQ/D,kGAAkG;AAClG,eAAO,MAAM,oBAAoB,QAC1B,UAAU,UAAU,SAAS,GAAG,YAAY,GAAG,cAAc,YAAY,MAAM,YAAY,MAAM,GAAG,SAAS,OAC7G,MAAM,OAAO,CAAC,IAAI,CAAC,KACvB,OAAO,CAAC,OAAO,CAajB,CAAA;AAED,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,QACtB,UAAU,eAAe,yBAAyB,YAAY,cAAc,UAAU,gBAAgB,eAC9F,IAAI,CAAC,qBAAqB,EAAE,SAAS,GAAG,UAAU,GAAG,eAAe,GAAG,UAAU,GAAG,aAAa,CAAC,GAAG,IAAI,aAC3G,mBAAmB,GAAG,IAAI,KACpC,OAAO,CAAC,OAAO,CAoBhB,CAAA;AAEF,uCAAuC;AACvC,eAAO,MAAM,kBAAkB,QACxB,UAAU,eAAe,yBAAyB,UAAU,kBAAkB,KAClF,OAAO,CAAC,OAAO,CAahB,CAAA;AAEF,kCAAkC;AAClC,eAAO,MAAM,aAAa,QAAe,UAAU,WAAW,qBAAqB,KAAG,OAAO,CAAC,OAAO,CASjG,CAAA;AAEJ;;;GAGG;AACH,eAAO,MAAM,oBAAoB,QAC1B,UAAU,UAAU,MAAM,eAAe,yBAAyB,OAAO,yBAAyB,YAC9F,MAAM,KACd,OAAO,CAAC,OAAO,CAyBjB,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,WAC7B,MAAM,SAAkC,qBAAqB,KACnE,qBAohBF,CAAA;AAwDD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,OACtE,CAAC,SAAQ,qBAAqB,SAAa,uBAAuB,KACtE,CAsBF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,OACpE,CAAC,SAAQ,qBAAqB,KAClC,CAAqD,CAAA"}
|