@fabriktor/fx 0.0.130 → 0.0.132
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PaymentEntityTypeBill, PaymentEntityTypePayroll, type Bill, type Payroll, PSPPaymentStatusPending, PSPPaymentStatusPartial, PSPPaymentStatusFull, type CreditLedgerEntry, type Payment, type PmtAccount, type PmtBankAccount, type PmtCard, type PmtCustomer, type PmtPublicSession, type PmtRefund } from "@fabriktor/schema";
|
|
1
|
+
import { PaymentEntityTypeBill, PaymentEntityTypePayroll, type Bill, type Payroll, PSPPaymentStatusPending, PSPPaymentStatusPartial, PSPPaymentStatusFull, type CreditLedgerEntry, type Payment, type PmtAccount, type PmtBankAccount, type PmtCard, type PmtCustomer, type PmtPublicSession, type PmtRefund, type SortStripeBalanceResult } from "@fabriktor/schema";
|
|
2
2
|
import { type PaymentsOperator, type BillableOperator, type PayrollsOperator } from "@fabriktor/client";
|
|
3
3
|
import { type SearchOptions, type OwnerSearchOptions, type SearchPage } from "../core/search.js";
|
|
4
4
|
import { EventBus } from "../core/events.js";
|
|
@@ -86,11 +86,23 @@ export type CreateEntityPaymentOptions = {
|
|
|
86
86
|
};
|
|
87
87
|
export type CreatePaymentOptions = PaymentInsertOptions & MultiCreateCheckpoint;
|
|
88
88
|
export type ReplacePaymentOptions = PaymentReplaceOptions;
|
|
89
|
-
export type
|
|
89
|
+
export type PaymentSearchFilters = {
|
|
90
90
|
type?: Payment["type"] | Payment["type"][];
|
|
91
91
|
kind?: Payment["kind"];
|
|
92
|
+
psp_actionable_status?: Payment["psp_actionable_status"][];
|
|
93
|
+
currency?: string;
|
|
92
94
|
};
|
|
95
|
+
export type SearchPaymentsOptions = SearchOptions & EntityPaymentScope & PaymentSearchFilters;
|
|
93
96
|
export type SearchPaymentsPage = SearchPage<Payment>;
|
|
97
|
+
export declare const PaymentDirection: {
|
|
98
|
+
readonly Outgoing: "outgoing";
|
|
99
|
+
readonly Incoming: "incoming";
|
|
100
|
+
};
|
|
101
|
+
export type PaymentDirection = (typeof PaymentDirection)[keyof typeof PaymentDirection];
|
|
102
|
+
export type SearchPaymentHistoryOptions = OwnerSearchOptions & PaymentSearchFilters & {
|
|
103
|
+
direction: PaymentDirection;
|
|
104
|
+
};
|
|
105
|
+
export declare function isIncomingPayment(payment: Payment, viewerID: string): boolean;
|
|
94
106
|
export type CreatePmtAccountOptions = PmtAccountInsertOptions;
|
|
95
107
|
export type ContinuePmtAccountOnboardingOptions = PmtAccountOnboardingOptions;
|
|
96
108
|
export type ContinuePmtAccountOnboardingResult = string;
|
|
@@ -137,6 +149,11 @@ export type GetPmtAccountAccessOptions = {
|
|
|
137
149
|
owner_id: string;
|
|
138
150
|
signal?: AbortSignal;
|
|
139
151
|
};
|
|
152
|
+
export type GetPayoutBalanceOptions = GetPmtAccountAccessOptions;
|
|
153
|
+
export type PayoutBalance = {
|
|
154
|
+
access: PmtAccountAccess;
|
|
155
|
+
balance: SortStripeBalanceResult | null;
|
|
156
|
+
};
|
|
140
157
|
export declare function isPmtAccountReady(account: PmtAccount | null): boolean;
|
|
141
158
|
export declare function currentPmtAccount(accounts: readonly PmtAccount[]): PmtAccount | null;
|
|
142
159
|
export declare function pmtAccountAccess(account: PmtAccount | null): PmtAccountAccess;
|
|
@@ -182,11 +199,13 @@ export interface PaymentsFXOperator {
|
|
|
182
199
|
createPayment(opts: CreatePaymentOptions): Promise<Payment>;
|
|
183
200
|
replacePayment(opts: ReplacePaymentOptions): Promise<Payment>;
|
|
184
201
|
searchPayments(opts: SearchPaymentsOptions): Promise<SearchPaymentsPage>;
|
|
202
|
+
searchPaymentHistory(opts: SearchPaymentHistoryOptions): Promise<SearchPaymentsPage>;
|
|
185
203
|
createPmtAccount(opts: CreatePmtAccountOptions): Promise<PmtAccount>;
|
|
186
204
|
continuePmtAccountOnboarding(opts: ContinuePmtAccountOnboardingOptions): Promise<ContinuePmtAccountOnboardingResult>;
|
|
187
205
|
replacePmtAccount(opts: ReplacePmtAccountOptions): Promise<PmtAccount>;
|
|
188
206
|
searchPmtAccounts(opts: SearchPmtAccountsOptions): Promise<SearchPmtAccountsPage>;
|
|
189
207
|
getPmtAccountAccess(opts: GetPmtAccountAccessOptions): Promise<PmtAccountAccess>;
|
|
208
|
+
getPayoutBalance(opts: GetPayoutBalanceOptions): Promise<PayoutBalance>;
|
|
190
209
|
createPmtBankAccount(opts: CreatePmtBankAccountOptions): Promise<PmtBankAccount>;
|
|
191
210
|
replacePmtBankAccount(opts: ReplacePmtBankAccountOptions): Promise<PmtBankAccount>;
|
|
192
211
|
searchPmtBankAccounts(opts: SearchPmtBankAccountsOptions): Promise<SearchPmtBankAccountsPage>;
|
|
@@ -228,11 +247,13 @@ export declare class PaymentsFX implements PaymentsFXOperator {
|
|
|
228
247
|
createPayment(opts: CreatePaymentOptions): Promise<Payment>;
|
|
229
248
|
replacePayment(opts: ReplacePaymentOptions): Promise<Payment>;
|
|
230
249
|
searchPayments(opts: SearchPaymentsOptions): Promise<SearchPaymentsPage>;
|
|
250
|
+
searchPaymentHistory(opts: SearchPaymentHistoryOptions): Promise<SearchPaymentsPage>;
|
|
231
251
|
createPmtAccount(opts: CreatePmtAccountOptions): Promise<PmtAccount>;
|
|
232
252
|
continuePmtAccountOnboarding(opts: ContinuePmtAccountOnboardingOptions): Promise<ContinuePmtAccountOnboardingResult>;
|
|
233
253
|
replacePmtAccount(opts: ReplacePmtAccountOptions): Promise<PmtAccount>;
|
|
234
254
|
searchPmtAccounts(opts: SearchPmtAccountsOptions): Promise<SearchPmtAccountsPage>;
|
|
235
255
|
getPmtAccountAccess(opts: GetPmtAccountAccessOptions): Promise<PmtAccountAccess>;
|
|
256
|
+
getPayoutBalance(opts: GetPayoutBalanceOptions): Promise<PayoutBalance>;
|
|
236
257
|
createPmtBankAccount(opts: CreatePmtBankAccountOptions): Promise<PmtBankAccount>;
|
|
237
258
|
replacePmtBankAccount(opts: ReplacePmtBankAccountOptions): Promise<PmtBankAccount>;
|
|
238
259
|
searchPmtBankAccounts(opts: SearchPmtBankAccountsOptions): Promise<SearchPmtBankAccountsPage>;
|
|
@@ -14,6 +14,7 @@ const publicAmountPattern = /^\d+$/;
|
|
|
14
14
|
const resourcePayment = "payment";
|
|
15
15
|
const resourcePmtAccount = "pmt_account";
|
|
16
16
|
const resourcePmtAccountOnboarding = "pmt_account_onboarding";
|
|
17
|
+
const resourcePayoutBalance = "payout_balance";
|
|
17
18
|
const resourcePmtBankAccount = "pmt_bank_account";
|
|
18
19
|
const resourcePmtCard = "pmt_card";
|
|
19
20
|
const resourcePmtRefund = "pmt_refund";
|
|
@@ -26,7 +27,7 @@ const msgPayableSourceMissing = "Payable entity source is unavailable.";
|
|
|
26
27
|
const msgPayableBalanceChanged = "Payment balance changed or a payment is still pending. Refresh before paying.";
|
|
27
28
|
const msgPaymentMethodRequired = "A payment method is required.";
|
|
28
29
|
const msgPayableUnavailable = "This entity is not available for payment.";
|
|
29
|
-
const msgPaymentScopeMissing = "Payment history requires a payer or recipient scope
|
|
30
|
+
const msgPaymentScopeMissing = "Payment history requires a payer or recipient scope.";
|
|
30
31
|
const msgPaymentHistoryIncomplete = "Payment history response is incomplete.";
|
|
31
32
|
const msgPaymentEntityInvalid = "Payment resolution requires a valid entity, currency, and amount.";
|
|
32
33
|
const msgPaymentEntityConflict = "Payment resolution received conflicting entity amounts.";
|
|
@@ -37,6 +38,7 @@ const msgCreatedPaymentIDMissing = "Created payment response did not contain an
|
|
|
37
38
|
const msgPaymentMissing = "Payment could not be resolved after the mutation.";
|
|
38
39
|
const msgCreatedPmtAccountIDMissing = "Created payment account response did not contain an ID.";
|
|
39
40
|
const msgPmtAccountMissing = "Payment account could not be resolved after the mutation.";
|
|
41
|
+
const msgPayoutBalanceMissing = "Payout balance response is incomplete.";
|
|
40
42
|
const msgPmtAccountOnboardingIDMissing = "Payment account onboarding requires a valid account ID.";
|
|
41
43
|
const msgPmtAccountOnboardingLinkMissing = "Payment account onboarding did not return a link.";
|
|
42
44
|
const msgCreatedPmtBankAccountIDMissing = "Created payment bank account response did not contain an ID.";
|
|
@@ -63,6 +65,14 @@ const msgPublicAmountExceedsBalance = "Public payment amount cannot exceed the s
|
|
|
63
65
|
export const PaymentsEvents = {
|
|
64
66
|
Changed: createEvent(),
|
|
65
67
|
};
|
|
68
|
+
export const PaymentDirection = {
|
|
69
|
+
Outgoing: "outgoing",
|
|
70
|
+
Incoming: "incoming",
|
|
71
|
+
};
|
|
72
|
+
export function isIncomingPayment(payment, viewerID) {
|
|
73
|
+
return (payment.recipient_id === viewerID &&
|
|
74
|
+
(payment.is_external || payment.payer_id !== viewerID));
|
|
75
|
+
}
|
|
66
76
|
export const PmtAccountAccessStatus = {
|
|
67
77
|
Missing: "missing",
|
|
68
78
|
OnboardingRequired: "onboarding_required",
|
|
@@ -390,12 +400,57 @@ export class PaymentsFX {
|
|
|
390
400
|
return payment;
|
|
391
401
|
}
|
|
392
402
|
async searchPayments(opts) {
|
|
393
|
-
|
|
403
|
+
const owner_id = resolvedID(opts.owner_id);
|
|
404
|
+
const recipient_id = resolvedID(opts.recipient_id);
|
|
405
|
+
if (!owner_id && !recipient_id)
|
|
406
|
+
throw errValidation({ msg: msgPaymentScopeMissing });
|
|
407
|
+
return await runSearch({
|
|
394
408
|
...opts,
|
|
395
|
-
query: queryParams({
|
|
409
|
+
query: queryParams({
|
|
410
|
+
owner_id,
|
|
411
|
+
recipient_id,
|
|
412
|
+
type: opts.type,
|
|
413
|
+
kind: opts.kind,
|
|
414
|
+
psp_actionable_status: opts.psp_actionable_status,
|
|
415
|
+
currency: opts.currency?.trim().toUpperCase() || undefined,
|
|
416
|
+
}),
|
|
396
417
|
search: (searchOpts) => this.payments.searchManyPayments(searchOpts),
|
|
397
418
|
});
|
|
398
419
|
}
|
|
420
|
+
async searchPaymentHistory(opts) {
|
|
421
|
+
const { owner_id, direction, ...searchOpts } = opts;
|
|
422
|
+
const viewer = resolvedID(owner_id);
|
|
423
|
+
if (!viewer)
|
|
424
|
+
throw errValidation({ msg: msgPaymentScopeMissing });
|
|
425
|
+
const incoming = direction === PaymentDirection.Incoming;
|
|
426
|
+
let page = opts.page;
|
|
427
|
+
while (true) {
|
|
428
|
+
opts.signal?.throwIfAborted();
|
|
429
|
+
const out = await this.searchPayments({
|
|
430
|
+
...searchOpts,
|
|
431
|
+
...(incoming ? { recipient_id: viewer } : { owner_id: viewer }),
|
|
432
|
+
page,
|
|
433
|
+
});
|
|
434
|
+
// Public bill payments belong to their recipient. Ownership alone does
|
|
435
|
+
// not make them outgoing; scan source pages without changing their order.
|
|
436
|
+
const results = out.results.filter((payment) => isIncomingPayment(payment, viewer) === incoming);
|
|
437
|
+
if (results.length || out.done) {
|
|
438
|
+
return {
|
|
439
|
+
...out,
|
|
440
|
+
results,
|
|
441
|
+
total_count: undefined,
|
|
442
|
+
last_page: undefined,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
if (out.next_page <= out.page) {
|
|
446
|
+
throw errResolveFailed({
|
|
447
|
+
resource: resourcePayment,
|
|
448
|
+
msg: msgPaymentHistoryIncomplete,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
page = out.next_page;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
399
454
|
async createPmtAccount(opts) {
|
|
400
455
|
const out = await this.payments.insertOnePmtAccount(opts);
|
|
401
456
|
const id = requiredOperationID(out, msgCreatedPmtAccountIDMissing);
|
|
@@ -449,6 +504,31 @@ export class PaymentsFX {
|
|
|
449
504
|
page = out.next_page;
|
|
450
505
|
}
|
|
451
506
|
}
|
|
507
|
+
async getPayoutBalance(opts) {
|
|
508
|
+
const access = await this.getPmtAccountAccess(opts);
|
|
509
|
+
opts.signal?.throwIfAborted();
|
|
510
|
+
const accountID = resolvedID(access.account?.psp_id);
|
|
511
|
+
if (accountID === undefined) {
|
|
512
|
+
return { access, balance: null };
|
|
513
|
+
}
|
|
514
|
+
// Outstanding funds remain visible when the account needs updated onboarding.
|
|
515
|
+
const out = await this.payments.balance({ psp_account_id: accountID }, { signal: opts.signal });
|
|
516
|
+
opts.signal?.throwIfAborted();
|
|
517
|
+
if (!out?.value) {
|
|
518
|
+
throw errResolveFailed({
|
|
519
|
+
resource: resourcePayoutBalance,
|
|
520
|
+
msg: msgPayoutBalanceMissing,
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
return {
|
|
524
|
+
access,
|
|
525
|
+
balance: {
|
|
526
|
+
available: out.value.available ?? [],
|
|
527
|
+
pending: out.value.pending ?? [],
|
|
528
|
+
instant_available: out.value.instant_available ?? [],
|
|
529
|
+
},
|
|
530
|
+
};
|
|
531
|
+
}
|
|
452
532
|
async createPmtBankAccount(opts) {
|
|
453
533
|
const out = await this.payments.insertOnePmtBankAccount(opts);
|
|
454
534
|
const id = requiredOperationID(out, msgCreatedPmtBankAccountIDMissing);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabriktor/fx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.132",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"typescript": "^6.0.3"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@fabriktor/client": "0.0.
|
|
20
|
+
"@fabriktor/client": "0.0.93",
|
|
21
21
|
"@fabriktor/fx": "0.0.94",
|
|
22
22
|
"@fabriktor/schema": "0.0.66"
|
|
23
23
|
}
|