@classytic/revenue 1.1.2 → 1.1.4
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 +8 -7
- package/dist/application/services/index.d.mts +4 -0
- package/dist/application/services/index.mjs +3 -0
- package/dist/base-CsTlVQJe.d.mts +136 -0
- package/dist/base-DCoyIUj6.mjs +152 -0
- package/dist/category-resolver-DV83N8ok.mjs +284 -0
- package/dist/commission-split-BzB8cd39.mjs +485 -0
- package/dist/core/events.d.mts +294 -0
- package/dist/core/events.mjs +100 -0
- package/dist/core/index.d.mts +9 -0
- package/dist/core/index.mjs +8 -0
- package/dist/enums/index.d.mts +157 -0
- package/dist/enums/index.mjs +56 -0
- package/dist/errors-rRdOqnWx.d.mts +787 -0
- package/dist/escrow.enums-CZGrrdg7.mjs +101 -0
- package/dist/{escrow.enums-CE0VQsfe.d.ts → escrow.enums-DwdLuuve.d.mts} +30 -28
- package/dist/idempotency-DaYcUGY1.mjs +172 -0
- package/dist/index-Dsp7H5Wb.d.mts +471 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.mjs +38 -0
- package/dist/infrastructure/plugins/{index.d.ts → index.d.mts} +81 -109
- package/dist/infrastructure/plugins/index.mjs +345 -0
- package/dist/money-CvrDOijQ.mjs +271 -0
- package/dist/money-DPG8AtJ8.d.mts +112 -0
- package/dist/{payment.enums-C1BiGlRa.d.ts → payment.enums-HAuAS9Pp.d.mts} +14 -13
- package/dist/payment.enums-tEFVa-Xp.mjs +69 -0
- package/dist/plugin-BbK0OVHy.d.mts +327 -0
- package/dist/plugin-Cd_V04Em.mjs +210 -0
- package/dist/providers/index.d.mts +3 -0
- package/dist/providers/index.mjs +3 -0
- package/dist/reconciliation/{index.d.ts → index.d.mts} +90 -112
- package/dist/reconciliation/index.mjs +192 -0
- package/dist/retry-HHCOXYdn.d.mts +186 -0
- package/dist/revenue-BhdS7nXh.mjs +553 -0
- package/dist/schemas/index.d.mts +2665 -0
- package/dist/schemas/index.mjs +717 -0
- package/dist/schemas/validation.d.mts +375 -0
- package/dist/schemas/validation.mjs +325 -0
- package/dist/{settlement.enums-ByC1x0ye.d.ts → settlement.enums-DFhkqZEY.d.mts} +31 -29
- package/dist/settlement.schema-DnNSFpGd.d.mts +344 -0
- package/dist/settlement.service-DjzAjezU.d.mts +594 -0
- package/dist/settlement.service-DmdKv0Zu.mjs +2511 -0
- package/dist/split.enums-BrjabxIX.mjs +86 -0
- package/dist/split.enums-DmskfLOM.d.mts +43 -0
- package/dist/tax-BoCt5cEd.d.mts +61 -0
- package/dist/tax-EQ15DO81.mjs +162 -0
- package/dist/transaction.enums-pCyMFT4Z.mjs +96 -0
- package/dist/utils/{index.d.ts → index.d.mts} +91 -161
- package/dist/utils/index.mjs +346 -0
- package/package.json +39 -37
- package/dist/application/services/index.d.ts +0 -6
- package/dist/application/services/index.js +0 -3288
- package/dist/application/services/index.js.map +0 -1
- package/dist/core/events.d.ts +0 -455
- package/dist/core/events.js +0 -122
- package/dist/core/events.js.map +0 -1
- package/dist/core/index.d.ts +0 -13
- package/dist/core/index.js +0 -4591
- package/dist/core/index.js.map +0 -1
- package/dist/enums/index.d.ts +0 -159
- package/dist/enums/index.js +0 -296
- package/dist/enums/index.js.map +0 -1
- package/dist/index-DxIK0UmZ.d.ts +0 -633
- package/dist/index-EnfKzDbs.d.ts +0 -806
- package/dist/index-cLJBLUvx.d.ts +0 -478
- package/dist/index.d.ts +0 -43
- package/dist/index.js +0 -4864
- package/dist/index.js.map +0 -1
- package/dist/infrastructure/plugins/index.js +0 -292
- package/dist/infrastructure/plugins/index.js.map +0 -1
- package/dist/money-widWVD7r.d.ts +0 -111
- package/dist/plugin-Bb9HOE10.d.ts +0 -336
- package/dist/providers/index.d.ts +0 -145
- package/dist/providers/index.js +0 -141
- package/dist/providers/index.js.map +0 -1
- package/dist/reconciliation/index.js +0 -140
- package/dist/reconciliation/index.js.map +0 -1
- package/dist/retry-D4hFUwVk.d.ts +0 -194
- package/dist/schemas/index.d.ts +0 -2655
- package/dist/schemas/index.js +0 -841
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/validation.d.ts +0 -384
- package/dist/schemas/validation.js +0 -303
- package/dist/schemas/validation.js.map +0 -1
- package/dist/settlement.schema-CpamV7ZY.d.ts +0 -343
- package/dist/split.enums-DG3TxQf9.d.ts +0 -42
- package/dist/tax-CV8A0sxl.d.ts +0 -60
- package/dist/utils/index.js +0 -1202
- package/dist/utils/index.js.map +0 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
//#region src/enums/subscription.enums.ts
|
|
2
|
+
/**
|
|
3
|
+
* Subscription Enums
|
|
4
|
+
* @classytic/revenue
|
|
5
|
+
*
|
|
6
|
+
* All subscription-related enums and constants
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Subscription Status
|
|
10
|
+
*/
|
|
11
|
+
const SUBSCRIPTION_STATUS = {
|
|
12
|
+
ACTIVE: "active",
|
|
13
|
+
PAUSED: "paused",
|
|
14
|
+
CANCELLED: "cancelled",
|
|
15
|
+
EXPIRED: "expired",
|
|
16
|
+
PENDING: "pending",
|
|
17
|
+
PENDING_RENEWAL: "pending_renewal",
|
|
18
|
+
INACTIVE: "inactive"
|
|
19
|
+
};
|
|
20
|
+
const SUBSCRIPTION_STATUS_VALUES = Object.values(SUBSCRIPTION_STATUS);
|
|
21
|
+
/**
|
|
22
|
+
* Supported plan intervals
|
|
23
|
+
*/
|
|
24
|
+
const PLAN_KEYS = {
|
|
25
|
+
MONTHLY: "monthly",
|
|
26
|
+
QUARTERLY: "quarterly",
|
|
27
|
+
YEARLY: "yearly"
|
|
28
|
+
};
|
|
29
|
+
const PLAN_KEY_VALUES = Object.values(PLAN_KEYS);
|
|
30
|
+
const subscriptionStatusSet = new Set(SUBSCRIPTION_STATUS_VALUES);
|
|
31
|
+
const planKeySet = new Set(PLAN_KEY_VALUES);
|
|
32
|
+
function isSubscriptionStatus(value) {
|
|
33
|
+
return typeof value === "string" && subscriptionStatusSet.has(value);
|
|
34
|
+
}
|
|
35
|
+
function isPlanKey(value) {
|
|
36
|
+
return typeof value === "string" && planKeySet.has(value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/enums/split.enums.ts
|
|
41
|
+
/**
|
|
42
|
+
* Split Payment Enums
|
|
43
|
+
* @classytic/revenue
|
|
44
|
+
*
|
|
45
|
+
* Enums for multi-party commission splits
|
|
46
|
+
*/
|
|
47
|
+
const SPLIT_TYPE = {
|
|
48
|
+
PLATFORM_COMMISSION: "platform_commission",
|
|
49
|
+
AFFILIATE_COMMISSION: "affiliate_commission",
|
|
50
|
+
REFERRAL_COMMISSION: "referral_commission",
|
|
51
|
+
PARTNER_COMMISSION: "partner_commission",
|
|
52
|
+
CUSTOM: "custom"
|
|
53
|
+
};
|
|
54
|
+
const SPLIT_TYPE_VALUES = Object.values(SPLIT_TYPE);
|
|
55
|
+
const SPLIT_STATUS = {
|
|
56
|
+
PENDING: "pending",
|
|
57
|
+
DUE: "due",
|
|
58
|
+
PAID: "paid",
|
|
59
|
+
WAIVED: "waived",
|
|
60
|
+
CANCELLED: "cancelled"
|
|
61
|
+
};
|
|
62
|
+
const SPLIT_STATUS_VALUES = Object.values(SPLIT_STATUS);
|
|
63
|
+
const PAYOUT_METHOD = {
|
|
64
|
+
BANK_TRANSFER: "bank_transfer",
|
|
65
|
+
MOBILE_WALLET: "mobile_wallet",
|
|
66
|
+
PLATFORM_BALANCE: "platform_balance",
|
|
67
|
+
CRYPTO: "crypto",
|
|
68
|
+
CHECK: "check",
|
|
69
|
+
MANUAL: "manual"
|
|
70
|
+
};
|
|
71
|
+
const PAYOUT_METHOD_VALUES = Object.values(PAYOUT_METHOD);
|
|
72
|
+
const splitTypeSet = new Set(SPLIT_TYPE_VALUES);
|
|
73
|
+
const splitStatusSet = new Set(SPLIT_STATUS_VALUES);
|
|
74
|
+
const payoutMethodSet = new Set(PAYOUT_METHOD_VALUES);
|
|
75
|
+
function isSplitType(value) {
|
|
76
|
+
return typeof value === "string" && splitTypeSet.has(value);
|
|
77
|
+
}
|
|
78
|
+
function isSplitStatus(value) {
|
|
79
|
+
return typeof value === "string" && splitStatusSet.has(value);
|
|
80
|
+
}
|
|
81
|
+
function isPayoutMethod(value) {
|
|
82
|
+
return typeof value === "string" && payoutMethodSet.has(value);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
export { SPLIT_TYPE as a, isSplitStatus as c, PLAN_KEY_VALUES as d, SUBSCRIPTION_STATUS as f, isSubscriptionStatus as h, SPLIT_STATUS_VALUES as i, isSplitType as l, isPlanKey as m, PAYOUT_METHOD_VALUES as n, SPLIT_TYPE_VALUES as o, SUBSCRIPTION_STATUS_VALUES as p, SPLIT_STATUS as r, isPayoutMethod as s, PAYOUT_METHOD as t, PLAN_KEYS as u };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/enums/split.enums.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Split Payment Enums
|
|
4
|
+
* @classytic/revenue
|
|
5
|
+
*
|
|
6
|
+
* Enums for multi-party commission splits
|
|
7
|
+
*/
|
|
8
|
+
declare const SPLIT_TYPE: {
|
|
9
|
+
readonly PLATFORM_COMMISSION: "platform_commission";
|
|
10
|
+
readonly AFFILIATE_COMMISSION: "affiliate_commission";
|
|
11
|
+
readonly REFERRAL_COMMISSION: "referral_commission";
|
|
12
|
+
readonly PARTNER_COMMISSION: "partner_commission";
|
|
13
|
+
readonly CUSTOM: "custom";
|
|
14
|
+
};
|
|
15
|
+
type SplitType = typeof SPLIT_TYPE;
|
|
16
|
+
type SplitTypeValue = SplitType[keyof SplitType];
|
|
17
|
+
declare const SPLIT_TYPE_VALUES: SplitTypeValue[];
|
|
18
|
+
declare const SPLIT_STATUS: {
|
|
19
|
+
readonly PENDING: "pending";
|
|
20
|
+
readonly DUE: "due";
|
|
21
|
+
readonly PAID: "paid";
|
|
22
|
+
readonly WAIVED: "waived";
|
|
23
|
+
readonly CANCELLED: "cancelled";
|
|
24
|
+
};
|
|
25
|
+
type SplitStatus = typeof SPLIT_STATUS;
|
|
26
|
+
type SplitStatusValue = SplitStatus[keyof SplitStatus];
|
|
27
|
+
declare const SPLIT_STATUS_VALUES: SplitStatusValue[];
|
|
28
|
+
declare const PAYOUT_METHOD: {
|
|
29
|
+
readonly BANK_TRANSFER: "bank_transfer";
|
|
30
|
+
readonly MOBILE_WALLET: "mobile_wallet";
|
|
31
|
+
readonly PLATFORM_BALANCE: "platform_balance";
|
|
32
|
+
readonly CRYPTO: "crypto";
|
|
33
|
+
readonly CHECK: "check";
|
|
34
|
+
readonly MANUAL: "manual";
|
|
35
|
+
};
|
|
36
|
+
type PayoutMethod = typeof PAYOUT_METHOD;
|
|
37
|
+
type PayoutMethodValue = PayoutMethod[keyof PayoutMethod];
|
|
38
|
+
declare const PAYOUT_METHOD_VALUES: PayoutMethodValue[];
|
|
39
|
+
declare function isSplitType(value: unknown): value is SplitTypeValue;
|
|
40
|
+
declare function isSplitStatus(value: unknown): value is SplitStatusValue;
|
|
41
|
+
declare function isPayoutMethod(value: unknown): value is PayoutMethodValue;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { SPLIT_STATUS as a, SPLIT_TYPE_VALUES as c, SplitType as d, SplitTypeValue as f, isSplitType as h, PayoutMethodValue as i, SplitStatus as l, isSplitStatus as m, PAYOUT_METHOD_VALUES as n, SPLIT_STATUS_VALUES as o, isPayoutMethod as p, PayoutMethod as r, SPLIT_TYPE as s, PAYOUT_METHOD as t, SplitStatusValue as u };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//#region src/shared/types/tax.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Tax Types
|
|
4
|
+
* @classytic/revenue
|
|
5
|
+
*
|
|
6
|
+
* Type definitions for tax calculation
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Tax Configuration
|
|
10
|
+
* Apps provide this configuration based on their jurisdiction
|
|
11
|
+
*
|
|
12
|
+
* Philosophy: Apps know their tax rules, library does the math
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Australia - 10% GST
|
|
17
|
+
* const taxConfig: TaxConfig = {
|
|
18
|
+
* isRegistered: true,
|
|
19
|
+
* defaultRate: 0.10,
|
|
20
|
+
* pricesIncludeTax: false,
|
|
21
|
+
* exemptCategories: ['education', 'medical'],
|
|
22
|
+
* };
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
interface TaxConfig {
|
|
26
|
+
/** Is the organization registered for tax collection? */
|
|
27
|
+
isRegistered: boolean;
|
|
28
|
+
/** Default tax rate (0-1, e.g., 0.15 = 15%) */
|
|
29
|
+
defaultRate: number;
|
|
30
|
+
/** Do displayed prices include tax? */
|
|
31
|
+
pricesIncludeTax: boolean;
|
|
32
|
+
/** Categories exempt from tax (e.g., groceries, education) */
|
|
33
|
+
exemptCategories?: string[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Tax Calculation Result
|
|
37
|
+
* Returned by calculateTax() utility
|
|
38
|
+
*/
|
|
39
|
+
interface TaxCalculation {
|
|
40
|
+
/** Is tax applicable for this transaction? */
|
|
41
|
+
isApplicable: boolean;
|
|
42
|
+
/** Tax rate used (0-1) */
|
|
43
|
+
rate: number;
|
|
44
|
+
/** Base amount (before tax) */
|
|
45
|
+
baseAmount: number;
|
|
46
|
+
/** Tax amount */
|
|
47
|
+
taxAmount: number;
|
|
48
|
+
/** Total amount (base + tax) */
|
|
49
|
+
totalAmount: number;
|
|
50
|
+
/** Were prices tax-inclusive? */
|
|
51
|
+
pricesIncludeTax: boolean;
|
|
52
|
+
/** Tax type */
|
|
53
|
+
type?: TaxType;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Tax Type
|
|
57
|
+
* Indicates whether tax is collected or paid
|
|
58
|
+
*/
|
|
59
|
+
type TaxType = 'collected' | 'paid' | 'exempt';
|
|
60
|
+
//#endregion
|
|
61
|
+
export { TaxConfig as n, TaxType as r, TaxCalculation as t };
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { C as ValidationError } from "./category-resolver-DV83N8ok.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/shared/utils/calculators/tax.ts
|
|
4
|
+
/**
|
|
5
|
+
* Calculate tax for a transaction
|
|
6
|
+
*
|
|
7
|
+
* Handles both tax-inclusive and tax-exclusive pricing:
|
|
8
|
+
* - Tax-exclusive: Customer pays baseAmount + tax
|
|
9
|
+
* - Tax-inclusive: Customer pays totalAmount (which includes tax)
|
|
10
|
+
*
|
|
11
|
+
* @param amount - Transaction amount (in smallest currency unit, e.g., cents)
|
|
12
|
+
* @param category - Transaction category (for exemption check)
|
|
13
|
+
* @param config - Tax configuration from app
|
|
14
|
+
* @returns Tax calculation result
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Tax-exclusive pricing (customer pays base + tax)
|
|
19
|
+
* const result = calculateTax(10000, 'subscription', {
|
|
20
|
+
* isRegistered: true,
|
|
21
|
+
* defaultRate: 0.15,
|
|
22
|
+
* pricesIncludeTax: false,
|
|
23
|
+
* });
|
|
24
|
+
* // result = {
|
|
25
|
+
* // isApplicable: true,
|
|
26
|
+
* // rate: 0.15,
|
|
27
|
+
* // baseAmount: 10000,
|
|
28
|
+
* // taxAmount: 1500,
|
|
29
|
+
* // totalAmount: 11500,
|
|
30
|
+
* // pricesIncludeTax: false
|
|
31
|
+
* // }
|
|
32
|
+
*
|
|
33
|
+
* // Tax-inclusive pricing (price already includes tax)
|
|
34
|
+
* const result2 = calculateTax(11500, 'subscription', {
|
|
35
|
+
* isRegistered: true,
|
|
36
|
+
* defaultRate: 0.15,
|
|
37
|
+
* pricesIncludeTax: true,
|
|
38
|
+
* });
|
|
39
|
+
* // result2 = {
|
|
40
|
+
* // isApplicable: true,
|
|
41
|
+
* // rate: 0.15,
|
|
42
|
+
* // baseAmount: 10000,
|
|
43
|
+
* // taxAmount: 1500,
|
|
44
|
+
* // totalAmount: 11500,
|
|
45
|
+
* // pricesIncludeTax: true
|
|
46
|
+
* // }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
function calculateTax(amount, category, config) {
|
|
50
|
+
if (!config?.isRegistered || config.exemptCategories?.includes(category)) return {
|
|
51
|
+
isApplicable: false,
|
|
52
|
+
rate: 0,
|
|
53
|
+
baseAmount: amount,
|
|
54
|
+
taxAmount: 0,
|
|
55
|
+
totalAmount: amount,
|
|
56
|
+
pricesIncludeTax: false
|
|
57
|
+
};
|
|
58
|
+
const rate = config.defaultRate;
|
|
59
|
+
const [baseAmount, taxAmount, totalAmount] = config.pricesIncludeTax ? [
|
|
60
|
+
Math.round(amount / (1 + rate)),
|
|
61
|
+
Math.round(amount - amount / (1 + rate)),
|
|
62
|
+
amount
|
|
63
|
+
] : [
|
|
64
|
+
amount,
|
|
65
|
+
Math.round(amount * rate),
|
|
66
|
+
Math.round(amount * (1 + rate))
|
|
67
|
+
];
|
|
68
|
+
return {
|
|
69
|
+
isApplicable: true,
|
|
70
|
+
rate,
|
|
71
|
+
baseAmount,
|
|
72
|
+
taxAmount,
|
|
73
|
+
totalAmount,
|
|
74
|
+
pricesIncludeTax: config.pricesIncludeTax
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get tax type based on transaction flow
|
|
79
|
+
*
|
|
80
|
+
* - Inflow transactions → tax is "collected" (you collect from customer)
|
|
81
|
+
* - Outflow transactions → tax is "paid" (you pay to supplier)
|
|
82
|
+
* - Exempt categories → "exempt"
|
|
83
|
+
*
|
|
84
|
+
* @param transactionFlow - 'inflow' or 'outflow'
|
|
85
|
+
* @param category - Transaction category
|
|
86
|
+
* @param exemptCategories - List of exempt categories
|
|
87
|
+
* @returns Tax type
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* getTaxType('inflow', 'subscription', []) // 'collected'
|
|
92
|
+
* getTaxType('outflow', 'refund', []) // 'paid'
|
|
93
|
+
* getTaxType('inflow', 'education', ['education']) // 'exempt'
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
function getTaxType(transactionFlow, category, exemptCategories = []) {
|
|
97
|
+
if (exemptCategories.includes(category)) return "exempt";
|
|
98
|
+
return transactionFlow === "inflow" ? "collected" : "paid";
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Reverse tax calculation for refunds
|
|
102
|
+
* When refunding a transaction, tax must be reversed proportionally
|
|
103
|
+
*
|
|
104
|
+
* @param originalTax - Tax from original transaction
|
|
105
|
+
* @param originalAmount - Original transaction amount
|
|
106
|
+
* @param refundAmount - Amount being refunded
|
|
107
|
+
* @returns Reversed tax calculation
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* // Original: $100 + $15 tax = $115
|
|
112
|
+
* const originalTax = {
|
|
113
|
+
* isApplicable: true,
|
|
114
|
+
* rate: 0.15,
|
|
115
|
+
* baseAmount: 10000,
|
|
116
|
+
* taxAmount: 1500,
|
|
117
|
+
* totalAmount: 11500,
|
|
118
|
+
* type: 'collected',
|
|
119
|
+
* };
|
|
120
|
+
*
|
|
121
|
+
* // Refund 50% ($57.50)
|
|
122
|
+
* const refundTax = reverseTax(originalTax, 11500, 5750);
|
|
123
|
+
* // refundTax = {
|
|
124
|
+
* // isApplicable: true,
|
|
125
|
+
* // rate: 0.15,
|
|
126
|
+
* // baseAmount: 5000,
|
|
127
|
+
* // taxAmount: 750,
|
|
128
|
+
* // totalAmount: 5750,
|
|
129
|
+
* // type: 'paid', // Reversed!
|
|
130
|
+
* // }
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
function reverseTax(originalTax, originalAmount, refundAmount) {
|
|
134
|
+
if (!originalTax.isApplicable) return {
|
|
135
|
+
isApplicable: false,
|
|
136
|
+
rate: 0,
|
|
137
|
+
baseAmount: refundAmount,
|
|
138
|
+
taxAmount: 0,
|
|
139
|
+
totalAmount: refundAmount,
|
|
140
|
+
pricesIncludeTax: false
|
|
141
|
+
};
|
|
142
|
+
if (!originalAmount || originalAmount <= 0) throw new ValidationError("Original amount must be greater than 0", { originalAmount });
|
|
143
|
+
if (refundAmount < 0) throw new ValidationError("Refund amount cannot be negative", { refundAmount });
|
|
144
|
+
if (refundAmount > originalAmount) throw new ValidationError(`Refund amount (${refundAmount}) exceeds original amount (${originalAmount})`, {
|
|
145
|
+
refundAmount,
|
|
146
|
+
originalAmount
|
|
147
|
+
});
|
|
148
|
+
const refundRatio = refundAmount / originalAmount;
|
|
149
|
+
const reversedType = originalTax.type ? originalTax.type === "collected" ? "paid" : originalTax.type === "paid" ? "collected" : "exempt" : void 0;
|
|
150
|
+
return {
|
|
151
|
+
isApplicable: true,
|
|
152
|
+
rate: originalTax.rate,
|
|
153
|
+
baseAmount: Math.round(originalTax.baseAmount * refundRatio),
|
|
154
|
+
taxAmount: Math.round(originalTax.taxAmount * refundRatio),
|
|
155
|
+
totalAmount: Math.round(originalTax.totalAmount * refundRatio),
|
|
156
|
+
pricesIncludeTax: originalTax.pricesIncludeTax,
|
|
157
|
+
type: reversedType
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
//#endregion
|
|
162
|
+
export { getTaxType as n, reverseTax as r, calculateTax as t };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
//#region src/enums/transaction.enums.ts
|
|
2
|
+
/**
|
|
3
|
+
* Transaction Enums
|
|
4
|
+
* @classytic/revenue
|
|
5
|
+
*
|
|
6
|
+
* Library-managed transaction enums only.
|
|
7
|
+
* Users should define their own categories and merge with these.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Transaction Flow - Directional money movement
|
|
11
|
+
*
|
|
12
|
+
* INFLOW: Money coming in (payments, subscriptions, purchases, receipts)
|
|
13
|
+
* OUTFLOW: Money going out (refunds, payouts, expenses, disbursements)
|
|
14
|
+
*
|
|
15
|
+
* Industry-standard terminology compatible with QuickBooks, Xero, and other accounting systems.
|
|
16
|
+
* Users can map categories to flow directions via transactionTypeMapping config.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Revenue platform
|
|
20
|
+
* { type: 'subscription', flow: 'inflow' }
|
|
21
|
+
*
|
|
22
|
+
* // Payroll platform
|
|
23
|
+
* { type: 'salary', flow: 'outflow' }
|
|
24
|
+
*
|
|
25
|
+
* // Marketplace
|
|
26
|
+
* { type: 'commission', flow: 'outflow' } // Paying sellers
|
|
27
|
+
* { type: 'platform_fee', flow: 'inflow' } // Platform revenue
|
|
28
|
+
*/
|
|
29
|
+
const TRANSACTION_FLOW = {
|
|
30
|
+
INFLOW: "inflow",
|
|
31
|
+
OUTFLOW: "outflow"
|
|
32
|
+
};
|
|
33
|
+
/** @deprecated Use TRANSACTION_FLOW instead */
|
|
34
|
+
const TRANSACTION_TYPE = TRANSACTION_FLOW;
|
|
35
|
+
const TRANSACTION_FLOW_VALUES = Object.values(TRANSACTION_FLOW);
|
|
36
|
+
/** @deprecated Use TRANSACTION_FLOW_VALUES instead */
|
|
37
|
+
const TRANSACTION_TYPE_VALUES = TRANSACTION_FLOW_VALUES;
|
|
38
|
+
/**
|
|
39
|
+
* Transaction Status - Library-managed states
|
|
40
|
+
*/
|
|
41
|
+
const TRANSACTION_STATUS = {
|
|
42
|
+
PENDING: "pending",
|
|
43
|
+
PAYMENT_INITIATED: "payment_initiated",
|
|
44
|
+
PROCESSING: "processing",
|
|
45
|
+
REQUIRES_ACTION: "requires_action",
|
|
46
|
+
VERIFIED: "verified",
|
|
47
|
+
COMPLETED: "completed",
|
|
48
|
+
FAILED: "failed",
|
|
49
|
+
CANCELLED: "cancelled",
|
|
50
|
+
EXPIRED: "expired",
|
|
51
|
+
REFUNDED: "refunded",
|
|
52
|
+
PARTIALLY_REFUNDED: "partially_refunded"
|
|
53
|
+
};
|
|
54
|
+
const TRANSACTION_STATUS_VALUES = Object.values(TRANSACTION_STATUS);
|
|
55
|
+
/**
|
|
56
|
+
* Categories managed by this library
|
|
57
|
+
*
|
|
58
|
+
* SUBSCRIPTION: Recurring subscription payments
|
|
59
|
+
* PURCHASE: One-time purchases
|
|
60
|
+
*
|
|
61
|
+
* Users should spread these into their own category enums:
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* import { LIBRARY_CATEGORIES } from '@classytic/revenue';
|
|
65
|
+
*
|
|
66
|
+
* export const MY_CATEGORIES = {
|
|
67
|
+
* ...LIBRARY_CATEGORIES,
|
|
68
|
+
* SALARY: 'salary',
|
|
69
|
+
* RENT: 'rent',
|
|
70
|
+
* EQUIPMENT: 'equipment',
|
|
71
|
+
* } as const;
|
|
72
|
+
*/
|
|
73
|
+
const LIBRARY_CATEGORIES = {
|
|
74
|
+
SUBSCRIPTION: "subscription",
|
|
75
|
+
PURCHASE: "purchase"
|
|
76
|
+
};
|
|
77
|
+
const LIBRARY_CATEGORY_VALUES = Object.values(LIBRARY_CATEGORIES);
|
|
78
|
+
const transactionFlowSet = new Set(TRANSACTION_FLOW_VALUES);
|
|
79
|
+
const transactionStatusSet = new Set(TRANSACTION_STATUS_VALUES);
|
|
80
|
+
const libraryCategorySet = new Set(LIBRARY_CATEGORY_VALUES);
|
|
81
|
+
function isLibraryCategory(value) {
|
|
82
|
+
return typeof value === "string" && libraryCategorySet.has(value);
|
|
83
|
+
}
|
|
84
|
+
function isTransactionFlow(value) {
|
|
85
|
+
return typeof value === "string" && transactionFlowSet.has(value);
|
|
86
|
+
}
|
|
87
|
+
/** @deprecated Use isTransactionFlow instead */
|
|
88
|
+
function isTransactionType(value) {
|
|
89
|
+
return isTransactionFlow(value);
|
|
90
|
+
}
|
|
91
|
+
function isTransactionStatus(value) {
|
|
92
|
+
return typeof value === "string" && transactionStatusSet.has(value);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
export { TRANSACTION_STATUS as a, TRANSACTION_TYPE_VALUES as c, isTransactionStatus as d, isTransactionType as f, TRANSACTION_FLOW_VALUES as i, isLibraryCategory as l, LIBRARY_CATEGORY_VALUES as n, TRANSACTION_STATUS_VALUES as o, TRANSACTION_FLOW as r, TRANSACTION_TYPE as s, LIBRARY_CATEGORIES as t, isTransactionFlow as u };
|