@fantastic.dev/better-stripe 0.16.0 → 0.17.1
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/CHANGELOG.md +21 -0
- package/README.md +60 -9
- package/dist/client/connect/refunds.d.ts +12 -0
- package/dist/client/connect/refunds.d.ts.map +1 -1
- package/dist/client/connect/refunds.js +8 -0
- package/dist/client/connect/refunds.js.map +1 -1
- package/dist/client/index.d.ts +5 -7
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/component.d.ts +36 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/connect/queries.d.ts.map +1 -1
- package/dist/component/connect/queries.js +2 -1
- package/dist/component/connect/queries.js.map +1 -1
- package/dist/component/connect/schema.d.ts +2 -0
- package/dist/component/connect/schema.d.ts.map +1 -1
- package/dist/component/connect/schema.js +9 -0
- package/dist/component/connect/schema.js.map +1 -1
- package/dist/component/earnings/arithmetic.d.ts +3 -0
- package/dist/component/earnings/arithmetic.d.ts.map +1 -0
- package/dist/component/earnings/arithmetic.js +11 -0
- package/dist/component/earnings/arithmetic.js.map +1 -0
- package/dist/component/earnings/reads.d.ts.map +1 -1
- package/dist/component/earnings/reads.js +6 -0
- package/dist/component/earnings/reads.js.map +1 -1
- package/dist/component/earnings/triggers.d.ts +4 -0
- package/dist/component/earnings/triggers.d.ts.map +1 -1
- package/dist/component/earnings/triggers.js +17 -12
- package/dist/component/earnings/triggers.js.map +1 -1
- package/dist/component/refundHistory/queries.d.ts +28 -0
- package/dist/component/refundHistory/queries.d.ts.map +1 -0
- package/dist/component/refundHistory/queries.js +59 -0
- package/dist/component/refundHistory/queries.js.map +1 -0
- package/dist/component/schema.d.ts +2 -0
- package/dist/react/workflows/Costs.d.ts +1 -0
- package/dist/react/workflows/Costs.d.ts.map +1 -1
- package/dist/react/workflows/Costs.js +7 -3
- package/dist/react/workflows/Costs.js.map +1 -1
- package/docs/react-workflows.md +39 -3
- package/docs/read-contracts.md +13 -0
- package/package.json +1 -1
- package/src/client/connect/refunds.ts +28 -0
- package/src/client/index.ts +6 -7
- package/src/client/refund-history.test.ts +67 -0
- package/src/component/_generated/api.ts +4 -0
- package/src/component/_generated/component.ts +56 -0
- package/src/component/connect/queries.ts +2 -1
- package/src/component/connect/schema.ts +9 -0
- package/src/component/earnings/arithmetic.ts +10 -0
- package/src/component/earnings/reads.ts +6 -0
- package/src/component/earnings/triggers.ts +18 -13
- package/src/component/refund-history.test.ts +198 -0
- package/src/component/refundHistory/queries.ts +99 -0
- package/src/component/summary-arithmetic.test.ts +246 -0
- package/src/react/workflows/Costs.test.tsx +21 -0
- package/src/react/workflows/Costs.tsx +9 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"triggers.js","sourceRoot":"","sources":["../../../src/component/earnings/triggers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EACL,SAAS,EACT,cAAc,GACf,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EACL,QAAQ,IAAI,WAAW,GAExB,MAAM,yBAAyB,CAAC;AAUjC,KAAK,UAAU,MAAM,CACnB,GAAgB,EAChB,IAA4B,EAC5B,KAAmB,EACnB,IAAY;IAEZ,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,EAAE;SACrB,KAAK,CAAC,gBAAgB,CAAC;SACvB,SAAS,CAAC,0BAA0B,EAAE,CAAC,CAAC,EAAE,EAAE,CAC3C,CAAC;SACE,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC;SAChC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC;SAChB,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,CAClC;SACA,MAAM,EAAE,CAAC;IACZ,MAAM,MAAM,GAAG;QACb,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"triggers.js","sourceRoot":"","sources":["../../../src/component/earnings/triggers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Host-authorized scopes are conjunctive; use the package React pagination binding. */
|
|
2
|
+
export declare const paginateRefunds: import("convex/server").RegisteredQuery<"public", {
|
|
3
|
+
accountId?: string | undefined;
|
|
4
|
+
paginationOpts: {
|
|
5
|
+
id?: number;
|
|
6
|
+
endCursor?: string | null;
|
|
7
|
+
maximumRowsRead?: number;
|
|
8
|
+
maximumBytesRead?: number;
|
|
9
|
+
numItems: number;
|
|
10
|
+
cursor: string | null;
|
|
11
|
+
};
|
|
12
|
+
status?: "canceled" | "failed" | "pending" | "requires_action" | "succeeded" | undefined;
|
|
13
|
+
stripePaymentIntentId?: string | undefined;
|
|
14
|
+
}, Promise<import("convex/server").PaginationResult<{
|
|
15
|
+
_creationTime: number;
|
|
16
|
+
_id: import("convex/values").GenericId<"refunds">;
|
|
17
|
+
accountId?: string | undefined;
|
|
18
|
+
amount: number;
|
|
19
|
+
currency: string;
|
|
20
|
+
failureReason?: string | undefined;
|
|
21
|
+
metadata?: any;
|
|
22
|
+
reason?: "duplicate" | "expired_uncaptured_charge" | "fraudulent" | "requested_by_customer" | undefined;
|
|
23
|
+
status: "canceled" | "failed" | "pending" | "requires_action" | "succeeded";
|
|
24
|
+
stripeChargeId?: string | undefined;
|
|
25
|
+
stripePaymentIntentId?: string | undefined;
|
|
26
|
+
stripeRefundId: string;
|
|
27
|
+
}>>>;
|
|
28
|
+
//# sourceMappingURL=queries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/component/refundHistory/queries.ts"],"names":[],"mappings":"AAeA,wFAAwF;AACxF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;IA0B1B,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { paginationOptsValidator, paginationResultValidator, } from "convex/server";
|
|
2
|
+
import { v } from "convex/values";
|
|
3
|
+
import { paginator } from "convex-helpers/server/pagination";
|
|
4
|
+
import { query } from "../_generated/server.js";
|
|
5
|
+
import schema from "../schema.js";
|
|
6
|
+
import { refundDocValidator, refundStatusValidator, } from "../connect/validators.js";
|
|
7
|
+
/** Host-authorized scopes are conjunctive; use the package React pagination binding. */
|
|
8
|
+
export const paginateRefunds = query({
|
|
9
|
+
args: {
|
|
10
|
+
accountId: v.optional(v.string()),
|
|
11
|
+
stripePaymentIntentId: v.optional(v.string()),
|
|
12
|
+
status: v.optional(refundStatusValidator),
|
|
13
|
+
paginationOpts: paginationOptsValidator,
|
|
14
|
+
},
|
|
15
|
+
returns: paginationResultValidator(refundDocValidator),
|
|
16
|
+
handler: (ctx, args) => {
|
|
17
|
+
const { paginationOpts } = args;
|
|
18
|
+
if (!Number.isSafeInteger(paginationOpts.numItems) ||
|
|
19
|
+
paginationOpts.numItems < 1 ||
|
|
20
|
+
paginationOpts.numItems > 100)
|
|
21
|
+
throw new Error("Refund history page size must be an integer from 1 to 100");
|
|
22
|
+
return scopedRefunds(ctx, args)
|
|
23
|
+
.order("desc")
|
|
24
|
+
.paginate({
|
|
25
|
+
...paginationOpts,
|
|
26
|
+
maximumRowsRead: 200,
|
|
27
|
+
maximumBytesRead: 1_000_000,
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
function scopedRefunds(ctx, args) {
|
|
32
|
+
const { accountId, stripePaymentIntentId, status } = args;
|
|
33
|
+
const refunds = paginator(ctx.db, schema).query("refunds");
|
|
34
|
+
if (accountId !== undefined &&
|
|
35
|
+
stripePaymentIntentId !== undefined &&
|
|
36
|
+
status === undefined)
|
|
37
|
+
return refunds.withIndex("by_account_id_and_stripe_payment_intent_id", (q) => q
|
|
38
|
+
.eq("accountId", accountId)
|
|
39
|
+
.eq("stripePaymentIntentId", stripePaymentIntentId));
|
|
40
|
+
if (accountId !== undefined &&
|
|
41
|
+
stripePaymentIntentId !== undefined &&
|
|
42
|
+
status !== undefined)
|
|
43
|
+
return refunds.withIndex("by_account_id_and_stripe_payment_intent_id_and_status", (q) => q
|
|
44
|
+
.eq("accountId", accountId)
|
|
45
|
+
.eq("stripePaymentIntentId", stripePaymentIntentId)
|
|
46
|
+
.eq("status", status));
|
|
47
|
+
if (accountId !== undefined && status !== undefined)
|
|
48
|
+
return refunds.withIndex("by_account_id_and_status", (q) => q.eq("accountId", accountId).eq("status", status));
|
|
49
|
+
if (stripePaymentIntentId !== undefined && status !== undefined)
|
|
50
|
+
return refunds.withIndex("by_payment_intent_id_and_status", (q) => q.eq("stripePaymentIntentId", stripePaymentIntentId).eq("status", status));
|
|
51
|
+
if (accountId !== undefined)
|
|
52
|
+
return refunds.withIndex("by_account_id", (q) => q.eq("accountId", accountId));
|
|
53
|
+
if (stripePaymentIntentId !== undefined)
|
|
54
|
+
return refunds.withIndex("by_stripe_payment_intent_id", (q) => q.eq("stripePaymentIntentId", stripePaymentIntentId));
|
|
55
|
+
if (status !== undefined)
|
|
56
|
+
return refunds.withIndex("by_status", (q) => q.eq("status", status));
|
|
57
|
+
return refunds;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../../src/component/refundHistory/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAE7D,OAAO,EAAE,KAAK,EAAiB,MAAM,yBAAyB,CAAC;AAC/D,OAAO,MAAM,MAAM,cAAc,CAAC;AAClC,OAAO,EACL,kBAAkB,EAClB,qBAAqB,GAEtB,MAAM,0BAA0B,CAAC;AAElC,wFAAwF;AACxF,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;IACnC,IAAI,EAAE;QACJ,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACjC,qBAAqB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC7C,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACzC,cAAc,EAAE,uBAAuB;KACxC;IACD,OAAO,EAAE,yBAAyB,CAAC,kBAAkB,CAAC;IACtD,OAAO,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;QAChC,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,QAAQ,CAAC;YAC9C,cAAc,CAAC,QAAQ,GAAG,CAAC;YAC3B,cAAc,CAAC,QAAQ,GAAG,GAAG;YAE7B,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;QACJ,OAAO,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC;aAC5B,KAAK,CAAC,MAAM,CAAC;aACb,QAAQ,CAAC;YACR,GAAG,cAAc;YACjB,eAAe,EAAE,GAAG;YACpB,gBAAgB,EAAE,SAAS;SAC5B,CAAC,CAAC;IACP,CAAC;CACF,CAAC,CAAC;AAEH,SAAS,aAAa,CACpB,GAAa,EACb,IAIC;IAED,MAAM,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1D,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC3D,IACE,SAAS,KAAK,SAAS;QACvB,qBAAqB,KAAK,SAAS;QACnC,MAAM,KAAK,SAAS;QAEpB,OAAO,OAAO,CAAC,SAAS,CACtB,4CAA4C,EAC5C,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC;aACE,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;aAC1B,EAAE,CAAC,uBAAuB,EAAE,qBAAqB,CAAC,CACxD,CAAC;IACJ,IACE,SAAS,KAAK,SAAS;QACvB,qBAAqB,KAAK,SAAS;QACnC,MAAM,KAAK,SAAS;QAEpB,OAAO,OAAO,CAAC,SAAS,CACtB,uDAAuD,EACvD,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC;aACE,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;aAC1B,EAAE,CAAC,uBAAuB,EAAE,qBAAqB,CAAC;aAClD,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAC1B,CAAC;IACJ,IAAI,SAAS,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;QACjD,OAAO,OAAO,CAAC,SAAS,CAAC,0BAA0B,EAAE,CAAC,CAAC,EAAE,EAAE,CACzD,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAClD,CAAC;IACJ,IAAI,qBAAqB,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;QAC7D,OAAO,OAAO,CAAC,SAAS,CAAC,iCAAiC,EAAE,CAAC,CAAC,EAAE,EAAE,CAChE,CAAC,CAAC,EAAE,CAAC,uBAAuB,EAAE,qBAAqB,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAC1E,CAAC;IACJ,IAAI,SAAS,KAAK,SAAS;QACzB,OAAO,OAAO,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE,CAC9C,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,CAC7B,CAAC;IACJ,IAAI,qBAAqB,KAAK,SAAS;QACrC,OAAO,OAAO,CAAC,SAAS,CAAC,6BAA6B,EAAE,CAAC,CAAC,EAAE,EAAE,CAC5D,CAAC,CAAC,EAAE,CAAC,uBAAuB,EAAE,qBAAqB,CAAC,CACrD,CAAC;IACJ,IAAI,MAAM,KAAK,SAAS;QACtB,OAAO,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IACvE,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -674,6 +674,8 @@ declare const _default: import("convex/server").SchemaDefinition<{
|
|
|
674
674
|
}, "required", "accountId" | "amount" | "currency" | "failureReason" | "metadata" | "reason" | "status" | "stripeChargeId" | "stripePaymentIntentId" | "stripeRefundId" | `metadata.${string}`>, {
|
|
675
675
|
by_account_id: ["accountId", "_creationTime"];
|
|
676
676
|
by_account_id_and_status: ["accountId", "status", "_creationTime"];
|
|
677
|
+
by_account_id_and_stripe_payment_intent_id: ["accountId", "stripePaymentIntentId", "_creationTime"];
|
|
678
|
+
by_account_id_and_stripe_payment_intent_id_and_status: ["accountId", "stripePaymentIntentId", "status", "_creationTime"];
|
|
677
679
|
by_payment_intent_id_and_status: ["stripePaymentIntentId", "status", "_creationTime"];
|
|
678
680
|
by_status: ["status", "_creationTime"];
|
|
679
681
|
by_stripe_payment_intent_id: ["stripePaymentIntentId", "_creationTime"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Costs.d.ts","sourceRoot":"","sources":["../../../src/react/workflows/Costs.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AACF,wBAAgB,YAAY,CAAC,KAAK,EAAE,uBAAuB,CAAC,eAAe,CAAC,+
|
|
1
|
+
{"version":3,"file":"Costs.d.ts","sourceRoot":"","sources":["../../../src/react/workflows/Costs.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AACF,wBAAgB,YAAY,CAAC,KAAK,EAAE,uBAAuB,CAAC,eAAe,CAAC,+BA+B3E;AACD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AACF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AACF,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS,CAAC;IAC3C,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,CAAC,kBAAkB,CAAC,EAAE,CAAC;CAC/C,CAAC;AACF,wBAAgB,gBAAgB,CAAC,EAC/B,UAAU,EACV,QAAQ,GACT,EAAE;IACD,UAAU,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,2BAA2B,KAAK,SAAS,CAAC;CAC9D,+BA2DA"}
|
|
@@ -3,18 +3,22 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
3
3
|
import { Collection } from "./Collection.js";
|
|
4
4
|
import { formatPrice } from "../lib/price-helpers.js";
|
|
5
5
|
export function CostRecovery(props) {
|
|
6
|
+
const reserved = props.rows?.some((row) => row.reservedAmount !== undefined);
|
|
6
7
|
const columns = [
|
|
7
8
|
{ id: "payment", label: "Payment", cell: (row) => row.paymentIntentId },
|
|
8
9
|
...[
|
|
9
10
|
["amountDue", "Total cost"],
|
|
10
|
-
["collectedAmount", "Deducted from earnings"],
|
|
11
|
-
[
|
|
11
|
+
["collectedAmount", reserved ? "Collected" : "Deducted from earnings"],
|
|
12
|
+
[
|
|
13
|
+
reserved ? "reservedAmount" : "invoicedAmount",
|
|
14
|
+
reserved ? "Reserved" : "Added to invoice",
|
|
15
|
+
],
|
|
12
16
|
["outstanding", "Outstanding"],
|
|
13
17
|
].map(([field, label]) => ({
|
|
14
18
|
id: field,
|
|
15
19
|
label,
|
|
16
20
|
align: "end",
|
|
17
|
-
cell: (row) => formatPrice(row[field], row.currency),
|
|
21
|
+
cell: (row) => formatPrice(row[field] ?? row.invoicedAmount, row.currency),
|
|
18
22
|
})),
|
|
19
23
|
];
|
|
20
24
|
return (_jsx(Collection, { emptyLabel: "No costs yet.", loadingLabel: "Loading costs\u2026", ...props, columns: props.columns ?? columns, getKey: (row) => row._id ?? row.id ?? row.paymentIntentId }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Costs.js","sourceRoot":"","sources":["../../../src/react/workflows/Costs.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,UAAU,EAAuB,MAAM,iBAAiB,CAAC;AAElE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"Costs.js","sourceRoot":"","sources":["../../../src/react/workflows/Costs.tsx"],"names":[],"mappings":"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"}
|
package/docs/react-workflows.md
CHANGED
|
@@ -391,6 +391,40 @@ Preview grouping performs no reads, writes or provider operations and cannot pro
|
|
|
391
391
|
bank delivery or complete-account earnings. Authorize and bound the source read in
|
|
392
392
|
the host; keep authoritative full-account aggregates separate.
|
|
393
393
|
|
|
394
|
+
### Complete refund history (added after 0.16.0)
|
|
395
|
+
|
|
396
|
+
`BetterStripe.paginateRefunds(ctx, opts)` reads authoritative synchronized component
|
|
397
|
+
refund records. `RefundPageOptions` is exported from the main package entrypoint.
|
|
398
|
+
Pass `paginationOpts: { numItems, cursor }` with an integer page size from 1 to 100
|
|
399
|
+
and `null` for the initial cursor. The result has `page`, `isDone` and
|
|
400
|
+
`continueCursor`; feed the returned cursor into the next request until `isDone`.
|
|
401
|
+
Each request performs one bounded helper-compatible component paginate operation
|
|
402
|
+
in newest-first order. Bind the authorized host query with the package React
|
|
403
|
+
`useComponentPaginatedQuery`, matching the catalog and payout readers. Pinned
|
|
404
|
+
ranges may grow beyond the requested page size; reads cap at 200 rows or 1 MB
|
|
405
|
+
and return split hints for the hook. Existing `listRefunds` retains its
|
|
406
|
+
capped-array compatibility.
|
|
407
|
+
|
|
408
|
+
The host must authenticate the session and derive an authorized account/payment
|
|
409
|
+
scope before exposing this method through its reactive query. Optional
|
|
410
|
+
`stripeAccountId`, `stripePaymentIntentId` and `status` filters all apply together;
|
|
411
|
+
a mismatched account/payment pair returns no records. Do not expose an unscoped
|
|
412
|
+
reader to ordinary sellers, trust browser-supplied account IDs or treat this
|
|
413
|
+
component API as an authentication boundary.
|
|
414
|
+
|
|
415
|
+
Render returned records with `RefundHistory` or its render prop, retaining their
|
|
416
|
+
original amount, currency, status and charge/payment identifiers. Dojo supplies
|
|
417
|
+
translated Shadcn presentation and its application audit context. Loaded pages
|
|
418
|
+
and the existing 25-row Vite preview are incomplete until pagination finishes;
|
|
419
|
+
neither is a monetary aggregate. Grouped preview amounts remain explicitly
|
|
420
|
+
bounded, and authoritative monetary totals require currency-isolated aggregate
|
|
421
|
+
APIs. This reader performs no Stripe request, refund or ledger write.
|
|
422
|
+
|
|
423
|
+
This method is absent from public 0.16.0. Source acceptance does not publish it.
|
|
424
|
+
Host applications must wait for a separately verified published artifact and
|
|
425
|
+
package adoption before importing it; source merges alone do not satisfy that
|
|
426
|
+
consumer gate.
|
|
427
|
+
|
|
394
428
|
## Store-plan pricing editor
|
|
395
429
|
|
|
396
430
|
`PlanPricingEditor` accepts a `plan` with `id`, `name`, `monthlyAmount` in minor
|
|
@@ -526,9 +560,11 @@ checking that the response still belongs to the mounted scope. `useOnboarding`
|
|
|
526
560
|
uses this lifecycle for both create and continue navigation, including its
|
|
527
561
|
`window.location.assign` fallback. An old response cannot navigate after unmount
|
|
528
562
|
or scope replacement. Current requests preserve shared pending locks and errors.
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
563
|
+
`uploadDisputeEvidence`, `EvidenceUpload` and the onboarding navigation fix shipped
|
|
564
|
+
in [0.14.0](https://github.com/FantasticDevHQ/better-stripe/releases/tag/v0.14.0).
|
|
565
|
+
Version 0.13.0 does not contain them. Consumers must upgrade to
|
|
566
|
+
`@fantastic.dev/better-stripe@0.14.0` or later before using the upload API or relying
|
|
567
|
+
on the package's navigation guard.
|
|
532
568
|
Production storage, session authorization, styling, translations and extended
|
|
533
569
|
hosted onboarding verification remain application responsibilities.
|
|
534
570
|
|
package/docs/read-contracts.md
CHANGED
|
@@ -94,6 +94,19 @@ earnings ledger does not determine settlement availability.
|
|
|
94
94
|
|
|
95
95
|
### Existing installations
|
|
96
96
|
|
|
97
|
+
Summary amounts, counts and derived net amounts must remain safe integers in the
|
|
98
|
+
public Number representation. Checked integer intermediates reject fractional,
|
|
99
|
+
non-finite or unsupported inputs/results before rounding. A rejected transfer,
|
|
100
|
+
payout, reversal or backfill page rolls back its source changes, markers and
|
|
101
|
+
summary updates together. Stored unsafe summary fields also fail closed on reads.
|
|
102
|
+
|
|
103
|
+
These guards prevent new precision loss; they do not repair summaries rounded by
|
|
104
|
+
an earlier release. An affected historical summary needs reconciliation against
|
|
105
|
+
its original records before reuse, even if a later rounded value appears safe.
|
|
106
|
+
The ordinary backfill below skips already-marked records and cannot repair that
|
|
107
|
+
case. Do not treat a successful backfill or a current safe-looking Number as
|
|
108
|
+
proof that previously unsupported arithmetic was exact.
|
|
109
|
+
|
|
97
110
|
After deploying the optional marker fields and summary table, invoke
|
|
98
111
|
`components.betterStripe.earnings.mutations.backfillCurrencyTotals` from a trusted
|
|
99
112
|
server migration. Run separately for `kind: "earnings"` and `kind: "payouts"`,
|
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type Stripe from "stripe";
|
|
2
|
+
import type { PaginationOptions, PaginationResult } from "convex/server";
|
|
2
3
|
|
|
3
4
|
import type { RefundStatus } from "../../component/connect/validators.js";
|
|
4
5
|
import { throwStripeError } from "../errors.js";
|
|
@@ -12,6 +13,33 @@ import { type RefundActor, isRefundAuthorized } from "./refundActor.js";
|
|
|
12
13
|
|
|
13
14
|
export type { RefundActor } from "./refundActor.js";
|
|
14
15
|
|
|
16
|
+
export type RefundListOptions = {
|
|
17
|
+
stripeAccountId?: string;
|
|
18
|
+
stripePaymentIntentId?: string;
|
|
19
|
+
status?: RefundStatus;
|
|
20
|
+
limit?: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type RefundPageOptions = Omit<RefundListOptions, "limit"> & {
|
|
24
|
+
paginationOpts: PaginationOptions;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** The host must authenticate/authorize scopes before exposing this reactive reader. */
|
|
28
|
+
export async function paginateRefunds(
|
|
29
|
+
component: Component,
|
|
30
|
+
ctx: RunCtx,
|
|
31
|
+
opts: RefundPageOptions,
|
|
32
|
+
): Promise<PaginationResult<StripeComponentRefund>> {
|
|
33
|
+
const { stripeAccountId, ...rest } = opts;
|
|
34
|
+
return await ctx.runQuery(
|
|
35
|
+
componentRef(component, "refundHistory/queries/paginateRefunds"),
|
|
36
|
+
{
|
|
37
|
+
...rest,
|
|
38
|
+
...(stripeAccountId !== undefined ? { accountId: stripeAccountId } : {}),
|
|
39
|
+
},
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
15
43
|
// =============================================================================
|
|
16
44
|
// Refund methods
|
|
17
45
|
// =============================================================================
|
package/src/client/index.ts
CHANGED
|
@@ -79,7 +79,6 @@ import type { ComponentApi } from "../component/_generated/component.js";
|
|
|
79
79
|
import type {
|
|
80
80
|
DisputeStatus,
|
|
81
81
|
PayoutStatus,
|
|
82
|
-
RefundStatus,
|
|
83
82
|
} from "../component/connect/validators.js";
|
|
84
83
|
import type { SplitRecipient } from "../component/lib/fees.js";
|
|
85
84
|
import * as checkoutImpl from "./billing/checkout.js";
|
|
@@ -89,6 +88,7 @@ import * as disputesImpl from "./connect/disputes.js";
|
|
|
89
88
|
import * as paymentMethodsImpl from "./connect/paymentMethods.js";
|
|
90
89
|
import * as payoutsImpl from "./connect/payouts.js";
|
|
91
90
|
import * as refundsImpl from "./connect/refunds.js";
|
|
91
|
+
export type { RefundPageOptions } from "./connect/refunds.js";
|
|
92
92
|
import * as transfersImpl from "./connect/transfers.js";
|
|
93
93
|
import * as accountLinksImpl from "./core/accountLinks.js";
|
|
94
94
|
import * as accountsImpl from "./core/accounts.js";
|
|
@@ -1360,16 +1360,15 @@ export class BetterStripe extends ReadContractClient {
|
|
|
1360
1360
|
|
|
1361
1361
|
async listRefunds(
|
|
1362
1362
|
ctx: RunCtx,
|
|
1363
|
-
opts?:
|
|
1364
|
-
stripeAccountId?: string;
|
|
1365
|
-
stripePaymentIntentId?: string;
|
|
1366
|
-
status?: RefundStatus;
|
|
1367
|
-
limit?: number;
|
|
1368
|
-
},
|
|
1363
|
+
opts?: refundsImpl.RefundListOptions,
|
|
1369
1364
|
): Promise<StripeComponentRefund[]> {
|
|
1370
1365
|
return refundsImpl.listRefunds(this.component, ctx, opts);
|
|
1371
1366
|
}
|
|
1372
1367
|
|
|
1368
|
+
paginateRefunds(ctx: RunCtx, opts: refundsImpl.RefundPageOptions) {
|
|
1369
|
+
return refundsImpl.paginateRefunds(this.component, ctx, opts);
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1373
1372
|
// DISPUTE METHODS
|
|
1374
1373
|
|
|
1375
1374
|
async getDisputeByStripeId(
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { componentsGeneric, type FunctionReference } from "convex/server";
|
|
2
|
+
import { expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import schema from "../component/schema.js";
|
|
5
|
+
import type { Component, RunCtx } from "./helpers.js";
|
|
6
|
+
import { BetterStripe, type RefundPageOptions } from "./index.js";
|
|
7
|
+
import { initConvexTest } from "./setup.test.js";
|
|
8
|
+
|
|
9
|
+
const modules = import.meta.glob("../component/**/*.{ts,js,tsx,jsx}");
|
|
10
|
+
|
|
11
|
+
it("reads multiple conjunctively scoped pages through the public client without provider credentials", async () => {
|
|
12
|
+
const t = initConvexTest();
|
|
13
|
+
t.registerComponent("betterStripe", schema, modules);
|
|
14
|
+
const component = componentsGeneric().betterStripe as unknown as Component;
|
|
15
|
+
const stripe = new BetterStripe(component, {});
|
|
16
|
+
const ctx = {
|
|
17
|
+
runQuery: (
|
|
18
|
+
ref: FunctionReference<"query">,
|
|
19
|
+
args: Record<string, unknown>,
|
|
20
|
+
) => t.query(ref, args),
|
|
21
|
+
} as unknown as RunCtx;
|
|
22
|
+
for (let index = 0; index < 5; index++) {
|
|
23
|
+
await t.mutation(component.connect.mutations.upsertRefund, {
|
|
24
|
+
stripeRefundId: `re_${index}`,
|
|
25
|
+
accountId: index === 4 ? "acct_foreign" : "acct_owner",
|
|
26
|
+
stripePaymentIntentId: index === 3 ? "pi_foreign" : "pi_original",
|
|
27
|
+
stripeChargeId: "ch_original",
|
|
28
|
+
amount: 500,
|
|
29
|
+
currency: "jpy",
|
|
30
|
+
status: "succeeded",
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const opts: RefundPageOptions = {
|
|
34
|
+
stripeAccountId: "acct_owner",
|
|
35
|
+
stripePaymentIntentId: "pi_original",
|
|
36
|
+
status: "succeeded",
|
|
37
|
+
paginationOpts: { numItems: 2, cursor: null },
|
|
38
|
+
};
|
|
39
|
+
const first = await stripe.paginateRefunds(ctx, opts);
|
|
40
|
+
expect(first.page).toHaveLength(2);
|
|
41
|
+
expect(first.isDone).toBe(false);
|
|
42
|
+
const last = await stripe.paginateRefunds(ctx, {
|
|
43
|
+
...opts,
|
|
44
|
+
paginationOpts: { numItems: 2, cursor: first.continueCursor },
|
|
45
|
+
});
|
|
46
|
+
expect(last.isDone).toBe(true);
|
|
47
|
+
expect([...first.page, ...last.page]).toHaveLength(3);
|
|
48
|
+
for (const refund of [...first.page, ...last.page]) {
|
|
49
|
+
expect(refund).toMatchObject({
|
|
50
|
+
accountId: "acct_owner",
|
|
51
|
+
stripePaymentIntentId: "pi_original",
|
|
52
|
+
stripeChargeId: "ch_original",
|
|
53
|
+
amount: 500,
|
|
54
|
+
currency: "jpy",
|
|
55
|
+
status: "succeeded",
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
expect(
|
|
59
|
+
await stripe.paginateRefunds(ctx, {
|
|
60
|
+
...opts,
|
|
61
|
+
stripeAccountId: "acct_absent",
|
|
62
|
+
}),
|
|
63
|
+
).toMatchObject({ page: [], isDone: true });
|
|
64
|
+
expect(
|
|
65
|
+
await stripe.listRefunds(ctx, { stripeAccountId: "acct_owner", limit: 1 }),
|
|
66
|
+
).toHaveLength(1);
|
|
67
|
+
});
|
|
@@ -24,6 +24,7 @@ import type * as costRecovery_imports from "../costRecovery/imports.js";
|
|
|
24
24
|
import type * as costRecovery_mutations from "../costRecovery/mutations.js";
|
|
25
25
|
import type * as costRecovery_queries from "../costRecovery/queries.js";
|
|
26
26
|
import type * as costRecovery_reservations from "../costRecovery/reservations.js";
|
|
27
|
+
import type * as earnings_arithmetic from "../earnings/arithmetic.js";
|
|
27
28
|
import type * as earnings_legacyReads from "../earnings/legacyReads.js";
|
|
28
29
|
import type * as earnings_mutations from "../earnings/mutations.js";
|
|
29
30
|
import type * as earnings_reads from "../earnings/reads.js";
|
|
@@ -36,6 +37,7 @@ import type * as lib_stripeFactory from "../lib/stripeFactory.js";
|
|
|
36
37
|
import type * as products_mutations from "../products/mutations.js";
|
|
37
38
|
import type * as products_queries from "../products/queries.js";
|
|
38
39
|
import type * as products_validators from "../products/validators.js";
|
|
40
|
+
import type * as refundHistory_queries from "../refundHistory/queries.js";
|
|
39
41
|
import type * as settlement_mutations from "../settlement/mutations.js";
|
|
40
42
|
import type * as settlement_queries from "../settlement/queries.js";
|
|
41
43
|
import type * as webhooks_mutations from "../webhooks/mutations.js";
|
|
@@ -66,6 +68,7 @@ const fullApi: ApiFromModules<{
|
|
|
66
68
|
"costRecovery/mutations": typeof costRecovery_mutations;
|
|
67
69
|
"costRecovery/queries": typeof costRecovery_queries;
|
|
68
70
|
"costRecovery/reservations": typeof costRecovery_reservations;
|
|
71
|
+
"earnings/arithmetic": typeof earnings_arithmetic;
|
|
69
72
|
"earnings/legacyReads": typeof earnings_legacyReads;
|
|
70
73
|
"earnings/mutations": typeof earnings_mutations;
|
|
71
74
|
"earnings/reads": typeof earnings_reads;
|
|
@@ -78,6 +81,7 @@ const fullApi: ApiFromModules<{
|
|
|
78
81
|
"products/mutations": typeof products_mutations;
|
|
79
82
|
"products/queries": typeof products_queries;
|
|
80
83
|
"products/validators": typeof products_validators;
|
|
84
|
+
"refundHistory/queries": typeof refundHistory_queries;
|
|
81
85
|
"settlement/mutations": typeof settlement_mutations;
|
|
82
86
|
"settlement/queries": typeof settlement_queries;
|
|
83
87
|
"webhooks/mutations": typeof webhooks_mutations;
|
|
@@ -2436,6 +2436,62 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
|
|
|
2436
2436
|
>;
|
|
2437
2437
|
};
|
|
2438
2438
|
};
|
|
2439
|
+
refundHistory: {
|
|
2440
|
+
queries: {
|
|
2441
|
+
paginateRefunds: FunctionReference<
|
|
2442
|
+
"query",
|
|
2443
|
+
"internal",
|
|
2444
|
+
{
|
|
2445
|
+
accountId?: string;
|
|
2446
|
+
paginationOpts: {
|
|
2447
|
+
cursor: string | null;
|
|
2448
|
+
endCursor?: string | null;
|
|
2449
|
+
id?: number;
|
|
2450
|
+
maximumBytesRead?: number;
|
|
2451
|
+
maximumRowsRead?: number;
|
|
2452
|
+
numItems: number;
|
|
2453
|
+
};
|
|
2454
|
+
status?:
|
|
2455
|
+
| "pending"
|
|
2456
|
+
| "requires_action"
|
|
2457
|
+
| "succeeded"
|
|
2458
|
+
| "failed"
|
|
2459
|
+
| "canceled";
|
|
2460
|
+
stripePaymentIntentId?: string;
|
|
2461
|
+
},
|
|
2462
|
+
{
|
|
2463
|
+
continueCursor: string;
|
|
2464
|
+
isDone: boolean;
|
|
2465
|
+
page: Array<{
|
|
2466
|
+
_creationTime: number;
|
|
2467
|
+
_id: string;
|
|
2468
|
+
accountId?: string;
|
|
2469
|
+
amount: number;
|
|
2470
|
+
currency: string;
|
|
2471
|
+
failureReason?: string;
|
|
2472
|
+
metadata?: any;
|
|
2473
|
+
reason?:
|
|
2474
|
+
| "duplicate"
|
|
2475
|
+
| "fraudulent"
|
|
2476
|
+
| "requested_by_customer"
|
|
2477
|
+
| "expired_uncaptured_charge";
|
|
2478
|
+
status:
|
|
2479
|
+
| "pending"
|
|
2480
|
+
| "requires_action"
|
|
2481
|
+
| "succeeded"
|
|
2482
|
+
| "failed"
|
|
2483
|
+
| "canceled";
|
|
2484
|
+
stripeChargeId?: string;
|
|
2485
|
+
stripePaymentIntentId?: string;
|
|
2486
|
+
stripeRefundId: string;
|
|
2487
|
+
}>;
|
|
2488
|
+
pageStatus?: "SplitRecommended" | "SplitRequired" | null;
|
|
2489
|
+
splitCursor?: string | null;
|
|
2490
|
+
},
|
|
2491
|
+
Name
|
|
2492
|
+
>;
|
|
2493
|
+
};
|
|
2494
|
+
};
|
|
2439
2495
|
settlement: {
|
|
2440
2496
|
mutations: {
|
|
2441
2497
|
claimCommissionInvoice: FunctionReference<
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
getAccountPayouts as getAccountPayoutsLegacy,
|
|
4
4
|
} from "../earnings/legacyReads.js";
|
|
5
5
|
import { currencyTotals, previewSize } from "../earnings/reads.js";
|
|
6
|
+
import { addSummaryAmounts } from "../earnings/arithmetic.js";
|
|
6
7
|
import { v } from "convex/values";
|
|
7
8
|
import { paginator } from "convex-helpers/server/pagination";
|
|
8
9
|
import schema from "../schema.js";
|
|
@@ -557,7 +558,7 @@ export const getAccountEarningsByCurrency = query({
|
|
|
557
558
|
currency: r.currency,
|
|
558
559
|
gross: r.gross,
|
|
559
560
|
reversed: r.reversed,
|
|
560
|
-
net: r.gross -
|
|
561
|
+
net: addSummaryAmounts(r.gross, -r.reversed),
|
|
561
562
|
transferCount: r.count,
|
|
562
563
|
})),
|
|
563
564
|
transfers,
|
|
@@ -54,6 +54,15 @@ export const refundsTable = defineTable(refundFields)
|
|
|
54
54
|
.index("by_account_id", ["accountId"])
|
|
55
55
|
.index("by_status", ["status"])
|
|
56
56
|
.index("by_account_id_and_status", ["accountId", "status"])
|
|
57
|
+
.index("by_account_id_and_stripe_payment_intent_id", [
|
|
58
|
+
"accountId",
|
|
59
|
+
"stripePaymentIntentId",
|
|
60
|
+
])
|
|
61
|
+
.index("by_account_id_and_stripe_payment_intent_id_and_status", [
|
|
62
|
+
"accountId",
|
|
63
|
+
"stripePaymentIntentId",
|
|
64
|
+
"status",
|
|
65
|
+
])
|
|
57
66
|
.index("by_payment_intent_id_and_status", [
|
|
58
67
|
"stripePaymentIntentId",
|
|
59
68
|
"status",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Check exact integer arithmetic before converting back to the public Number representation. */
|
|
2
|
+
export function addSummaryAmounts(left: number, right: number): number {
|
|
3
|
+
if (!Number.isSafeInteger(left) || !Number.isSafeInteger(right))
|
|
4
|
+
throw new Error("Currency totals require safe integer amounts");
|
|
5
|
+
const result = BigInt(left) + BigInt(right);
|
|
6
|
+
const limit = BigInt(Number.MAX_SAFE_INTEGER);
|
|
7
|
+
if (result > limit || result < -limit)
|
|
8
|
+
throw new Error("Currency totals exceed supported safe integer bounds");
|
|
9
|
+
return Number(result);
|
|
10
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { QueryCtx } from "../_generated/server.js";
|
|
2
|
+
import { addSummaryAmounts } from "./arithmetic.js";
|
|
2
3
|
export function previewSize(value = 50) {
|
|
3
4
|
if (!Number.isInteger(value) || value < 0 || value > 100)
|
|
4
5
|
throw new Error("Preview size must be an integer from 0 to 100");
|
|
@@ -37,5 +38,10 @@ export async function currencyTotals(
|
|
|
37
38
|
.take(501);
|
|
38
39
|
if (rows.length > 500)
|
|
39
40
|
throw new Error("Account exceeds supported currency count");
|
|
41
|
+
for (const row of rows) {
|
|
42
|
+
for (const value of [row.gross, row.reversed, row.paidOut, row.count])
|
|
43
|
+
addSummaryAmounts(value, 0);
|
|
44
|
+
addSummaryAmounts(row.gross, -row.reversed);
|
|
45
|
+
}
|
|
40
46
|
return rows;
|
|
41
47
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
customMutation,
|
|
5
5
|
} from "convex-helpers/server/customFunctions";
|
|
6
6
|
import type { DataModel } from "../_generated/dataModel.js";
|
|
7
|
+
import { addSummaryAmounts } from "./arithmetic.js";
|
|
7
8
|
import {
|
|
8
9
|
mutation as rawMutation,
|
|
9
10
|
type MutationCtx,
|
|
@@ -21,7 +22,7 @@ async function adjust(
|
|
|
21
22
|
ctx: MutationCtx,
|
|
22
23
|
kind: "earnings" | "payouts",
|
|
23
24
|
value: Contribution,
|
|
24
|
-
sign:
|
|
25
|
+
sign: 1 | -1,
|
|
25
26
|
) {
|
|
26
27
|
const row = await ctx.db
|
|
27
28
|
.query("currencyTotals")
|
|
@@ -33,11 +34,12 @@ async function adjust(
|
|
|
33
34
|
)
|
|
34
35
|
.unique();
|
|
35
36
|
const totals = {
|
|
36
|
-
gross: (row?.gross ?? 0
|
|
37
|
-
reversed: (row?.reversed ?? 0
|
|
38
|
-
paidOut: (row?.paidOut ?? 0
|
|
39
|
-
count: (row?.count ?? 0
|
|
37
|
+
gross: addSummaryAmounts(row?.gross ?? 0, sign * value.gross),
|
|
38
|
+
reversed: addSummaryAmounts(row?.reversed ?? 0, sign * value.reversed),
|
|
39
|
+
paidOut: addSummaryAmounts(row?.paidOut ?? 0, sign * value.paidOut),
|
|
40
|
+
count: addSummaryAmounts(row?.count ?? 0, sign * value.count),
|
|
40
41
|
};
|
|
42
|
+
addSummaryAmounts(totals.gross, -totals.reversed);
|
|
41
43
|
if (row) {
|
|
42
44
|
if (totals.count === 0) await ctx.db.delete("currencyTotals", row._id);
|
|
43
45
|
else await ctx.db.patch("currencyTotals", row._id, totals);
|
|
@@ -72,14 +74,17 @@ triggers.register("transfers", async (ctx, change) => {
|
|
|
72
74
|
triggers.register("payouts", async (ctx, change) => {
|
|
73
75
|
const contribution = (
|
|
74
76
|
row: NonNullable<typeof change.newDoc>,
|
|
75
|
-
): Contribution =>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
): Contribution => {
|
|
78
|
+
const amount = addSummaryAmounts(row.amount, 0);
|
|
79
|
+
return {
|
|
80
|
+
accountId: row.accountId,
|
|
81
|
+
currency: row.currency,
|
|
82
|
+
gross: 0,
|
|
83
|
+
reversed: 0,
|
|
84
|
+
paidOut: row.status === "paid" ? amount : 0,
|
|
85
|
+
count: 1,
|
|
86
|
+
};
|
|
87
|
+
};
|
|
83
88
|
if (change.oldDoc?.totalsRecorded)
|
|
84
89
|
await adjust(ctx, "payouts", contribution(change.oldDoc), -1);
|
|
85
90
|
if (change.newDoc) {
|