@managemint-solutions/sdk 0.40.1 → 0.41.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/dist/billing/index.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export declare class BillingReadsResource {
|
|
|
19
19
|
openTransaction(openStatuses: string[]): Promise<BillingTransactionRow | null>;
|
|
20
20
|
/** The replay lookup: the same key must never raise a second charge. */
|
|
21
21
|
transactionByIdempotencyKey(idempotencyKey: string): Promise<BillingTransactionRow | null>;
|
|
22
|
+
/** The organization's newest renewal in this status, or null. */
|
|
23
|
+
latestRenewalIn(transactionStatus: string): Promise<BillingTransactionRow | null>;
|
|
22
24
|
/**
|
|
23
25
|
* The organization's payments, newest first: every ledger row, whatever its type or
|
|
24
26
|
* status. RLS scopes the rows; the eq is belt-and-braces.
|
package/dist/billing/index.js
CHANGED
|
@@ -26,7 +26,7 @@ const BILLING_TRANSACTIONS_TABLE = {
|
|
|
26
26
|
entityType: enum_1.AuditTrailEntityType.BILLING_TRANSACTIONS,
|
|
27
27
|
};
|
|
28
28
|
/** The wire shape of a payment list row - never the internal bigint id, never the checkout secrets. */
|
|
29
|
-
const PAYMENT_SUMMARY_SELECT = 'mms_id, created_at, transaction_type, transaction_status, amount_minor, currency, paid_at, failure_reason';
|
|
29
|
+
const PAYMENT_SUMMARY_SELECT = 'mms_id, created_at, transaction_type, transaction_status, amount_minor, currency, paid_at, failure_reason, refunded_at, refund_amount_minor';
|
|
30
30
|
/**
|
|
31
31
|
* PaymentEntity, column for column, plus the renewal's invoice through the unique
|
|
32
32
|
* `invoices.billing_transaction_id` foreign key. The Paystack access code and
|
|
@@ -70,6 +70,21 @@ class BillingReadsResource {
|
|
|
70
70
|
throw (0, errors_1.mapPostgrestError)(error);
|
|
71
71
|
return data ? (0, audit_1.withoutInternalId)(data) : null;
|
|
72
72
|
}
|
|
73
|
+
/** The organization's newest renewal in this status, or null. */
|
|
74
|
+
async latestRenewalIn(transactionStatus) {
|
|
75
|
+
const { data, error } = await this.supabase
|
|
76
|
+
.from('billing_transactions')
|
|
77
|
+
.select('*')
|
|
78
|
+
.eq('organization_id', this.actor.organization_id)
|
|
79
|
+
.eq('transaction_type', enum_2.BillingTransactionType.RENEWAL)
|
|
80
|
+
.eq('transaction_status', transactionStatus)
|
|
81
|
+
.order('created_at', { ascending: false })
|
|
82
|
+
.limit(1)
|
|
83
|
+
.maybeSingle();
|
|
84
|
+
if (error)
|
|
85
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
86
|
+
return data ? (0, audit_1.withoutInternalId)(data) : null;
|
|
87
|
+
}
|
|
73
88
|
/**
|
|
74
89
|
* The organization's payments, newest first: every ledger row, whatever its type or
|
|
75
90
|
* status. RLS scopes the rows; the eq is belt-and-braces.
|
|
@@ -21,14 +21,26 @@ export declare class InvoicesReadsResource {
|
|
|
21
21
|
/**
|
|
22
22
|
* The document writes, on the service client only - every write policy on `invoices` is
|
|
23
23
|
* `false` for `authenticated`. Rows are written by the api's billing service beside a
|
|
24
|
-
* renewal's ledger
|
|
25
|
-
* status after it is issued - never by a caller.
|
|
24
|
+
* renewal's ledger row, never by a caller; an invoice mirrors its ledger row's status.
|
|
26
25
|
*/
|
|
27
26
|
export declare class InvoicesResource extends InvoicesReadsResource {
|
|
28
27
|
private readonly invoices;
|
|
29
28
|
constructor(supabase: TypedSupabaseClient, actor: AuditActor, audit: AuditResource);
|
|
30
29
|
/** Audited insert of the accounting document beside its ledger row. */
|
|
31
30
|
create(payload: AuditRow): Promise<AuditRow>;
|
|
31
|
+
/** Audited status change: the row follows its ledger row (paid, refunded). */
|
|
32
|
+
update(invoiceId: string, patch: AuditRow): Promise<AuditRow>;
|
|
33
|
+
/**
|
|
34
|
+
* The invoice Paystack named with this INV_… code, or null. The invoice events
|
|
35
|
+
* (create, payment_failed, update) all carry the code, so it is how a later event finds
|
|
36
|
+
* the row an earlier one opened.
|
|
37
|
+
*/
|
|
38
|
+
byPaystackInvoiceCode(invoiceCode: string): Promise<InvoiceEntity | null>;
|
|
39
|
+
/**
|
|
40
|
+
* The invoice behind a ledger row, or null. `billing_transaction_id` is unique, so a
|
|
41
|
+
* renewal has at most one; every other transaction type has none.
|
|
42
|
+
*/
|
|
43
|
+
byTransactionId(transactionId: string): Promise<InvoiceEntity | null>;
|
|
32
44
|
/**
|
|
33
45
|
* The organization's highest invoice number, 0 when it has none. The api assigns
|
|
34
46
|
* `max + 1` and lets the `(organization_id, invoice_number)` unique index arbitrate a
|
|
@@ -27,7 +27,7 @@ const INVOICES_TABLE = {
|
|
|
27
27
|
/** The wire shape of an invoice list row - never the internal bigint id. */
|
|
28
28
|
const INVOICE_SUMMARY_SELECT = 'mms_id, invoice_number, transaction_type, status, issued_at, paid_at, amount_minor, currency';
|
|
29
29
|
/** InvoiceEntity, column for column: the summary plus the frozen document data. */
|
|
30
|
-
const INVOICE_ENTITY_SELECT = `${INVOICE_SUMMARY_SELECT}, billing_transaction_id, paystack_reference, period_start, period_end, line_items, billed_to`;
|
|
30
|
+
const INVOICE_ENTITY_SELECT = `${INVOICE_SUMMARY_SELECT}, billing_transaction_id, paystack_reference, paystack_invoice_code, period_start, period_end, line_items, billed_to`;
|
|
31
31
|
/**
|
|
32
32
|
* The readable half. `invoices` is SELECT-only for `authenticated` with an org-predicate
|
|
33
33
|
* policy - the same posture as the ledger it mirrors - so reads run on the caller's own
|
|
@@ -78,8 +78,7 @@ exports.InvoicesReadsResource = InvoicesReadsResource;
|
|
|
78
78
|
/**
|
|
79
79
|
* The document writes, on the service client only - every write policy on `invoices` is
|
|
80
80
|
* `false` for `authenticated`. Rows are written by the api's billing service beside a
|
|
81
|
-
* renewal's ledger
|
|
82
|
-
* status after it is issued - never by a caller.
|
|
81
|
+
* renewal's ledger row, never by a caller; an invoice mirrors its ledger row's status.
|
|
83
82
|
*/
|
|
84
83
|
class InvoicesResource extends InvoicesReadsResource {
|
|
85
84
|
invoices;
|
|
@@ -91,6 +90,44 @@ class InvoicesResource extends InvoicesReadsResource {
|
|
|
91
90
|
async create(payload) {
|
|
92
91
|
return this.invoices.insert(payload);
|
|
93
92
|
}
|
|
93
|
+
/** Audited status change: the row follows its ledger row (paid, refunded). */
|
|
94
|
+
async update(invoiceId, patch) {
|
|
95
|
+
return this.invoices.update(invoiceId, {
|
|
96
|
+
...patch,
|
|
97
|
+
updated_at: new Date().toISOString(),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The invoice Paystack named with this INV_… code, or null. The invoice events
|
|
102
|
+
* (create, payment_failed, update) all carry the code, so it is how a later event finds
|
|
103
|
+
* the row an earlier one opened.
|
|
104
|
+
*/
|
|
105
|
+
async byPaystackInvoiceCode(invoiceCode) {
|
|
106
|
+
const { data, error } = await this.supabase
|
|
107
|
+
.from('invoices')
|
|
108
|
+
.select(INVOICE_ENTITY_SELECT)
|
|
109
|
+
.eq('paystack_invoice_code', invoiceCode)
|
|
110
|
+
.eq('organization_id', this.actor.organization_id)
|
|
111
|
+
.maybeSingle();
|
|
112
|
+
if (error)
|
|
113
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
114
|
+
return data ?? null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The invoice behind a ledger row, or null. `billing_transaction_id` is unique, so a
|
|
118
|
+
* renewal has at most one; every other transaction type has none.
|
|
119
|
+
*/
|
|
120
|
+
async byTransactionId(transactionId) {
|
|
121
|
+
const { data, error } = await this.supabase
|
|
122
|
+
.from('invoices')
|
|
123
|
+
.select(INVOICE_ENTITY_SELECT)
|
|
124
|
+
.eq('billing_transaction_id', transactionId)
|
|
125
|
+
.eq('organization_id', this.actor.organization_id)
|
|
126
|
+
.maybeSingle();
|
|
127
|
+
if (error)
|
|
128
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
129
|
+
return data ?? null;
|
|
130
|
+
}
|
|
94
131
|
/**
|
|
95
132
|
* The organization's highest invoice number, 0 when it has none. The api assigns
|
|
96
133
|
* `max + 1` and lets the `(organization_id, invoice_number)` unique index arbitrate a
|
|
@@ -103,5 +103,12 @@ export declare class SupabaseServiceClient {
|
|
|
103
103
|
* transaction id in its metadata, and the row is what says which tenant it belongs to.
|
|
104
104
|
*/
|
|
105
105
|
findTransaction(transactionId: string): Promise<Record<string, unknown> | null>;
|
|
106
|
+
/**
|
|
107
|
+
* A ledger row by its Paystack reference. Unscoped for the same reason as
|
|
108
|
+
* `findTransaction`: a refund event names only `transaction_reference`, and the row is
|
|
109
|
+
* what says which tenant it belongs to. The partial unique index on
|
|
110
|
+
* `paystack_reference` makes at most one row match.
|
|
111
|
+
*/
|
|
112
|
+
findTransactionByReference(reference: string): Promise<Record<string, unknown> | null>;
|
|
106
113
|
}
|
|
107
114
|
export declare const createSupabaseServiceClient: (config: SupabaseServiceClientConfig) => SupabaseServiceClient;
|
|
@@ -182,6 +182,22 @@ class SupabaseServiceClient {
|
|
|
182
182
|
throw (0, errors_1.mapPostgrestError)(error);
|
|
183
183
|
return data ? (0, audit_1.withoutInternalId)(data) : null;
|
|
184
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* A ledger row by its Paystack reference. Unscoped for the same reason as
|
|
187
|
+
* `findTransaction`: a refund event names only `transaction_reference`, and the row is
|
|
188
|
+
* what says which tenant it belongs to. The partial unique index on
|
|
189
|
+
* `paystack_reference` makes at most one row match.
|
|
190
|
+
*/
|
|
191
|
+
async findTransactionByReference(reference) {
|
|
192
|
+
const { data, error } = await this.supabase
|
|
193
|
+
.from('billing_transactions')
|
|
194
|
+
.select('*')
|
|
195
|
+
.eq('paystack_reference', reference)
|
|
196
|
+
.maybeSingle();
|
|
197
|
+
if (error)
|
|
198
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
199
|
+
return data ? (0, audit_1.withoutInternalId)(data) : null;
|
|
200
|
+
}
|
|
185
201
|
}
|
|
186
202
|
exports.SupabaseServiceClient = SupabaseServiceClient;
|
|
187
203
|
const createSupabaseServiceClient = (config) => new SupabaseServiceClient(config);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@managemint-solutions/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"description": "Typed Supabase data-access SDK for ManageMint Solutions",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "Scott Bebington <scottbebington@gmail.com>",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"testEnvironment": "node"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@managemint-solutions/entities": "^1.
|
|
54
|
+
"@managemint-solutions/entities": "^1.24.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"@nestjs/common": "^11.0.0",
|