@saasicat/nest 1.0.0-rc.21 → 1.0.0-rc.22
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/.build-stamp +1 -1
- package/dist/_entries.cjs +4887 -3609
- package/dist/admin/index.js +7 -5
- package/dist/{aggregation-ChpZDh0g.d.ts → aggregation-6fPkeV8i.d.ts} +39 -4
- package/dist/{aggregation-OpnhwzF5.d.cts → aggregation-DjQUc7yd.d.cts} +39 -4
- package/dist/billing/index.d.cts +68 -9
- package/dist/billing/index.d.ts +68 -9
- package/dist/billing/index.js +16 -5
- package/dist/checkout-offer/index.d.cts +2 -2
- package/dist/checkout-offer/index.d.ts +2 -2
- package/dist/checkout-offer/index.js +4 -4
- package/dist/{checkout-offer.service-CCVxG9b2.d.cts → checkout-offer.service-DmVGrT4v.d.cts} +1 -1
- package/dist/{checkout-offer.service-BeHgYikI.d.ts → checkout-offer.service-Yi30L4ry.d.ts} +1 -1
- package/dist/{chunk-WHJSYKNC.js → chunk-3U4N5UYD.js} +1 -1
- package/dist/{chunk-M47BNEY2.js → chunk-3YYLOYUT.js} +1373 -266
- package/dist/{chunk-G6EZWECL.js → chunk-B4YP7REK.js} +94 -26
- package/dist/{chunk-QPVDCKYS.js → chunk-ESEWSAOV.js} +4 -3
- package/dist/{chunk-NDLC5GYK.js → chunk-EU4N5LET.js} +4 -3
- package/dist/{chunk-LLYVYRGJ.js → chunk-F2PF4IXB.js} +1 -275
- package/dist/{chunk-AOS2JPDD.js → chunk-FJIOHAO5.js} +77 -41
- package/dist/{chunk-TOEFN7DN.js → chunk-FPMBQDW7.js} +2 -2
- package/dist/chunk-OSOP4KWL.js +288 -0
- package/dist/{chunk-3RLWML2S.js → chunk-QWKBOLBH.js} +35 -0
- package/dist/{chunk-JBCC6C3M.js → chunk-R3I5X262.js} +5 -4
- package/dist/{chunk-4SDSYV4A.js → chunk-T6WXDGIU.js} +1 -1
- package/dist/{chunk-R5YCJBHY.js → chunk-U5UPEFWC.js} +2 -2
- package/dist/{chunk-XSSWYPP5.js → chunk-UMZCOCT5.js} +1 -1
- package/dist/{chunk-7NJKVC5X.js → chunk-WQNOCOI2.js} +53 -6
- package/dist/{chunk-55QEDAMX.js → chunk-WTAS2CLM.js} +4 -9
- package/dist/{enforce-quota.interceptor-BFyVdWe8.d.cts → enforce-quota.interceptor-B9UhCBXx.d.cts} +2 -2
- package/dist/{enforce-quota.interceptor-GaBXboGx.d.ts → enforce-quota.interceptor-CR2waXNA.d.ts} +2 -2
- package/dist/entitlement/index.d.cts +1 -1
- package/dist/entitlement/index.d.ts +1 -1
- package/dist/entitlement/index.js +4 -2
- package/dist/index.d.cts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.js +36 -20
- package/dist/{issuer-identity.check-CBO0vcsq.d.cts → issuer-identity.check-BntcNdld.d.cts} +1 -1
- package/dist/{issuer-identity.check-Cz9CEMkZ.d.ts → issuer-identity.check-DFmS8whs.d.ts} +1 -1
- package/dist/{module-options-qAOwinHR.d.cts → module-options-C4S_StYF.d.cts} +2 -2
- package/dist/{module-options-DmQ3G4sZ.d.ts → module-options-DxJI-1iH.d.ts} +2 -2
- package/dist/payments/index.js +2 -2
- package/dist/platform/index.d.cts +25 -16
- package/dist/platform/index.d.ts +25 -16
- package/dist/platform/index.js +16 -14
- package/dist/promo/index.d.cts +11 -4
- package/dist/promo/index.d.ts +11 -4
- package/dist/promo/index.js +5 -3
- package/dist/{promo.module-CKkECmU8.d.cts → promo.module-Ddx-swUV.d.cts} +1 -1
- package/dist/{promo.module-DuIJdK3U.d.ts → promo.module-PsIvDcUp.d.ts} +1 -1
- package/dist/{promo.service-BYBu6dy3.d.cts → promo.service-BextPvx5.d.cts} +23 -1
- package/dist/{promo.service-CFjfF0Xm.d.ts → promo.service-Dqqh0JXn.d.ts} +23 -1
- package/dist/registration/index.d.cts +2 -2
- package/dist/registration/index.d.ts +2 -2
- package/dist/registration/index.js +5 -5
- package/dist/subscription-contract/index.js +2 -2
- package/dist/{tenant-billing.controller-DKbAqTbM.d.cts → tenant-billing.controller-BC6-S5cT.d.cts} +91 -10
- package/dist/{tenant-billing.controller-BLqbsONe.d.ts → tenant-billing.controller-BuQDQ76i.d.ts} +91 -10
- package/dist/{tenant-billing.module-ClbjzocC.d.cts → tenant-billing.module-C6MFfCKq.d.cts} +24 -1
- package/dist/{tenant-billing.module-DohgJJ2m.d.ts → tenant-billing.module-CUCQL0-k.d.ts} +24 -1
- package/dist/testing/index.d.cts +6 -6
- package/dist/testing/index.d.ts +6 -6
- package/dist/testing/index.js +33 -31
- package/package.json +3 -3
|
@@ -1,12 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AdminResourcesService
|
|
3
|
+
} from "./chunk-OSOP4KWL.js";
|
|
1
4
|
import {
|
|
2
5
|
AdminAuditService
|
|
3
6
|
} from "./chunk-OOTEXP47.js";
|
|
4
7
|
import {
|
|
5
|
-
PromoCodesService
|
|
6
|
-
|
|
8
|
+
PromoCodesService,
|
|
9
|
+
buildLabel,
|
|
10
|
+
promoCodeDiscountNet
|
|
11
|
+
} from "./chunk-QWKBOLBH.js";
|
|
7
12
|
import {
|
|
8
|
-
SubscriptionContractService
|
|
9
|
-
|
|
13
|
+
SubscriptionContractService,
|
|
14
|
+
generatedDiscountLine
|
|
15
|
+
} from "./chunk-EU4N5LET.js";
|
|
10
16
|
import {
|
|
11
17
|
resolveBundlePriceNet
|
|
12
18
|
} from "./chunk-KPEMTBOP.js";
|
|
@@ -16,7 +22,7 @@ import {
|
|
|
16
22
|
SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN,
|
|
17
23
|
cancellationHasLanded,
|
|
18
24
|
toEffectiveLimitsSnapshot
|
|
19
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-B4YP7REK.js";
|
|
20
26
|
import {
|
|
21
27
|
ENTITLEMENT_SERVICE_TOKEN
|
|
22
28
|
} from "./chunk-OUDSQ3PU.js";
|
|
@@ -61,9 +67,15 @@ import {
|
|
|
61
67
|
USER_EMAIL_RESOLVER_TOKEN,
|
|
62
68
|
USER_ID_RESOLVER_TOKEN
|
|
63
69
|
} from "./chunk-GPQWGA6B.js";
|
|
70
|
+
import {
|
|
71
|
+
RLS_BYPASS_PORT_TOKEN
|
|
72
|
+
} from "./chunk-SZ7RFPXA.js";
|
|
64
73
|
import {
|
|
65
74
|
subscriberProviders
|
|
66
75
|
} from "./chunk-WOEJ6K7M.js";
|
|
76
|
+
import {
|
|
77
|
+
SUBSCRIBER_REPOSITORY_TOKEN
|
|
78
|
+
} from "./chunk-LF6J4YYN.js";
|
|
67
79
|
import {
|
|
68
80
|
SaaSiCatPublicRoute
|
|
69
81
|
} from "./chunk-YSC46BGM.js";
|
|
@@ -1028,23 +1040,52 @@ var SELF_SERVICE_BLOCKED_BUNDLES_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/ne
|
|
|
1028
1040
|
var DAY_MS2 = 864e5;
|
|
1029
1041
|
function computeProration(input) {
|
|
1030
1042
|
const { periodStart, periodEnd, now, currentPriceNet, targetPriceNet } = input;
|
|
1031
|
-
const daysInPeriod =
|
|
1032
|
-
const daysRemaining = Math.max(0, Math.min(daysInPeriod, Math.round((periodEnd.getTime() - now.getTime()) / DAY_MS2)));
|
|
1043
|
+
const { daysInPeriod, daysRemaining } = daysOf(periodStart, periodEnd, now);
|
|
1033
1044
|
const rawDeltaNet = round2((targetPriceNet - currentPriceNet) * daysRemaining / daysInPeriod);
|
|
1034
|
-
const prorataDeltaNet = Math.max(0, rawDeltaNet);
|
|
1035
1045
|
return {
|
|
1046
|
+
basis: "difference",
|
|
1036
1047
|
daysRemainingInPeriod: daysRemaining,
|
|
1037
1048
|
daysInPeriod,
|
|
1038
1049
|
periodStart,
|
|
1039
1050
|
periodEnd,
|
|
1040
1051
|
currentPriceNet,
|
|
1041
1052
|
targetPriceNet,
|
|
1042
|
-
prorataDeltaNet,
|
|
1053
|
+
prorataDeltaNet: Math.max(0, rawDeltaNet),
|
|
1043
1054
|
rawDeltaNet,
|
|
1044
|
-
isFree: rawDeltaNet < 0
|
|
1055
|
+
isFree: rawDeltaNet < 0,
|
|
1056
|
+
remainderNet: 0
|
|
1045
1057
|
};
|
|
1046
1058
|
}
|
|
1047
1059
|
__name(computeProration, "computeProration");
|
|
1060
|
+
function computeNewPeriodCharge(input) {
|
|
1061
|
+
const { periodStart, periodEnd, now, currentPriceNet, targetPriceNet } = input;
|
|
1062
|
+
const { daysInPeriod, daysRemaining } = daysOf(periodStart, periodEnd, now);
|
|
1063
|
+
const remainderNet = round2(currentPriceNet * daysRemaining / daysInPeriod);
|
|
1064
|
+
const rawDeltaNet = round2(targetPriceNet - remainderNet);
|
|
1065
|
+
return {
|
|
1066
|
+
basis: "newPeriod",
|
|
1067
|
+
daysRemainingInPeriod: daysRemaining,
|
|
1068
|
+
daysInPeriod,
|
|
1069
|
+
periodStart,
|
|
1070
|
+
periodEnd,
|
|
1071
|
+
currentPriceNet,
|
|
1072
|
+
targetPriceNet,
|
|
1073
|
+
prorataDeltaNet: Math.max(0, rawDeltaNet),
|
|
1074
|
+
rawDeltaNet,
|
|
1075
|
+
isFree: rawDeltaNet < 0,
|
|
1076
|
+
remainderNet
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
__name(computeNewPeriodCharge, "computeNewPeriodCharge");
|
|
1080
|
+
function daysOf(periodStart, periodEnd, now) {
|
|
1081
|
+
const daysInPeriod = Math.max(1, Math.round((periodEnd.getTime() - periodStart.getTime()) / DAY_MS2));
|
|
1082
|
+
const daysRemaining = Math.max(0, Math.min(daysInPeriod, Math.round((periodEnd.getTime() - now.getTime()) / DAY_MS2)));
|
|
1083
|
+
return {
|
|
1084
|
+
daysInPeriod,
|
|
1085
|
+
daysRemaining
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
__name(daysOf, "daysOf");
|
|
1048
1089
|
function round2(n) {
|
|
1049
1090
|
return Math.round(n * 100) / 100;
|
|
1050
1091
|
}
|
|
@@ -1081,7 +1122,8 @@ var PlanChangePreviewService = class {
|
|
|
1081
1122
|
blockedPlans;
|
|
1082
1123
|
trialProjection;
|
|
1083
1124
|
subscriptionBundles;
|
|
1084
|
-
|
|
1125
|
+
contracts;
|
|
1126
|
+
constructor(catalogs, entitlements, subscriptions, usageSnapshot, blockedPlans = null, trialProjection = null, subscriptionBundles = null, contracts = null) {
|
|
1085
1127
|
this.catalogs = catalogs;
|
|
1086
1128
|
this.entitlements = entitlements;
|
|
1087
1129
|
this.subscriptions = subscriptions;
|
|
@@ -1089,6 +1131,7 @@ var PlanChangePreviewService = class {
|
|
|
1089
1131
|
this.blockedPlans = blockedPlans;
|
|
1090
1132
|
this.trialProjection = trialProjection;
|
|
1091
1133
|
this.subscriptionBundles = subscriptionBundles;
|
|
1134
|
+
this.contracts = contracts;
|
|
1092
1135
|
}
|
|
1093
1136
|
async preview(tenantId, targetPlan, targetCycle, now = /* @__PURE__ */ new Date()) {
|
|
1094
1137
|
const sub = await this.subscriptions.findForTenant(tenantId);
|
|
@@ -1173,7 +1216,7 @@ var PlanChangePreviewService = class {
|
|
|
1173
1216
|
const commits = ctx.status !== "TRIAL";
|
|
1174
1217
|
const isImmediate = planDirection === "UP" && (!commits || cycleDirection !== "SHORTER");
|
|
1175
1218
|
const effectiveAt = isImmediate ? null : this.resolveEffectiveAt(ctx, now);
|
|
1176
|
-
const proration = isImmediate && ctx.status !== "TRIAL" ? this.computeProration(ctx, now,
|
|
1219
|
+
const proration = isImmediate && ctx.status !== "TRIAL" ? this.computeProration(ctx, now, await this.planPricePaid(tenantId, sub.plan, sub.billingCycle, now) ?? priceForCycle(currentSnap, sub.billingCycle) ?? 0, priceForCycle(targetSnap, targetCycle) ?? 0, cycleDirection) : null;
|
|
1177
1220
|
const blockers = [];
|
|
1178
1221
|
const warnings = [];
|
|
1179
1222
|
const landsAt = ctx.canceledEffectiveAt ?? ctx.canceledAt;
|
|
@@ -1360,17 +1403,41 @@ var PlanChangePreviewService = class {
|
|
|
1360
1403
|
if (ctx.minimumTermUntil && ctx.minimumTermUntil > periodEnd) return ctx.minimumTermUntil;
|
|
1361
1404
|
return periodEnd;
|
|
1362
1405
|
}
|
|
1363
|
-
computeProration(ctx, now,
|
|
1406
|
+
computeProration(ctx, now, currentPriceNet, targetPriceNet, cycleDirection) {
|
|
1407
|
+
if (ctx.currentPeriodEnd === null) {
|
|
1408
|
+
return computeNewPeriodCharge({
|
|
1409
|
+
periodStart: now,
|
|
1410
|
+
periodEnd: now,
|
|
1411
|
+
now,
|
|
1412
|
+
currentPriceNet,
|
|
1413
|
+
targetPriceNet
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1364
1416
|
const periodStart = ctx.currentPeriodStart ?? ctx.startedAt ?? now;
|
|
1365
|
-
const
|
|
1366
|
-
return
|
|
1417
|
+
const charge = cycleDirection === "SAME" ? computeProration : computeNewPeriodCharge;
|
|
1418
|
+
return charge({
|
|
1367
1419
|
periodStart,
|
|
1368
|
-
periodEnd,
|
|
1420
|
+
periodEnd: ctx.currentPeriodEnd,
|
|
1369
1421
|
now,
|
|
1370
|
-
currentPriceNet
|
|
1371
|
-
targetPriceNet
|
|
1422
|
+
currentPriceNet,
|
|
1423
|
+
targetPriceNet
|
|
1372
1424
|
});
|
|
1373
1425
|
}
|
|
1426
|
+
/**
|
|
1427
|
+
* The net price of the plan line in the contract in force, when it is for
|
|
1428
|
+
* `plan` billed in `cycle` — what the customer pays for the period they are
|
|
1429
|
+
* in. Null without contracts, or where the line is for another plan or
|
|
1430
|
+
* rhythm: a freeze is optional and does not stop the change it follows when
|
|
1431
|
+
* it fails, so the contract in force can still describe the plan before.
|
|
1432
|
+
* The caller then prices from the catalogue.
|
|
1433
|
+
*/
|
|
1434
|
+
async planPricePaid(tenantId, plan, cycle, now) {
|
|
1435
|
+
const contract = await this.contracts?.findActiveByTenantId(tenantId, now);
|
|
1436
|
+
const planLine = contract?.lineItems.find((line) => line.kind === "plan");
|
|
1437
|
+
if (!planLine || planLine.sourceKey !== plan) return null;
|
|
1438
|
+
if (planLine.billingCycle !== cycle.toLowerCase()) return null;
|
|
1439
|
+
return planLine.priceNet;
|
|
1440
|
+
}
|
|
1374
1441
|
};
|
|
1375
1442
|
PlanChangePreviewService = _ts_decorate4([
|
|
1376
1443
|
Injectable2(),
|
|
@@ -1384,6 +1451,8 @@ PlanChangePreviewService = _ts_decorate4([
|
|
|
1384
1451
|
_ts_param2(5, Inject2(TRIAL_PROJECTION_PORT_TOKEN)),
|
|
1385
1452
|
_ts_param2(6, Optional2()),
|
|
1386
1453
|
_ts_param2(6, Inject2(SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN)),
|
|
1454
|
+
_ts_param2(7, Optional2()),
|
|
1455
|
+
_ts_param2(7, Inject2(SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN)),
|
|
1387
1456
|
_ts_metadata2("design:type", Function),
|
|
1388
1457
|
_ts_metadata2("design:paramtypes", [
|
|
1389
1458
|
typeof PlanCatalogSource === "undefined" ? Object : PlanCatalogSource,
|
|
@@ -1392,6 +1461,7 @@ PlanChangePreviewService = _ts_decorate4([
|
|
|
1392
1461
|
typeof UsageSnapshotPort === "undefined" ? Object : UsageSnapshotPort,
|
|
1393
1462
|
Object,
|
|
1394
1463
|
Object,
|
|
1464
|
+
Object,
|
|
1395
1465
|
Object
|
|
1396
1466
|
])
|
|
1397
1467
|
], PlanChangePreviewService);
|
|
@@ -1536,11 +1606,15 @@ var SubscriptionContractFreezeService = class {
|
|
|
1536
1606
|
entitlements;
|
|
1537
1607
|
contracts;
|
|
1538
1608
|
source;
|
|
1539
|
-
|
|
1609
|
+
subscriptions;
|
|
1610
|
+
promoCodes;
|
|
1611
|
+
constructor(catalogs, entitlements, contracts, source, writes = null, subscriptions = null, promoCodes = null) {
|
|
1540
1612
|
this.catalogs = catalogs;
|
|
1541
1613
|
this.entitlements = entitlements;
|
|
1542
1614
|
this.contracts = contracts;
|
|
1543
1615
|
this.source = source;
|
|
1616
|
+
this.subscriptions = subscriptions;
|
|
1617
|
+
this.promoCodes = promoCodes;
|
|
1544
1618
|
if (writes?.bindsPlanVersion === false) {
|
|
1545
1619
|
throw new Error("The contract freeze records the plan version a subscription is bound to, and this installation's subscription write does not bind it on a plan change. With @saasicat/adapter-prisma, leave `tenantSubscription.synchronizePlanVersion` at its default of true \u2014 or do not configure `contractFreeze`.");
|
|
1546
1620
|
}
|
|
@@ -1598,9 +1672,13 @@ var SubscriptionContractFreezeService = class {
|
|
|
1598
1672
|
quotaEffectsSnapshot: planDef.quotas,
|
|
1599
1673
|
metadata: null
|
|
1600
1674
|
};
|
|
1675
|
+
const redeemed = await this.redeemedCodeNotYetRecorded(tenantId, planPriceNet, billingCycle, vatRate);
|
|
1601
1676
|
const lineItems = recordContractLinesMoney([
|
|
1602
1677
|
planLineItem,
|
|
1603
|
-
...bundles.lineItems
|
|
1678
|
+
...bundles.lineItems,
|
|
1679
|
+
...redeemed ? [
|
|
1680
|
+
redeemed.line
|
|
1681
|
+
] : []
|
|
1604
1682
|
], {
|
|
1605
1683
|
currency: catalog.currency,
|
|
1606
1684
|
taxRate: vatRate
|
|
@@ -1627,7 +1705,7 @@ var SubscriptionContractFreezeService = class {
|
|
|
1627
1705
|
});
|
|
1628
1706
|
}
|
|
1629
1707
|
this.entitlements.invalidateTenant(tenantId);
|
|
1630
|
-
const limits = await this.entitlements.
|
|
1708
|
+
const { limits, leftOutBundleVersionIds } = await this.entitlements.computeContractLimits(tenantId, effectiveFrom, catalog);
|
|
1631
1709
|
const data = {
|
|
1632
1710
|
tenantId,
|
|
1633
1711
|
status: "active",
|
|
@@ -1646,14 +1724,81 @@ var SubscriptionContractFreezeService = class {
|
|
|
1646
1724
|
},
|
|
1647
1725
|
features: [
|
|
1648
1726
|
...limits.features
|
|
1649
|
-
]
|
|
1727
|
+
],
|
|
1728
|
+
...leftOutBundleVersionIds.length > 0 ? {
|
|
1729
|
+
leftOutBundleVersionIds
|
|
1730
|
+
} : {}
|
|
1650
1731
|
},
|
|
1651
1732
|
priceSnapshot,
|
|
1733
|
+
promoCodeSnapshots: redeemed ? [
|
|
1734
|
+
redeemed.snapshot
|
|
1735
|
+
] : [],
|
|
1652
1736
|
lineItems
|
|
1653
1737
|
};
|
|
1654
1738
|
await this.contracts.create(data);
|
|
1655
1739
|
this.entitlements.invalidateTenant(tenantId);
|
|
1656
1740
|
}
|
|
1741
|
+
/**
|
|
1742
|
+
* The code redeemed for the tenant's subscription, as a discount line, where
|
|
1743
|
+
* no contract of the tenant records it yet.
|
|
1744
|
+
*
|
|
1745
|
+
* The first contract written after a redemption records it — at onboarding,
|
|
1746
|
+
* or at the activation after a trial, where onboarding wrote none — and the
|
|
1747
|
+
* ones after it do not repeat it: the discount runs from where it was first
|
|
1748
|
+
* agreed, for the duration on its snapshot, counted from the first period
|
|
1749
|
+
* that is paid. A contract concluded from an offer that carried the code
|
|
1750
|
+
* already records it. Nothing is recorded without the promo module, for a
|
|
1751
|
+
* reversed redemption, or where a contract written since the redemption
|
|
1752
|
+
* does not record it: that was the first one, written before contracts
|
|
1753
|
+
* recorded codes or by the application itself, and a later contract does
|
|
1754
|
+
* not start the discount again.
|
|
1755
|
+
*/
|
|
1756
|
+
async redeemedCodeNotYetRecorded(tenantId, planPriceNet, billingCycle, vatRate) {
|
|
1757
|
+
if (!this.promoCodes || !this.subscriptions) return null;
|
|
1758
|
+
const subscription = await this.subscriptions.findForTenant(tenantId);
|
|
1759
|
+
if (!subscription?.id) return null;
|
|
1760
|
+
const redeemed = await this.promoCodes.redeemedCodeFor(subscription.id);
|
|
1761
|
+
if (!redeemed) return null;
|
|
1762
|
+
const recorded = await this.contracts.list({
|
|
1763
|
+
tenantId
|
|
1764
|
+
});
|
|
1765
|
+
if (recorded.some((contract) => recordsPromoCode(contract, redeemed.code) || contract.createdAt > redeemed.redeemedAt)) {
|
|
1766
|
+
return null;
|
|
1767
|
+
}
|
|
1768
|
+
const cycle = billingCycle === "YEARLY" ? "yearly" : "monthly";
|
|
1769
|
+
const snapshot = {
|
|
1770
|
+
code: redeemed.code,
|
|
1771
|
+
label: buildLabel(redeemed, billingCycle),
|
|
1772
|
+
valueType: redeemed.valueType,
|
|
1773
|
+
value: Number(redeemed.value),
|
|
1774
|
+
resolvedAmountNet: promoCodeDiscountNet(planPriceNet, vatRate, redeemed),
|
|
1775
|
+
durationType: redeemed.durationType,
|
|
1776
|
+
durationValue: redeemed.durationValue
|
|
1777
|
+
};
|
|
1778
|
+
const line = generatedDiscountLine({
|
|
1779
|
+
billingCycle: cycle,
|
|
1780
|
+
promoCodeSnapshot: snapshot,
|
|
1781
|
+
promotionSnapshots: []
|
|
1782
|
+
}, snapshot.resolvedAmountNet);
|
|
1783
|
+
return {
|
|
1784
|
+
snapshot,
|
|
1785
|
+
line: {
|
|
1786
|
+
kind: line.kind,
|
|
1787
|
+
sourceKey: line.sourceKey,
|
|
1788
|
+
sourceVersionId: line.sourceVersionId ?? null,
|
|
1789
|
+
titleSnapshot: line.titleSnapshot,
|
|
1790
|
+
descriptionSnapshot: line.descriptionSnapshot ?? null,
|
|
1791
|
+
quantity: line.quantity,
|
|
1792
|
+
unit: line.unit ?? null,
|
|
1793
|
+
priceNet: line.priceNet,
|
|
1794
|
+
billingCycle: cycle,
|
|
1795
|
+
minimumTermUntil: null,
|
|
1796
|
+
featuresSnapshot: [],
|
|
1797
|
+
quotaEffectsSnapshot: {},
|
|
1798
|
+
metadata: line.metadata ?? null
|
|
1799
|
+
}
|
|
1800
|
+
};
|
|
1801
|
+
}
|
|
1657
1802
|
};
|
|
1658
1803
|
SubscriptionContractFreezeService = _ts_decorate6([
|
|
1659
1804
|
Injectable4(),
|
|
@@ -1663,18 +1808,76 @@ SubscriptionContractFreezeService = _ts_decorate6([
|
|
|
1663
1808
|
_ts_param4(3, Inject4(CONTRACT_FREEZE_SOURCE_PORT_TOKEN)),
|
|
1664
1809
|
_ts_param4(4, Optional4()),
|
|
1665
1810
|
_ts_param4(4, Inject4(SUBSCRIPTION_WRITE_PORT_TOKEN)),
|
|
1811
|
+
_ts_param4(5, Optional4()),
|
|
1812
|
+
_ts_param4(5, Inject4(SUBSCRIPTION_USAGE_PORT_TOKEN)),
|
|
1813
|
+
_ts_param4(6, Optional4()),
|
|
1814
|
+
_ts_param4(6, Inject4(PromoCodesService)),
|
|
1666
1815
|
_ts_metadata4("design:type", Function),
|
|
1667
1816
|
_ts_metadata4("design:paramtypes", [
|
|
1668
1817
|
typeof PlanCatalogSource === "undefined" ? Object : PlanCatalogSource,
|
|
1669
1818
|
typeof EntitlementService === "undefined" ? Object : EntitlementService,
|
|
1670
1819
|
typeof SubscriptionContractService === "undefined" ? Object : SubscriptionContractService,
|
|
1671
1820
|
typeof ContractFreezeSourcePort === "undefined" ? Object : ContractFreezeSourcePort,
|
|
1821
|
+
Object,
|
|
1822
|
+
Object,
|
|
1672
1823
|
Object
|
|
1673
1824
|
])
|
|
1674
1825
|
], SubscriptionContractFreezeService);
|
|
1826
|
+
function recordsPromoCode(contract, code) {
|
|
1827
|
+
return contract.promoCodeSnapshots.some((snapshot) => snapshot !== null && typeof snapshot === "object" && snapshot.code === code);
|
|
1828
|
+
}
|
|
1829
|
+
__name(recordsPromoCode, "recordsPromoCode");
|
|
1675
1830
|
|
|
1676
|
-
// src/billing/
|
|
1677
|
-
|
|
1831
|
+
// src/billing/charges/subscriber-charge.tokens.ts
|
|
1832
|
+
var SUBSCRIBER_LEDGER_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SubscriberLedgerRepository");
|
|
1833
|
+
|
|
1834
|
+
// src/billing/charges/subscriber-account.service.ts
|
|
1835
|
+
import { Inject as Inject5, Injectable as Injectable5 } from "@nestjs/common";
|
|
1836
|
+
|
|
1837
|
+
// src/billing/charges/subscriber-account.ts
|
|
1838
|
+
var SOURCE_ORDER = {
|
|
1839
|
+
plan: 0,
|
|
1840
|
+
bundle: 1,
|
|
1841
|
+
discount: 2
|
|
1842
|
+
};
|
|
1843
|
+
function toWire(charge) {
|
|
1844
|
+
return {
|
|
1845
|
+
...charge,
|
|
1846
|
+
periodStart: charge.periodStart.toISOString(),
|
|
1847
|
+
periodEnd: charge.periodEnd.toISOString(),
|
|
1848
|
+
bookedAt: charge.bookedAt.toISOString(),
|
|
1849
|
+
createdAt: charge.createdAt.toISOString()
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
__name(toWire, "toWire");
|
|
1853
|
+
function newestFirst(a, b) {
|
|
1854
|
+
return b.bookedAt.getTime() - a.bookedAt.getTime() || b.periodStart.getTime() - a.periodStart.getTime() || SOURCE_ORDER[a.source] - SOURCE_ORDER[b.source] || a.id.localeCompare(b.id);
|
|
1855
|
+
}
|
|
1856
|
+
__name(newestFirst, "newestFirst");
|
|
1857
|
+
function accountViewOf(input) {
|
|
1858
|
+
const titles = /* @__PURE__ */ new Map();
|
|
1859
|
+
for (const contract of input.contracts) {
|
|
1860
|
+
for (const line of contract.lineItems) titles.set(line.id, line.titleSnapshot);
|
|
1861
|
+
}
|
|
1862
|
+
const entries = [
|
|
1863
|
+
...input.charges
|
|
1864
|
+
].sort(newestFirst).map((charge) => ({
|
|
1865
|
+
charge: toWire(charge),
|
|
1866
|
+
title: titles.get(charge.contractLineItemId) ?? null
|
|
1867
|
+
}));
|
|
1868
|
+
const subscriber = input.subscriber;
|
|
1869
|
+
return {
|
|
1870
|
+
holder: subscriber ? {
|
|
1871
|
+
id: subscriber.id,
|
|
1872
|
+
customerNumber: subscriber.customerNumber,
|
|
1873
|
+
legalName: subscriber.legalName
|
|
1874
|
+
} : null,
|
|
1875
|
+
entries
|
|
1876
|
+
};
|
|
1877
|
+
}
|
|
1878
|
+
__name(accountViewOf, "accountViewOf");
|
|
1879
|
+
|
|
1880
|
+
// src/billing/charges/subscriber-account.service.ts
|
|
1678
1881
|
function _ts_decorate7(decorators, target, key, desc) {
|
|
1679
1882
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1680
1883
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1686,6 +1889,863 @@ function _ts_metadata5(k, v) {
|
|
|
1686
1889
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1687
1890
|
}
|
|
1688
1891
|
__name(_ts_metadata5, "_ts_metadata");
|
|
1892
|
+
function _ts_param5(paramIndex, decorator) {
|
|
1893
|
+
return function(target, key) {
|
|
1894
|
+
decorator(target, key, paramIndex);
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
__name(_ts_param5, "_ts_param");
|
|
1898
|
+
var SubscriberAccountService = class {
|
|
1899
|
+
static {
|
|
1900
|
+
__name(this, "SubscriberAccountService");
|
|
1901
|
+
}
|
|
1902
|
+
ledger;
|
|
1903
|
+
contracts;
|
|
1904
|
+
subscribers;
|
|
1905
|
+
subscriptions;
|
|
1906
|
+
constructor(ledger, contracts, subscribers, subscriptions) {
|
|
1907
|
+
this.ledger = ledger;
|
|
1908
|
+
this.contracts = contracts;
|
|
1909
|
+
this.subscribers = subscribers;
|
|
1910
|
+
this.subscriptions = subscriptions;
|
|
1911
|
+
}
|
|
1912
|
+
/** The account of the tenant's subscriber; empty while it has no subscription. */
|
|
1913
|
+
async accountOf(tenantId) {
|
|
1914
|
+
const [subscription, subscriber, contracts] = await Promise.all([
|
|
1915
|
+
this.subscriptions.findForTenant(tenantId),
|
|
1916
|
+
this.subscribers.findByTenantId(tenantId),
|
|
1917
|
+
this.contracts.list({
|
|
1918
|
+
tenantId
|
|
1919
|
+
})
|
|
1920
|
+
]);
|
|
1921
|
+
const charges = subscription?.id ? await this.ledger.listBySubscription(subscription.id) : [];
|
|
1922
|
+
return accountViewOf({
|
|
1923
|
+
subscriber,
|
|
1924
|
+
charges,
|
|
1925
|
+
contracts
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
};
|
|
1929
|
+
SubscriberAccountService = _ts_decorate7([
|
|
1930
|
+
Injectable5(),
|
|
1931
|
+
_ts_param5(0, Inject5(SUBSCRIBER_LEDGER_REPOSITORY_TOKEN)),
|
|
1932
|
+
_ts_param5(1, Inject5(SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN)),
|
|
1933
|
+
_ts_param5(2, Inject5(SUBSCRIBER_REPOSITORY_TOKEN)),
|
|
1934
|
+
_ts_param5(3, Inject5(SUBSCRIPTION_USAGE_PORT_TOKEN)),
|
|
1935
|
+
_ts_metadata5("design:type", Function),
|
|
1936
|
+
_ts_metadata5("design:paramtypes", [
|
|
1937
|
+
typeof SubscriberLedgerRepository === "undefined" ? Object : SubscriberLedgerRepository,
|
|
1938
|
+
typeof SubscriptionContractRepository === "undefined" ? Object : SubscriptionContractRepository,
|
|
1939
|
+
typeof SubscriberRepository === "undefined" ? Object : SubscriberRepository,
|
|
1940
|
+
typeof SubscriptionUsagePort === "undefined" ? Object : SubscriptionUsagePort
|
|
1941
|
+
])
|
|
1942
|
+
], SubscriberAccountService);
|
|
1943
|
+
|
|
1944
|
+
// src/billing/charges/subscriber-account.module.ts
|
|
1945
|
+
import { Controller as Controller2, Get as Get2, Inject as Inject6, Module as Module2, Param, UseGuards } from "@nestjs/common";
|
|
1946
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
1947
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1948
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1949
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1950
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1951
|
+
}
|
|
1952
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
1953
|
+
function _ts_metadata6(k, v) {
|
|
1954
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1955
|
+
}
|
|
1956
|
+
__name(_ts_metadata6, "_ts_metadata");
|
|
1957
|
+
function _ts_param6(paramIndex, decorator) {
|
|
1958
|
+
return function(target, key) {
|
|
1959
|
+
decorator(target, key, paramIndex);
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
__name(_ts_param6, "_ts_param");
|
|
1963
|
+
function buildSubscriberAccountController(guards) {
|
|
1964
|
+
let GeneratedSubscriberAccountController = class GeneratedSubscriberAccountController {
|
|
1965
|
+
static {
|
|
1966
|
+
__name(this, "GeneratedSubscriberAccountController");
|
|
1967
|
+
}
|
|
1968
|
+
tenants;
|
|
1969
|
+
accounts;
|
|
1970
|
+
rlsBypass;
|
|
1971
|
+
constructor(tenants, accounts, rlsBypass) {
|
|
1972
|
+
this.tenants = tenants;
|
|
1973
|
+
this.accounts = accounts;
|
|
1974
|
+
this.rlsBypass = rlsBypass;
|
|
1975
|
+
}
|
|
1976
|
+
/**
|
|
1977
|
+
* The charges of the tenant's subscriber. An operator's request is
|
|
1978
|
+
* scoped to no tenant, so finding the tenant and reading its account
|
|
1979
|
+
* both run outside any row-level policy the application keeps its
|
|
1980
|
+
* tenants apart with.
|
|
1981
|
+
*/
|
|
1982
|
+
chargesOf(slug) {
|
|
1983
|
+
const read = /* @__PURE__ */ __name(async () => {
|
|
1984
|
+
const tenant = await this.tenants.getTenantDetail(slug);
|
|
1985
|
+
return this.accounts.accountOf(tenant.id);
|
|
1986
|
+
}, "read");
|
|
1987
|
+
return this.rlsBypass.runWithBypass(read);
|
|
1988
|
+
}
|
|
1989
|
+
};
|
|
1990
|
+
_ts_decorate8([
|
|
1991
|
+
Get2("tenants/:slug/charges"),
|
|
1992
|
+
_ts_param6(0, Param("slug")),
|
|
1993
|
+
_ts_metadata6("design:type", Function),
|
|
1994
|
+
_ts_metadata6("design:paramtypes", [
|
|
1995
|
+
String
|
|
1996
|
+
]),
|
|
1997
|
+
_ts_metadata6("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
1998
|
+
], GeneratedSubscriberAccountController.prototype, "chargesOf", null);
|
|
1999
|
+
GeneratedSubscriberAccountController = _ts_decorate8([
|
|
2000
|
+
Controller2("admin"),
|
|
2001
|
+
UseGuards(...guards),
|
|
2002
|
+
_ts_param6(0, Inject6(AdminResourcesService)),
|
|
2003
|
+
_ts_param6(1, Inject6(SubscriberAccountService)),
|
|
2004
|
+
_ts_param6(2, Inject6(RLS_BYPASS_PORT_TOKEN)),
|
|
2005
|
+
_ts_metadata6("design:type", Function),
|
|
2006
|
+
_ts_metadata6("design:paramtypes", [
|
|
2007
|
+
typeof AdminResourcesService === "undefined" ? Object : AdminResourcesService,
|
|
2008
|
+
typeof SubscriberAccountService === "undefined" ? Object : SubscriberAccountService,
|
|
2009
|
+
typeof RlsBypassPort === "undefined" ? Object : RlsBypassPort
|
|
2010
|
+
])
|
|
2011
|
+
], GeneratedSubscriberAccountController);
|
|
2012
|
+
return GeneratedSubscriberAccountController;
|
|
2013
|
+
}
|
|
2014
|
+
__name(buildSubscriberAccountController, "buildSubscriberAccountController");
|
|
2015
|
+
var SubscriberAccountModule = class _SubscriberAccountModule {
|
|
2016
|
+
static {
|
|
2017
|
+
__name(this, "SubscriberAccountModule");
|
|
2018
|
+
}
|
|
2019
|
+
static forRoot(options) {
|
|
2020
|
+
return {
|
|
2021
|
+
module: _SubscriberAccountModule,
|
|
2022
|
+
imports: options.imports,
|
|
2023
|
+
controllers: [
|
|
2024
|
+
buildSubscriberAccountController(options.guards)
|
|
2025
|
+
]
|
|
2026
|
+
};
|
|
2027
|
+
}
|
|
2028
|
+
};
|
|
2029
|
+
SubscriberAccountModule = _ts_decorate8([
|
|
2030
|
+
Module2({})
|
|
2031
|
+
], SubscriberAccountModule);
|
|
2032
|
+
|
|
2033
|
+
// src/billing/charges/subscriber-charge.service.ts
|
|
2034
|
+
import { Inject as Inject7, Injectable as Injectable6, Logger as Logger2, Optional as Optional5 } from "@nestjs/common";
|
|
2035
|
+
|
|
2036
|
+
// src/billing/charges/charge-derivation.ts
|
|
2037
|
+
var PERIOD_ORIGINS = [
|
|
2038
|
+
"activation",
|
|
2039
|
+
"renewal",
|
|
2040
|
+
"bundleBooking",
|
|
2041
|
+
"planChange"
|
|
2042
|
+
];
|
|
2043
|
+
var MAX_CYCLES = 600;
|
|
2044
|
+
var CENTS = 100;
|
|
2045
|
+
function deriveDueCharges(input) {
|
|
2046
|
+
const planCharges = derivePlanCharges(input);
|
|
2047
|
+
const periods = [
|
|
2048
|
+
...writtenPlanPeriods(input),
|
|
2049
|
+
...planCharges.map(({ period }) => period)
|
|
2050
|
+
];
|
|
2051
|
+
return [
|
|
2052
|
+
...planCharges.map(({ charge }) => charge),
|
|
2053
|
+
...deriveUpgradeDifferences(input, periods),
|
|
2054
|
+
...deriveDiscountCharges(input, planCharges, periods),
|
|
2055
|
+
...deriveBundleCharges(input, accountStart(input))
|
|
2056
|
+
];
|
|
2057
|
+
}
|
|
2058
|
+
__name(deriveDueCharges, "deriveDueCharges");
|
|
2059
|
+
function bookingsTheContractMisses(contracts, bookings, now) {
|
|
2060
|
+
const inForce = contractInForce(contracts, now);
|
|
2061
|
+
if (!inForce) return [];
|
|
2062
|
+
return bookings.filter((booking) => inForce.effectiveFrom < booking.startedAt && booking.currentPeriodEnd !== null && (booking.canceledEffectiveAt === null || booking.canceledEffectiveAt > now) && !inForce.lineItems.some((item) => item.kind === "bundle" && item.sourceVersionId === booking.bundleVersionId));
|
|
2063
|
+
}
|
|
2064
|
+
__name(bookingsTheContractMisses, "bookingsTheContractMisses");
|
|
2065
|
+
function derivePlanCharges(input) {
|
|
2066
|
+
const { subscription } = input;
|
|
2067
|
+
if (subscription.status === "TRIAL") return [];
|
|
2068
|
+
const window = windowOf(subscription.currentPeriodStart, subscription.currentPeriodEnd);
|
|
2069
|
+
if (!window) return [];
|
|
2070
|
+
const rhythm = rhythmOf(subscription.billingCycle);
|
|
2071
|
+
const isPlanLine = /* @__PURE__ */ __name((item) => item.kind === "plan" && item.billingCycle === rhythm, "isPlanLine");
|
|
2072
|
+
const replaced = periodReplacedBy(window, input);
|
|
2073
|
+
if (replaced) return newPeriodAfterChange(input, window, replaced, isPlanLine);
|
|
2074
|
+
const priced = periodsToCharge({
|
|
2075
|
+
window,
|
|
2076
|
+
from: lastPeriodEnd(input.written, "plan", subscription.id) ?? window.start,
|
|
2077
|
+
cycle: subscription.billingCycle,
|
|
2078
|
+
anchorDay: subscription.anchorDay,
|
|
2079
|
+
input,
|
|
2080
|
+
endsAt: subscription.endsAt
|
|
2081
|
+
}).flatMap((period) => {
|
|
2082
|
+
const found = lineFor(input.contracts, period, isPlanLine);
|
|
2083
|
+
return found ? [
|
|
2084
|
+
{
|
|
2085
|
+
period,
|
|
2086
|
+
...found
|
|
2087
|
+
}
|
|
2088
|
+
] : [];
|
|
2089
|
+
});
|
|
2090
|
+
const firstContract = earliest2(input.contracts);
|
|
2091
|
+
const opensSubscription = /* @__PURE__ */ __name((period) => holds(period, subscription.startedAt) || holds(period, firstContract?.effectiveFrom ?? null), "opensSubscription");
|
|
2092
|
+
return priced.map(({ period, contract, line }) => {
|
|
2093
|
+
const charge = chargeOf(input, contract, line, {
|
|
2094
|
+
origin: opensSubscription(period) ? "activation" : "renewal",
|
|
2095
|
+
source: "plan",
|
|
2096
|
+
sourceRef: subscription.id,
|
|
2097
|
+
period,
|
|
2098
|
+
amountNet: line.priceNet,
|
|
2099
|
+
bookedAt: period.start
|
|
2100
|
+
});
|
|
2101
|
+
return {
|
|
2102
|
+
charge,
|
|
2103
|
+
period: {
|
|
2104
|
+
charge,
|
|
2105
|
+
rhythm
|
|
2106
|
+
}
|
|
2107
|
+
};
|
|
2108
|
+
});
|
|
2109
|
+
}
|
|
2110
|
+
__name(derivePlanCharges, "derivePlanCharges");
|
|
2111
|
+
function periodReplacedBy(window, input) {
|
|
2112
|
+
const whole = input.written.filter((charge) => isWholePlanPeriod(charge, input.written, input.subscription.id));
|
|
2113
|
+
return whole.filter((charge) => charge.periodStart < window.start && window.start < charge.periodEnd).sort((a, b) => a.periodStart.getTime() - b.periodStart.getTime())[0] ?? null;
|
|
2114
|
+
}
|
|
2115
|
+
__name(periodReplacedBy, "periodReplacedBy");
|
|
2116
|
+
function newPeriodAfterChange(input, window, replaced, isPlanLine) {
|
|
2117
|
+
const { subscription } = input;
|
|
2118
|
+
if (!isChargeable(window, input, subscription.endsAt)) return [];
|
|
2119
|
+
const found = lineFor(input.contracts, window, isPlanLine);
|
|
2120
|
+
if (!found) return [];
|
|
2121
|
+
const charge = chargeOf(input, found.contract, found.line, {
|
|
2122
|
+
origin: "planChange",
|
|
2123
|
+
source: "plan",
|
|
2124
|
+
sourceRef: subscription.id,
|
|
2125
|
+
period: window,
|
|
2126
|
+
amountNet: computeNewPeriodCharge({
|
|
2127
|
+
periodStart: replaced.periodStart,
|
|
2128
|
+
periodEnd: replaced.periodEnd,
|
|
2129
|
+
now: window.start,
|
|
2130
|
+
currentPriceNet: pricePaidBefore(window.start, replaced, input.contracts),
|
|
2131
|
+
targetPriceNet: found.line.priceNet
|
|
2132
|
+
}).prorataDeltaNet,
|
|
2133
|
+
bookedAt: window.start
|
|
2134
|
+
});
|
|
2135
|
+
return [
|
|
2136
|
+
{
|
|
2137
|
+
charge,
|
|
2138
|
+
period: {
|
|
2139
|
+
charge,
|
|
2140
|
+
rhythm: rhythmOf(subscription.billingCycle)
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
];
|
|
2144
|
+
}
|
|
2145
|
+
__name(newPeriodAfterChange, "newPeriodAfterChange");
|
|
2146
|
+
function pricePaidBefore(at, replaced, contracts) {
|
|
2147
|
+
const chargedUnder = lineById(contracts, replaced.contractLineItemId);
|
|
2148
|
+
const rhythm = chargedUnder?.billingCycle;
|
|
2149
|
+
const before = contractInForce(contracts, new Date(at.getTime() - 1));
|
|
2150
|
+
const line = before?.lineItems.find((item) => item.kind === "plan" && item.billingCycle === rhythm);
|
|
2151
|
+
return line?.priceNet ?? chargedUnder?.priceNet ?? replaced.amountNet;
|
|
2152
|
+
}
|
|
2153
|
+
__name(pricePaidBefore, "pricePaidBefore");
|
|
2154
|
+
function deriveUpgradeDifferences(input, periods) {
|
|
2155
|
+
const { subscription } = input;
|
|
2156
|
+
const charges = [];
|
|
2157
|
+
for (const { charge: period, rhythm } of periods) {
|
|
2158
|
+
const isPlanLine = /* @__PURE__ */ __name((item) => item.kind === "plan" && item.billingCycle === rhythm, "isPlanLine");
|
|
2159
|
+
for (const contract of input.contracts) {
|
|
2160
|
+
const at = contract.effectiveFrom;
|
|
2161
|
+
if (contract.status === "scheduled") continue;
|
|
2162
|
+
if (!(period.periodStart < at && at < period.periodEnd)) continue;
|
|
2163
|
+
if (!isChargeable({
|
|
2164
|
+
start: at,
|
|
2165
|
+
end: period.periodEnd
|
|
2166
|
+
}, input, subscription.endsAt)) {
|
|
2167
|
+
continue;
|
|
2168
|
+
}
|
|
2169
|
+
const line = contract.lineItems.find(isPlanLine);
|
|
2170
|
+
const before = contractInForce(input.contracts, new Date(at.getTime() - 1));
|
|
2171
|
+
const lineBefore = before?.lineItems.find(isPlanLine);
|
|
2172
|
+
if (!line || !lineBefore) continue;
|
|
2173
|
+
const difference = computeProration({
|
|
2174
|
+
periodStart: period.periodStart,
|
|
2175
|
+
periodEnd: period.periodEnd,
|
|
2176
|
+
now: at,
|
|
2177
|
+
currentPriceNet: lineBefore.priceNet,
|
|
2178
|
+
targetPriceNet: line.priceNet
|
|
2179
|
+
}).prorataDeltaNet;
|
|
2180
|
+
if (difference <= 0) continue;
|
|
2181
|
+
charges.push(chargeOf(input, contract, line, {
|
|
2182
|
+
origin: "planChange",
|
|
2183
|
+
source: "plan",
|
|
2184
|
+
sourceRef: subscription.id,
|
|
2185
|
+
period: {
|
|
2186
|
+
start: at,
|
|
2187
|
+
end: period.periodEnd
|
|
2188
|
+
},
|
|
2189
|
+
amountNet: difference,
|
|
2190
|
+
bookedAt: at
|
|
2191
|
+
}));
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
return charges;
|
|
2195
|
+
}
|
|
2196
|
+
__name(deriveUpgradeDifferences, "deriveUpgradeDifferences");
|
|
2197
|
+
function writtenPlanPeriods(input) {
|
|
2198
|
+
return input.written.flatMap((charge) => {
|
|
2199
|
+
if (!isWholePlanPeriod(charge, input.written, input.subscription.id)) return [];
|
|
2200
|
+
const line = lineById(input.contracts, charge.contractLineItemId);
|
|
2201
|
+
return line ? [
|
|
2202
|
+
{
|
|
2203
|
+
charge,
|
|
2204
|
+
rhythm: line.billingCycle
|
|
2205
|
+
}
|
|
2206
|
+
] : [];
|
|
2207
|
+
});
|
|
2208
|
+
}
|
|
2209
|
+
__name(writtenPlanPeriods, "writtenPlanPeriods");
|
|
2210
|
+
function isWholePlanPeriod(charge, written, subscriptionId) {
|
|
2211
|
+
if (charge.source !== "plan" || charge.sourceRef !== subscriptionId) return false;
|
|
2212
|
+
if (!PERIOD_ORIGINS.includes(charge.origin)) return false;
|
|
2213
|
+
return charge.origin !== "planChange" || !isDifference(charge, written);
|
|
2214
|
+
}
|
|
2215
|
+
__name(isWholePlanPeriod, "isWholePlanPeriod");
|
|
2216
|
+
function isDifference(charge, written) {
|
|
2217
|
+
return written.some((other) => other.source === "plan" && other.sourceRef === charge.sourceRef && other.periodStart < charge.periodStart && sameInstant(other.periodEnd, charge.periodEnd));
|
|
2218
|
+
}
|
|
2219
|
+
__name(isDifference, "isDifference");
|
|
2220
|
+
function accountStart(input) {
|
|
2221
|
+
const { subscription } = input;
|
|
2222
|
+
const firstCharged = firstPlanPeriodStart(input.written, subscription.id);
|
|
2223
|
+
if (firstCharged) return firstCharged;
|
|
2224
|
+
if (subscription.status === "TRIAL") return null;
|
|
2225
|
+
return windowOf(subscription.currentPeriodStart, subscription.currentPeriodEnd)?.start ?? null;
|
|
2226
|
+
}
|
|
2227
|
+
__name(accountStart, "accountStart");
|
|
2228
|
+
function deriveBundleCharges(input, accountBegins) {
|
|
2229
|
+
if (!accountBegins) return [];
|
|
2230
|
+
const { subscription } = input;
|
|
2231
|
+
const anchorDay = subscription.anchorDay;
|
|
2232
|
+
const charges = [];
|
|
2233
|
+
for (const booking of input.bookings) {
|
|
2234
|
+
const window = windowOf(booking.currentPeriodStart, booking.currentPeriodEnd);
|
|
2235
|
+
if (!window) continue;
|
|
2236
|
+
const cycle = booking.billingCycle ?? subscription.billingCycle;
|
|
2237
|
+
const endsAt = earlierOf(booking.canceledEffectiveAt, subscription.endsAt);
|
|
2238
|
+
const lastEnd = lastPeriodEnd(input.written, "bundle", booking.id);
|
|
2239
|
+
const chainStart = laterOf(booking.startedAt, accountBegins);
|
|
2240
|
+
const periods = lastEnd ? periodsToCharge({
|
|
2241
|
+
window,
|
|
2242
|
+
from: lastEnd,
|
|
2243
|
+
cycle,
|
|
2244
|
+
anchorDay,
|
|
2245
|
+
input,
|
|
2246
|
+
endsAt
|
|
2247
|
+
}) : [
|
|
2248
|
+
...firstBundlePeriod(window, chainStart, cycle, anchorDay),
|
|
2249
|
+
...periodsToCharge({
|
|
2250
|
+
window,
|
|
2251
|
+
from: firstBoundaryAfter(window, chainStart, cycle, anchorDay),
|
|
2252
|
+
cycle,
|
|
2253
|
+
anchorDay,
|
|
2254
|
+
input,
|
|
2255
|
+
endsAt
|
|
2256
|
+
})
|
|
2257
|
+
].filter((period) => isChargeable(period, input, endsAt));
|
|
2258
|
+
for (const period of periods) {
|
|
2259
|
+
const priced = lineFor(input.contracts, period, (item) => item.kind === "bundle" && item.sourceVersionId === booking.bundleVersionId);
|
|
2260
|
+
if (!priced) continue;
|
|
2261
|
+
const { contract, line } = priced;
|
|
2262
|
+
charges.push(chargeOf(input, contract, line, {
|
|
2263
|
+
origin: !lastEnd && sameInstant(period.start, chainStart) ? "bundleBooking" : "renewal",
|
|
2264
|
+
source: "bundle",
|
|
2265
|
+
sourceRef: booking.id,
|
|
2266
|
+
period,
|
|
2267
|
+
// Every period is charged for its share of the whole cycle
|
|
2268
|
+
// it ends, which is all of it except for the short first
|
|
2269
|
+
// one — the same arithmetic the preview quoted
|
|
2270
|
+
// (`SC-BUN-003`, `SC-PRIC-002`).
|
|
2271
|
+
amountNet: computeProration({
|
|
2272
|
+
periodStart: bundleFirstPeriodStart(period.end, cycle, anchorDay),
|
|
2273
|
+
periodEnd: period.end,
|
|
2274
|
+
now: period.start,
|
|
2275
|
+
currentPriceNet: 0,
|
|
2276
|
+
targetPriceNet: line.priceNet
|
|
2277
|
+
}).prorataDeltaNet,
|
|
2278
|
+
bookedAt: period.start
|
|
2279
|
+
}));
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
return charges;
|
|
2283
|
+
}
|
|
2284
|
+
__name(deriveBundleCharges, "deriveBundleCharges");
|
|
2285
|
+
function deriveDiscountCharges(input, due, periods) {
|
|
2286
|
+
const { subscription } = input;
|
|
2287
|
+
const charges = [];
|
|
2288
|
+
for (const { contract, line } of discountsWhereAgreed(input.contracts)) {
|
|
2289
|
+
const rhythm = line.billingCycle;
|
|
2290
|
+
const cycle = rhythm === "yearly" ? "YEARLY" : "MONTHLY";
|
|
2291
|
+
const first = firstPeriodConcludedFor(contract, periods);
|
|
2292
|
+
if (!first) continue;
|
|
2293
|
+
const anchorDay = rhythm === rhythmOf(subscription.billingCycle) ? subscription.anchorDay : first.getUTCDate();
|
|
2294
|
+
const beganInItsRhythm = periods.some((period) => period.rhythm === rhythm && sameInstant(period.charge.periodStart, first));
|
|
2295
|
+
const endedAt = beganInItsRhythm ? firstPeriodStart(periods.filter((period) => period.rhythm !== rhythm && period.charge.periodStart > first)) : first;
|
|
2296
|
+
for (const { charge: planCharge, period } of due) {
|
|
2297
|
+
const amount = endedAt && planCharge.periodStart > endedAt ? 0 : period.rhythm === rhythm ? discountInPeriod(line, first, planCharge.periodStart, cycle, anchorDay) : sameInstant(planCharge.periodStart, endedAt) ? (
|
|
2298
|
+
// period, and no more than it costs.
|
|
2299
|
+
Math.min(discountLeftAt(line, first, planCharge.periodStart, cycle, anchorDay), planCharge.amountNet)
|
|
2300
|
+
) : 0;
|
|
2301
|
+
if (amount <= 0) continue;
|
|
2302
|
+
charges.push(chargeOf(input, contract, line, {
|
|
2303
|
+
origin: planCharge.origin,
|
|
2304
|
+
source: "discount",
|
|
2305
|
+
sourceRef: line.sourceKey,
|
|
2306
|
+
period: {
|
|
2307
|
+
start: planCharge.periodStart,
|
|
2308
|
+
end: planCharge.periodEnd
|
|
2309
|
+
},
|
|
2310
|
+
amountNet: -amount,
|
|
2311
|
+
bookedAt: planCharge.bookedAt
|
|
2312
|
+
}));
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
return charges;
|
|
2316
|
+
}
|
|
2317
|
+
__name(deriveDiscountCharges, "deriveDiscountCharges");
|
|
2318
|
+
function discountInPeriod(line, first, periodStart, cycle, anchorDay) {
|
|
2319
|
+
const index = cyclesBetween(first, periodStart, cycle, anchorDay);
|
|
2320
|
+
return index === null ? 0 : discountFor(line, index, first, periodStart, anchorDay);
|
|
2321
|
+
}
|
|
2322
|
+
__name(discountInPeriod, "discountInPeriod");
|
|
2323
|
+
function discountLeftAt(line, first, at, cycle, anchorDay) {
|
|
2324
|
+
let cents = 0;
|
|
2325
|
+
let periodStart = first;
|
|
2326
|
+
for (let index = 0; index < MAX_CYCLES; index++) {
|
|
2327
|
+
const amount = discountFor(line, index, first, periodStart, anchorDay);
|
|
2328
|
+
if (amount === 0) break;
|
|
2329
|
+
if (periodStart >= at) cents += toCents(amount);
|
|
2330
|
+
periodStart = advanceOneCycle(periodStart, cycle, anchorDay ?? void 0);
|
|
2331
|
+
}
|
|
2332
|
+
return cents / CENTS;
|
|
2333
|
+
}
|
|
2334
|
+
__name(discountLeftAt, "discountLeftAt");
|
|
2335
|
+
function discountsWhereAgreed(contracts) {
|
|
2336
|
+
const agreed = /* @__PURE__ */ new Map();
|
|
2337
|
+
for (const contract of [
|
|
2338
|
+
...contracts
|
|
2339
|
+
].sort(byEffectiveFrom)) {
|
|
2340
|
+
for (const line of contract.lineItems) {
|
|
2341
|
+
if (line.kind !== "discount" || agreed.has(line.sourceKey)) continue;
|
|
2342
|
+
agreed.set(line.sourceKey, {
|
|
2343
|
+
contract,
|
|
2344
|
+
line
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
return [
|
|
2349
|
+
...agreed.values()
|
|
2350
|
+
];
|
|
2351
|
+
}
|
|
2352
|
+
__name(discountsWhereAgreed, "discountsWhereAgreed");
|
|
2353
|
+
function discountFor(line, index, first, periodStart, anchorDay) {
|
|
2354
|
+
const snapshots = discountSnapshotsOf(line);
|
|
2355
|
+
if (!snapshots) {
|
|
2356
|
+
return index === 0 ? -line.priceNet : 0;
|
|
2357
|
+
}
|
|
2358
|
+
const withinMonths = /* @__PURE__ */ __name((months) => periodStart < monthsAfter(first, months, anchorDay), "withinMonths");
|
|
2359
|
+
let cents = 0;
|
|
2360
|
+
for (const promotion of snapshots.promotions) {
|
|
2361
|
+
const months = promotionMonths(promotion.value);
|
|
2362
|
+
const applies = promotion.type === "intro" || promotion.type === "freeMonths" ? months !== null && withinMonths(months) : index === 0;
|
|
2363
|
+
if (applies) cents += toCents(promotion.resolvedAmountNet);
|
|
2364
|
+
}
|
|
2365
|
+
const code = snapshots.promoCode;
|
|
2366
|
+
if (code) {
|
|
2367
|
+
const applies = code.durationType === "MONTHS" ? withinMonths(code.durationValue ?? 0) : code.durationType === "BILLING_CYCLES" ? index < (code.durationValue ?? 0) : index === 0;
|
|
2368
|
+
if (applies) cents += toCents(code.resolvedAmountNet);
|
|
2369
|
+
}
|
|
2370
|
+
return cents / CENTS;
|
|
2371
|
+
}
|
|
2372
|
+
__name(discountFor, "discountFor");
|
|
2373
|
+
function discountSnapshotsOf(line) {
|
|
2374
|
+
const metadata = line.metadata;
|
|
2375
|
+
if (!isRecord(metadata) || metadata.generated !== true) return null;
|
|
2376
|
+
const promotions = Array.isArray(metadata.promotionSnapshots) ? metadata.promotionSnapshots.filter(isRecord).map((snapshot) => ({
|
|
2377
|
+
type: typeof snapshot.type === "string" ? snapshot.type : "",
|
|
2378
|
+
value: snapshot.value,
|
|
2379
|
+
resolvedAmountNet: numberOr0(snapshot.resolvedAmountNet)
|
|
2380
|
+
})) : [];
|
|
2381
|
+
const code = isRecord(metadata.promoCodeSnapshot) ? metadata.promoCodeSnapshot : null;
|
|
2382
|
+
return {
|
|
2383
|
+
promotions,
|
|
2384
|
+
promoCode: code ? {
|
|
2385
|
+
durationType: typeof code.durationType === "string" ? code.durationType : null,
|
|
2386
|
+
durationValue: typeof code.durationValue === "number" ? code.durationValue : null,
|
|
2387
|
+
resolvedAmountNet: numberOr0(code.resolvedAmountNet)
|
|
2388
|
+
} : null
|
|
2389
|
+
};
|
|
2390
|
+
}
|
|
2391
|
+
__name(discountSnapshotsOf, "discountSnapshotsOf");
|
|
2392
|
+
function promotionMonths(value) {
|
|
2393
|
+
if (typeof value === "number") return value;
|
|
2394
|
+
if (isRecord(value) && typeof value.months === "number") return value.months;
|
|
2395
|
+
return null;
|
|
2396
|
+
}
|
|
2397
|
+
__name(promotionMonths, "promotionMonths");
|
|
2398
|
+
function periodsToCharge(args) {
|
|
2399
|
+
const { window, from, cycle, anchorDay, input, endsAt } = args;
|
|
2400
|
+
const periods = [];
|
|
2401
|
+
let start = from;
|
|
2402
|
+
for (let step = 0; step < MAX_CYCLES && start < window.start; step++) {
|
|
2403
|
+
const end = advanceOneCycle(start, cycle, anchorDay ?? void 0);
|
|
2404
|
+
if (end > window.start) break;
|
|
2405
|
+
periods.push({
|
|
2406
|
+
start,
|
|
2407
|
+
end
|
|
2408
|
+
});
|
|
2409
|
+
start = end;
|
|
2410
|
+
}
|
|
2411
|
+
if (from <= window.start) periods.push(window);
|
|
2412
|
+
return periods.filter((period) => isChargeable(period, input, endsAt));
|
|
2413
|
+
}
|
|
2414
|
+
__name(periodsToCharge, "periodsToCharge");
|
|
2415
|
+
function isChargeable(period, input, endsAt) {
|
|
2416
|
+
return period.start < period.end && period.start <= input.now && (!endsAt || period.start < endsAt);
|
|
2417
|
+
}
|
|
2418
|
+
__name(isChargeable, "isChargeable");
|
|
2419
|
+
function firstBoundaryAfter(window, start, cycle, anchorDay) {
|
|
2420
|
+
if (window.start <= start) return window.end;
|
|
2421
|
+
let boundary = window.start;
|
|
2422
|
+
for (let step = 0; step < MAX_CYCLES; step++) {
|
|
2423
|
+
const before = retreatOneCycle(boundary, cycle, anchorDay ?? void 0);
|
|
2424
|
+
if (before <= start) break;
|
|
2425
|
+
boundary = before;
|
|
2426
|
+
}
|
|
2427
|
+
return boundary;
|
|
2428
|
+
}
|
|
2429
|
+
__name(firstBoundaryAfter, "firstBoundaryAfter");
|
|
2430
|
+
function firstBundlePeriod(window, start, cycle, anchorDay) {
|
|
2431
|
+
return [
|
|
2432
|
+
{
|
|
2433
|
+
start,
|
|
2434
|
+
end: firstBoundaryAfter(window, start, cycle, anchorDay)
|
|
2435
|
+
}
|
|
2436
|
+
];
|
|
2437
|
+
}
|
|
2438
|
+
__name(firstBundlePeriod, "firstBundlePeriod");
|
|
2439
|
+
function lastPeriodEnd(written, source, sourceRef) {
|
|
2440
|
+
let last = null;
|
|
2441
|
+
for (const charge of written) {
|
|
2442
|
+
if (charge.source !== source || charge.sourceRef !== sourceRef) continue;
|
|
2443
|
+
if (!PERIOD_ORIGINS.includes(charge.origin)) continue;
|
|
2444
|
+
if (!last || charge.periodEnd > last) last = charge.periodEnd;
|
|
2445
|
+
}
|
|
2446
|
+
return last;
|
|
2447
|
+
}
|
|
2448
|
+
__name(lastPeriodEnd, "lastPeriodEnd");
|
|
2449
|
+
function firstPlanPeriodStart(written, subscriptionId) {
|
|
2450
|
+
let first = null;
|
|
2451
|
+
for (const charge of written) {
|
|
2452
|
+
if (charge.source !== "plan" || charge.sourceRef !== subscriptionId) continue;
|
|
2453
|
+
if (!PERIOD_ORIGINS.includes(charge.origin)) continue;
|
|
2454
|
+
if (!first || charge.periodStart < first) first = charge.periodStart;
|
|
2455
|
+
}
|
|
2456
|
+
return first;
|
|
2457
|
+
}
|
|
2458
|
+
__name(firstPlanPeriodStart, "firstPlanPeriodStart");
|
|
2459
|
+
function firstPeriodConcludedFor(concluded, periods) {
|
|
2460
|
+
const at = concluded.effectiveFrom;
|
|
2461
|
+
let first = null;
|
|
2462
|
+
for (const { charge } of periods) {
|
|
2463
|
+
if (charge.periodEnd <= at) continue;
|
|
2464
|
+
if (charge.periodStart < at && charge.contractId !== concluded.id) continue;
|
|
2465
|
+
if (!first || charge.periodStart < first) first = charge.periodStart;
|
|
2466
|
+
}
|
|
2467
|
+
return first;
|
|
2468
|
+
}
|
|
2469
|
+
__name(firstPeriodConcludedFor, "firstPeriodConcludedFor");
|
|
2470
|
+
function cyclesBetween(from, to, cycle, anchorDay) {
|
|
2471
|
+
let at = from;
|
|
2472
|
+
for (let step = 0; step < MAX_CYCLES; step++) {
|
|
2473
|
+
if (at.getTime() === to.getTime()) return step;
|
|
2474
|
+
if (at > to) return null;
|
|
2475
|
+
at = advanceOneCycle(at, cycle, anchorDay ?? void 0);
|
|
2476
|
+
}
|
|
2477
|
+
return null;
|
|
2478
|
+
}
|
|
2479
|
+
__name(cyclesBetween, "cyclesBetween");
|
|
2480
|
+
function monthsAfter(from, months, anchorDay) {
|
|
2481
|
+
let at = from;
|
|
2482
|
+
for (let step = 0; step < months; step++) {
|
|
2483
|
+
at = advanceOneCycle(at, "MONTHLY", anchorDay ?? from.getUTCDate());
|
|
2484
|
+
}
|
|
2485
|
+
return at;
|
|
2486
|
+
}
|
|
2487
|
+
__name(monthsAfter, "monthsAfter");
|
|
2488
|
+
function lineFor(contracts, period, matches) {
|
|
2489
|
+
const inForce = contractInForce(contracts, period.start);
|
|
2490
|
+
const inForceLine = inForce?.lineItems.find(matches);
|
|
2491
|
+
if (inForce && inForceLine) return {
|
|
2492
|
+
contract: inForce,
|
|
2493
|
+
line: inForceLine
|
|
2494
|
+
};
|
|
2495
|
+
for (const contract of [
|
|
2496
|
+
...contracts
|
|
2497
|
+
].sort(byEffectiveFrom)) {
|
|
2498
|
+
if (contract.status === "scheduled") continue;
|
|
2499
|
+
if (contract.effectiveFrom < period.start || contract.effectiveFrom >= period.end) continue;
|
|
2500
|
+
const line = contract.lineItems.find(matches);
|
|
2501
|
+
if (line) return {
|
|
2502
|
+
contract,
|
|
2503
|
+
line
|
|
2504
|
+
};
|
|
2505
|
+
}
|
|
2506
|
+
return null;
|
|
2507
|
+
}
|
|
2508
|
+
__name(lineFor, "lineFor");
|
|
2509
|
+
function contractInForce(contracts, at) {
|
|
2510
|
+
return [
|
|
2511
|
+
...contracts
|
|
2512
|
+
].filter((contract) => contract.status !== "scheduled" && contract.effectiveFrom <= at && (contract.effectiveUntil === null || at < contract.effectiveUntil)).sort(byEffectiveFrom).at(-1) ?? null;
|
|
2513
|
+
}
|
|
2514
|
+
__name(contractInForce, "contractInForce");
|
|
2515
|
+
function earliest2(contracts) {
|
|
2516
|
+
return [
|
|
2517
|
+
...contracts
|
|
2518
|
+
].sort(byEffectiveFrom)[0] ?? null;
|
|
2519
|
+
}
|
|
2520
|
+
__name(earliest2, "earliest");
|
|
2521
|
+
function byEffectiveFrom(a, b) {
|
|
2522
|
+
return a.effectiveFrom.getTime() - b.effectiveFrom.getTime();
|
|
2523
|
+
}
|
|
2524
|
+
__name(byEffectiveFrom, "byEffectiveFrom");
|
|
2525
|
+
function chargeOf(input, contract, line, charge) {
|
|
2526
|
+
return {
|
|
2527
|
+
subscriberId: input.subscriberId,
|
|
2528
|
+
tenantId: input.subscription.tenantId,
|
|
2529
|
+
subscriptionId: input.subscription.id,
|
|
2530
|
+
contractId: contract.id,
|
|
2531
|
+
contractLineItemId: line.id,
|
|
2532
|
+
origin: charge.origin,
|
|
2533
|
+
source: charge.source,
|
|
2534
|
+
sourceRef: charge.sourceRef,
|
|
2535
|
+
periodStart: charge.period.start,
|
|
2536
|
+
periodEnd: charge.period.end,
|
|
2537
|
+
currency: line.currency,
|
|
2538
|
+
// Rounded once, here, where it is derived (`SC-PRIC-018`).
|
|
2539
|
+
amountNet: toCents(charge.amountNet) / CENTS,
|
|
2540
|
+
bookedAt: charge.bookedAt
|
|
2541
|
+
};
|
|
2542
|
+
}
|
|
2543
|
+
__name(chargeOf, "chargeOf");
|
|
2544
|
+
function windowOf(start, end) {
|
|
2545
|
+
return start && end && start < end ? {
|
|
2546
|
+
start,
|
|
2547
|
+
end
|
|
2548
|
+
} : null;
|
|
2549
|
+
}
|
|
2550
|
+
__name(windowOf, "windowOf");
|
|
2551
|
+
function laterOf(a, b) {
|
|
2552
|
+
return b > a ? b : a;
|
|
2553
|
+
}
|
|
2554
|
+
__name(laterOf, "laterOf");
|
|
2555
|
+
function sameInstant(a, b) {
|
|
2556
|
+
return b !== null && a.getTime() === b.getTime();
|
|
2557
|
+
}
|
|
2558
|
+
__name(sameInstant, "sameInstant");
|
|
2559
|
+
function firstPeriodStart(periods) {
|
|
2560
|
+
return periods.reduce((first, { charge }) => !first || charge.periodStart < first ? charge.periodStart : first, null);
|
|
2561
|
+
}
|
|
2562
|
+
__name(firstPeriodStart, "firstPeriodStart");
|
|
2563
|
+
function holds(period, at) {
|
|
2564
|
+
return at !== null && period.start <= at && at < period.end;
|
|
2565
|
+
}
|
|
2566
|
+
__name(holds, "holds");
|
|
2567
|
+
function earlierOf(a, b) {
|
|
2568
|
+
if (!a) return b;
|
|
2569
|
+
if (!b) return a;
|
|
2570
|
+
return a < b ? a : b;
|
|
2571
|
+
}
|
|
2572
|
+
__name(earlierOf, "earlierOf");
|
|
2573
|
+
function rhythmOf(cycle) {
|
|
2574
|
+
return cycle === "YEARLY" ? "yearly" : "monthly";
|
|
2575
|
+
}
|
|
2576
|
+
__name(rhythmOf, "rhythmOf");
|
|
2577
|
+
function lineById(contracts, id) {
|
|
2578
|
+
for (const contract of contracts) {
|
|
2579
|
+
const line = contract.lineItems.find((item) => item.id === id);
|
|
2580
|
+
if (line) return line;
|
|
2581
|
+
}
|
|
2582
|
+
return null;
|
|
2583
|
+
}
|
|
2584
|
+
__name(lineById, "lineById");
|
|
2585
|
+
function toCents(amount) {
|
|
2586
|
+
return Math.round(amount * CENTS);
|
|
2587
|
+
}
|
|
2588
|
+
__name(toCents, "toCents");
|
|
2589
|
+
function numberOr0(value) {
|
|
2590
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2591
|
+
}
|
|
2592
|
+
__name(numberOr0, "numberOr0");
|
|
2593
|
+
function isRecord(value) {
|
|
2594
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2595
|
+
}
|
|
2596
|
+
__name(isRecord, "isRecord");
|
|
2597
|
+
|
|
2598
|
+
// src/billing/charges/subscriber-charge.service.ts
|
|
2599
|
+
function _ts_decorate9(decorators, target, key, desc) {
|
|
2600
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2601
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2602
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2603
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2604
|
+
}
|
|
2605
|
+
__name(_ts_decorate9, "_ts_decorate");
|
|
2606
|
+
function _ts_metadata7(k, v) {
|
|
2607
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2608
|
+
}
|
|
2609
|
+
__name(_ts_metadata7, "_ts_metadata");
|
|
2610
|
+
function _ts_param7(paramIndex, decorator) {
|
|
2611
|
+
return function(target, key) {
|
|
2612
|
+
decorator(target, key, paramIndex);
|
|
2613
|
+
};
|
|
2614
|
+
}
|
|
2615
|
+
__name(_ts_param7, "_ts_param");
|
|
2616
|
+
function planCycleOf(subscription) {
|
|
2617
|
+
return subscription.billingCycle;
|
|
2618
|
+
}
|
|
2619
|
+
__name(planCycleOf, "planCycleOf");
|
|
2620
|
+
function endOf(subscription) {
|
|
2621
|
+
return subscription.canceledEffectiveAt ?? subscription.canceledAt ?? null;
|
|
2622
|
+
}
|
|
2623
|
+
__name(endOf, "endOf");
|
|
2624
|
+
var SubscriberChargeService = class _SubscriberChargeService {
|
|
2625
|
+
static {
|
|
2626
|
+
__name(this, "SubscriberChargeService");
|
|
2627
|
+
}
|
|
2628
|
+
ledger;
|
|
2629
|
+
contracts;
|
|
2630
|
+
subscribers;
|
|
2631
|
+
subscriptions;
|
|
2632
|
+
bookings;
|
|
2633
|
+
freeze;
|
|
2634
|
+
logger = new Logger2(_SubscriberChargeService.name);
|
|
2635
|
+
constructor(ledger, contracts, subscribers, subscriptions, bookings = null, freeze = null) {
|
|
2636
|
+
this.ledger = ledger;
|
|
2637
|
+
this.contracts = contracts;
|
|
2638
|
+
this.subscribers = subscribers;
|
|
2639
|
+
this.subscriptions = subscriptions;
|
|
2640
|
+
this.bookings = bookings;
|
|
2641
|
+
this.freeze = freeze;
|
|
2642
|
+
}
|
|
2643
|
+
/**
|
|
2644
|
+
* Writes every charge the tenant's records give rise to by `now` that is
|
|
2645
|
+
* not written yet, and returns those.
|
|
2646
|
+
*
|
|
2647
|
+
* Nothing is charged without a contract (a charge points at a contract
|
|
2648
|
+
* line), in a trial, before the plan's current window when the account is
|
|
2649
|
+
* still empty, for a period that starts after `now`, or for one that
|
|
2650
|
+
* starts on or after the date a cancellation takes effect.
|
|
2651
|
+
*
|
|
2652
|
+
* A window that moved on before anything charged it is not charged
|
|
2653
|
+
* afterwards, so a job that renews periods calls this before it moves a
|
|
2654
|
+
* window, and moves it only when the call succeeded.
|
|
2655
|
+
*/
|
|
2656
|
+
async recordDueCharges(tenantId, now = /* @__PURE__ */ new Date()) {
|
|
2657
|
+
const subscription = await this.subscriptions.findForTenant(tenantId);
|
|
2658
|
+
if (!subscription?.id) return [];
|
|
2659
|
+
const subscriber = await this.subscribers.findByTenantId(tenantId);
|
|
2660
|
+
if (!subscriber) return [];
|
|
2661
|
+
const [bookings, written] = await Promise.all([
|
|
2662
|
+
this.bookings?.listBySubscription(subscription.id) ?? [],
|
|
2663
|
+
this.ledger.listBySubscription(subscription.id)
|
|
2664
|
+
]);
|
|
2665
|
+
const contracts = await this.contractsNamingEveryBooking(tenantId, subscription, bookings, now);
|
|
2666
|
+
const due = deriveDueCharges({
|
|
2667
|
+
now,
|
|
2668
|
+
subscriberId: subscriber.id,
|
|
2669
|
+
subscription: {
|
|
2670
|
+
id: subscription.id,
|
|
2671
|
+
tenantId,
|
|
2672
|
+
status: subscription.status,
|
|
2673
|
+
billingCycle: planCycleOf(subscription),
|
|
2674
|
+
currentPeriodStart: subscription.currentPeriodStart,
|
|
2675
|
+
currentPeriodEnd: subscription.currentPeriodEnd,
|
|
2676
|
+
anchorDay: resolvePlanAnchorDay(subscription),
|
|
2677
|
+
startedAt: subscription.startedAt,
|
|
2678
|
+
endsAt: endOf(subscription)
|
|
2679
|
+
},
|
|
2680
|
+
contracts,
|
|
2681
|
+
bookings,
|
|
2682
|
+
written
|
|
2683
|
+
});
|
|
2684
|
+
return this.ledger.recordCharges(due);
|
|
2685
|
+
}
|
|
2686
|
+
/**
|
|
2687
|
+
* The tenant's contracts, written once more where the one in force misses
|
|
2688
|
+
* a running booking.
|
|
2689
|
+
*
|
|
2690
|
+
* A booking writes its contract after it is saved, and a failure there does
|
|
2691
|
+
* not undo the booking. The booking would then stay uncharged for good,
|
|
2692
|
+
* since a charge points at a contract line — so the journal writes the
|
|
2693
|
+
* contract the way the booking would have. A failure here is logged and the
|
|
2694
|
+
* rest is charged: the next call tries again.
|
|
2695
|
+
*/
|
|
2696
|
+
async contractsNamingEveryBooking(tenantId, subscription, bookings, now) {
|
|
2697
|
+
const contracts = await this.contracts.list({
|
|
2698
|
+
tenantId
|
|
2699
|
+
});
|
|
2700
|
+
const missed = bookingsTheContractMisses(contracts, bookings, now);
|
|
2701
|
+
if (missed.length === 0 || !this.freeze || subscription.status === "TRIAL" || cancellationHasLanded(subscription, now)) {
|
|
2702
|
+
return contracts;
|
|
2703
|
+
}
|
|
2704
|
+
try {
|
|
2705
|
+
await this.freeze.freezeOnPlanChange(tenantId, subscription.planVersion.planId, planCycleOf(subscription), now, endOf(subscription));
|
|
2706
|
+
} catch (err) {
|
|
2707
|
+
this.logger.error(`Writing the contract for ${missed.length} booking(s) it misses failed (tenant ${tenantId}): ${String(err)}`);
|
|
2708
|
+
return contracts;
|
|
2709
|
+
}
|
|
2710
|
+
return this.contracts.list({
|
|
2711
|
+
tenantId
|
|
2712
|
+
});
|
|
2713
|
+
}
|
|
2714
|
+
};
|
|
2715
|
+
SubscriberChargeService = _ts_decorate9([
|
|
2716
|
+
Injectable6(),
|
|
2717
|
+
_ts_param7(0, Inject7(SUBSCRIBER_LEDGER_REPOSITORY_TOKEN)),
|
|
2718
|
+
_ts_param7(1, Inject7(SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN)),
|
|
2719
|
+
_ts_param7(2, Inject7(SUBSCRIBER_REPOSITORY_TOKEN)),
|
|
2720
|
+
_ts_param7(3, Inject7(SUBSCRIPTION_USAGE_PORT_TOKEN)),
|
|
2721
|
+
_ts_param7(4, Optional5()),
|
|
2722
|
+
_ts_param7(4, Inject7(SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN)),
|
|
2723
|
+
_ts_param7(5, Optional5()),
|
|
2724
|
+
_ts_param7(5, Inject7(CONTRACT_FREEZE_PORT_TOKEN)),
|
|
2725
|
+
_ts_metadata7("design:type", Function),
|
|
2726
|
+
_ts_metadata7("design:paramtypes", [
|
|
2727
|
+
typeof SubscriberLedgerRepository === "undefined" ? Object : SubscriberLedgerRepository,
|
|
2728
|
+
typeof SubscriptionContractRepository === "undefined" ? Object : SubscriptionContractRepository,
|
|
2729
|
+
typeof SubscriberRepository === "undefined" ? Object : SubscriberRepository,
|
|
2730
|
+
typeof SubscriptionUsagePort === "undefined" ? Object : SubscriptionUsagePort,
|
|
2731
|
+
Object,
|
|
2732
|
+
Object
|
|
2733
|
+
])
|
|
2734
|
+
], SubscriberChargeService);
|
|
2735
|
+
|
|
2736
|
+
// src/billing/dto/tenant-billing.dto.ts
|
|
2737
|
+
import { IsISO8601, IsOptional, IsString, Matches } from "class-validator";
|
|
2738
|
+
function _ts_decorate10(decorators, target, key, desc) {
|
|
2739
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2740
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2741
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2742
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2743
|
+
}
|
|
2744
|
+
__name(_ts_decorate10, "_ts_decorate");
|
|
2745
|
+
function _ts_metadata8(k, v) {
|
|
2746
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2747
|
+
}
|
|
2748
|
+
__name(_ts_metadata8, "_ts_metadata");
|
|
1689
2749
|
var PLAN_OR_CYCLE_PATTERN = /^[A-Z][A-Z0-9_]*$/;
|
|
1690
2750
|
var PreviewPlanChangeDto = class {
|
|
1691
2751
|
static {
|
|
@@ -1694,19 +2754,19 @@ var PreviewPlanChangeDto = class {
|
|
|
1694
2754
|
plan;
|
|
1695
2755
|
billingCycle;
|
|
1696
2756
|
};
|
|
1697
|
-
|
|
2757
|
+
_ts_decorate10([
|
|
1698
2758
|
IsString(),
|
|
1699
2759
|
Matches(PLAN_OR_CYCLE_PATTERN, {
|
|
1700
2760
|
message: "plan must be SCREAMING_SNAKE_CASE"
|
|
1701
2761
|
}),
|
|
1702
|
-
|
|
2762
|
+
_ts_metadata8("design:type", String)
|
|
1703
2763
|
], PreviewPlanChangeDto.prototype, "plan", void 0);
|
|
1704
|
-
|
|
2764
|
+
_ts_decorate10([
|
|
1705
2765
|
IsString(),
|
|
1706
2766
|
Matches(PLAN_OR_CYCLE_PATTERN, {
|
|
1707
2767
|
message: "billingCycle must be SCREAMING_SNAKE_CASE (e.g. MONTHLY, YEARLY)"
|
|
1708
2768
|
}),
|
|
1709
|
-
|
|
2769
|
+
_ts_metadata8("design:type", String)
|
|
1710
2770
|
], PreviewPlanChangeDto.prototype, "billingCycle", void 0);
|
|
1711
2771
|
var ChangePlanDto = class extends PreviewPlanChangeDto {
|
|
1712
2772
|
static {
|
|
@@ -1731,25 +2791,25 @@ var CancelSubscriptionDto = class {
|
|
|
1731
2791
|
*/
|
|
1732
2792
|
expectedEffectiveAt;
|
|
1733
2793
|
};
|
|
1734
|
-
|
|
2794
|
+
_ts_decorate10([
|
|
1735
2795
|
IsOptional(),
|
|
1736
2796
|
IsISO8601(),
|
|
1737
|
-
|
|
2797
|
+
_ts_metadata8("design:type", String)
|
|
1738
2798
|
], CancelSubscriptionDto.prototype, "expectedEffectiveAt", void 0);
|
|
1739
2799
|
|
|
1740
2800
|
// src/billing/dto/onboarding-subscription.dto.ts
|
|
1741
2801
|
import { ArrayMaxSize, IsArray, IsOptional as IsOptional2, IsString as IsString2, IsUUID, Matches as Matches2 } from "class-validator";
|
|
1742
|
-
function
|
|
2802
|
+
function _ts_decorate11(decorators, target, key, desc) {
|
|
1743
2803
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1744
2804
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1745
2805
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1746
2806
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1747
2807
|
}
|
|
1748
|
-
__name(
|
|
1749
|
-
function
|
|
2808
|
+
__name(_ts_decorate11, "_ts_decorate");
|
|
2809
|
+
function _ts_metadata9(k, v) {
|
|
1750
2810
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1751
2811
|
}
|
|
1752
|
-
__name(
|
|
2812
|
+
__name(_ts_metadata9, "_ts_metadata");
|
|
1753
2813
|
var PLAN_OR_CYCLE_PATTERN2 = /^[A-Z][A-Z0-9_]*$/;
|
|
1754
2814
|
var PROMO_CODE_PATTERN = /^[A-Z0-9_-]{4,32}$/i;
|
|
1755
2815
|
var CompleteOnboardingSubscriptionDto = class {
|
|
@@ -1769,52 +2829,52 @@ var CompleteOnboardingSubscriptionDto = class {
|
|
|
1769
2829
|
*/
|
|
1770
2830
|
bundleVersionIds;
|
|
1771
2831
|
};
|
|
1772
|
-
|
|
2832
|
+
_ts_decorate11([
|
|
1773
2833
|
IsString2(),
|
|
1774
2834
|
Matches2(PLAN_OR_CYCLE_PATTERN2, {
|
|
1775
2835
|
message: "plan must be SCREAMING_SNAKE_CASE"
|
|
1776
2836
|
}),
|
|
1777
|
-
|
|
2837
|
+
_ts_metadata9("design:type", String)
|
|
1778
2838
|
], CompleteOnboardingSubscriptionDto.prototype, "plan", void 0);
|
|
1779
|
-
|
|
2839
|
+
_ts_decorate11([
|
|
1780
2840
|
IsString2(),
|
|
1781
2841
|
Matches2(PLAN_OR_CYCLE_PATTERN2, {
|
|
1782
2842
|
message: "billingCycle must be SCREAMING_SNAKE_CASE (e.g. MONTHLY, YEARLY)"
|
|
1783
2843
|
}),
|
|
1784
|
-
|
|
2844
|
+
_ts_metadata9("design:type", String)
|
|
1785
2845
|
], CompleteOnboardingSubscriptionDto.prototype, "billingCycle", void 0);
|
|
1786
|
-
|
|
2846
|
+
_ts_decorate11([
|
|
1787
2847
|
IsOptional2(),
|
|
1788
2848
|
IsString2(),
|
|
1789
2849
|
Matches2(PROMO_CODE_PATTERN, {
|
|
1790
2850
|
message: 'promoCode must consist of A\u2013Z, 0\u20139, "-", "_" (4\u201332 characters)'
|
|
1791
2851
|
}),
|
|
1792
|
-
|
|
2852
|
+
_ts_metadata9("design:type", String)
|
|
1793
2853
|
], CompleteOnboardingSubscriptionDto.prototype, "promoCode", void 0);
|
|
1794
|
-
|
|
2854
|
+
_ts_decorate11([
|
|
1795
2855
|
IsOptional2(),
|
|
1796
2856
|
IsArray(),
|
|
1797
2857
|
ArrayMaxSize(10),
|
|
1798
2858
|
IsUUID("all", {
|
|
1799
2859
|
each: true
|
|
1800
2860
|
}),
|
|
1801
|
-
|
|
2861
|
+
_ts_metadata9("design:type", Array)
|
|
1802
2862
|
], CompleteOnboardingSubscriptionDto.prototype, "bundleVersionIds", void 0);
|
|
1803
2863
|
|
|
1804
2864
|
// src/billing/dto/subscription-bundles.dto.ts
|
|
1805
2865
|
import { ArrayMaxSize as ArrayMaxSize2, IsArray as IsArray2, IsIn, IsInt, IsOptional as IsOptional3, IsUUID as IsUUID2, Matches as Matches3, Max, Min } from "class-validator";
|
|
1806
2866
|
import { BUNDLE_PRICE_LOOKUP_LIMIT } from "@saasicat/core";
|
|
1807
|
-
function
|
|
2867
|
+
function _ts_decorate12(decorators, target, key, desc) {
|
|
1808
2868
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1809
2869
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1810
2870
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1811
2871
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1812
2872
|
}
|
|
1813
|
-
__name(
|
|
1814
|
-
function
|
|
2873
|
+
__name(_ts_decorate12, "_ts_decorate");
|
|
2874
|
+
function _ts_metadata10(k, v) {
|
|
1815
2875
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1816
2876
|
}
|
|
1817
|
-
__name(
|
|
2877
|
+
__name(_ts_metadata10, "_ts_metadata");
|
|
1818
2878
|
var ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}(T.*)?$/;
|
|
1819
2879
|
var AddSubscriptionBundleDto = class {
|
|
1820
2880
|
static {
|
|
@@ -1839,24 +2899,24 @@ var AddSubscriptionBundleDto = class {
|
|
|
1839
2899
|
*/
|
|
1840
2900
|
billingCycle;
|
|
1841
2901
|
};
|
|
1842
|
-
|
|
2902
|
+
_ts_decorate12([
|
|
1843
2903
|
IsUUID2(),
|
|
1844
|
-
|
|
2904
|
+
_ts_metadata10("design:type", String)
|
|
1845
2905
|
], AddSubscriptionBundleDto.prototype, "bundleVersionId", void 0);
|
|
1846
|
-
|
|
2906
|
+
_ts_decorate12([
|
|
1847
2907
|
IsOptional3(),
|
|
1848
2908
|
IsInt(),
|
|
1849
2909
|
Min(0),
|
|
1850
2910
|
Max(120),
|
|
1851
|
-
|
|
2911
|
+
_ts_metadata10("design:type", Number)
|
|
1852
2912
|
], AddSubscriptionBundleDto.prototype, "minimumTermMonths", void 0);
|
|
1853
|
-
|
|
2913
|
+
_ts_decorate12([
|
|
1854
2914
|
IsOptional3(),
|
|
1855
2915
|
IsIn([
|
|
1856
2916
|
"MONTHLY",
|
|
1857
2917
|
"YEARLY"
|
|
1858
2918
|
]),
|
|
1859
|
-
|
|
2919
|
+
_ts_metadata10("design:type", String)
|
|
1860
2920
|
], AddSubscriptionBundleDto.prototype, "billingCycle", void 0);
|
|
1861
2921
|
var PreviewSubscriptionBundleDto = class {
|
|
1862
2922
|
static {
|
|
@@ -1880,30 +2940,30 @@ var PreviewSubscriptionBundleDto = class {
|
|
|
1880
2940
|
*/
|
|
1881
2941
|
billingCycle;
|
|
1882
2942
|
};
|
|
1883
|
-
|
|
2943
|
+
_ts_decorate12([
|
|
1884
2944
|
IsOptional3(),
|
|
1885
2945
|
IsUUID2(),
|
|
1886
|
-
|
|
2946
|
+
_ts_metadata10("design:type", String)
|
|
1887
2947
|
], PreviewSubscriptionBundleDto.prototype, "bundleVersionId", void 0);
|
|
1888
|
-
|
|
2948
|
+
_ts_decorate12([
|
|
1889
2949
|
IsOptional3(),
|
|
1890
2950
|
IsUUID2(),
|
|
1891
|
-
|
|
2951
|
+
_ts_metadata10("design:type", String)
|
|
1892
2952
|
], PreviewSubscriptionBundleDto.prototype, "subscriptionBundleId", void 0);
|
|
1893
|
-
|
|
2953
|
+
_ts_decorate12([
|
|
1894
2954
|
IsOptional3(),
|
|
1895
2955
|
IsInt(),
|
|
1896
2956
|
Min(0),
|
|
1897
2957
|
Max(120),
|
|
1898
|
-
|
|
2958
|
+
_ts_metadata10("design:type", Number)
|
|
1899
2959
|
], PreviewSubscriptionBundleDto.prototype, "minimumTermMonths", void 0);
|
|
1900
|
-
|
|
2960
|
+
_ts_decorate12([
|
|
1901
2961
|
IsOptional3(),
|
|
1902
2962
|
IsIn([
|
|
1903
2963
|
"MONTHLY",
|
|
1904
2964
|
"YEARLY"
|
|
1905
2965
|
]),
|
|
1906
|
-
|
|
2966
|
+
_ts_metadata10("design:type", String)
|
|
1907
2967
|
], PreviewSubscriptionBundleDto.prototype, "billingCycle", void 0);
|
|
1908
2968
|
var CancelSubscriptionBundleDto = class {
|
|
1909
2969
|
static {
|
|
@@ -1916,12 +2976,12 @@ var CancelSubscriptionBundleDto = class {
|
|
|
1916
2976
|
*/
|
|
1917
2977
|
canceledAt;
|
|
1918
2978
|
};
|
|
1919
|
-
|
|
2979
|
+
_ts_decorate12([
|
|
1920
2980
|
IsOptional3(),
|
|
1921
2981
|
Matches3(ISO_DATE_PATTERN, {
|
|
1922
2982
|
message: "canceledAt must be an ISO date (YYYY-MM-DD)"
|
|
1923
2983
|
}),
|
|
1924
|
-
|
|
2984
|
+
_ts_metadata10("design:type", String)
|
|
1925
2985
|
], CancelSubscriptionBundleDto.prototype, "canceledAt", void 0);
|
|
1926
2986
|
var BundlePriceLookupDto = class {
|
|
1927
2987
|
static {
|
|
@@ -1933,35 +2993,35 @@ var BundlePriceLookupDto = class {
|
|
|
1933
2993
|
*/
|
|
1934
2994
|
bundleVersionIds;
|
|
1935
2995
|
};
|
|
1936
|
-
|
|
2996
|
+
_ts_decorate12([
|
|
1937
2997
|
IsArray2(),
|
|
1938
2998
|
ArrayMaxSize2(BUNDLE_PRICE_LOOKUP_LIMIT),
|
|
1939
2999
|
IsUUID2("4", {
|
|
1940
3000
|
each: true
|
|
1941
3001
|
}),
|
|
1942
|
-
|
|
3002
|
+
_ts_metadata10("design:type", Array)
|
|
1943
3003
|
], BundlePriceLookupDto.prototype, "bundleVersionIds", void 0);
|
|
1944
3004
|
|
|
1945
3005
|
// src/billing/subscription-bundles.service.ts
|
|
1946
|
-
import { Inject as
|
|
3006
|
+
import { Inject as Inject8, Injectable as Injectable7, NotFoundException as NotFoundException2, Optional as Optional6, UnprocessableEntityException as UnprocessableEntityException2 } from "@nestjs/common";
|
|
1947
3007
|
import { BILLING_ERROR_CODES as BILLING_ERROR_CODES2, CATALOG_ERROR_CODES } from "@saasicat/core";
|
|
1948
|
-
function
|
|
3008
|
+
function _ts_decorate13(decorators, target, key, desc) {
|
|
1949
3009
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1950
3010
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1951
3011
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1952
3012
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1953
3013
|
}
|
|
1954
|
-
__name(
|
|
1955
|
-
function
|
|
3014
|
+
__name(_ts_decorate13, "_ts_decorate");
|
|
3015
|
+
function _ts_metadata11(k, v) {
|
|
1956
3016
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1957
3017
|
}
|
|
1958
|
-
__name(
|
|
1959
|
-
function
|
|
3018
|
+
__name(_ts_metadata11, "_ts_metadata");
|
|
3019
|
+
function _ts_param8(paramIndex, decorator) {
|
|
1960
3020
|
return function(target, key) {
|
|
1961
3021
|
decorator(target, key, paramIndex);
|
|
1962
3022
|
};
|
|
1963
3023
|
}
|
|
1964
|
-
__name(
|
|
3024
|
+
__name(_ts_param8, "_ts_param");
|
|
1965
3025
|
var SubscriptionBundlesService = class {
|
|
1966
3026
|
static {
|
|
1967
3027
|
__name(this, "SubscriptionBundlesService");
|
|
@@ -2202,16 +3262,16 @@ var SubscriptionBundlesService = class {
|
|
|
2202
3262
|
return this.repo.reactivate(subscriptionBundleId);
|
|
2203
3263
|
}
|
|
2204
3264
|
};
|
|
2205
|
-
SubscriptionBundlesService =
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
3265
|
+
SubscriptionBundlesService = _ts_decorate13([
|
|
3266
|
+
Injectable7(),
|
|
3267
|
+
_ts_param8(0, Inject8(SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN)),
|
|
3268
|
+
_ts_param8(1, Inject8(BUNDLE_REPOSITORY_TOKEN)),
|
|
3269
|
+
_ts_param8(2, Optional6()),
|
|
3270
|
+
_ts_param8(2, Inject8(SUBSCRIPTION_BUNDLE_CONFIG_TOKEN)),
|
|
3271
|
+
_ts_param8(3, Optional6()),
|
|
3272
|
+
_ts_param8(3, Inject8(SELF_SERVICE_BLOCKED_BUNDLES_TOKEN)),
|
|
3273
|
+
_ts_metadata11("design:type", Function),
|
|
3274
|
+
_ts_metadata11("design:paramtypes", [
|
|
2215
3275
|
typeof SubscriptionBundleRepository === "undefined" ? Object : SubscriptionBundleRepository,
|
|
2216
3276
|
typeof BundleRepository === "undefined" ? Object : BundleRepository,
|
|
2217
3277
|
typeof SubscriptionBundleConfig === "undefined" ? Object : SubscriptionBundleConfig,
|
|
@@ -2243,25 +3303,38 @@ function clampToParent(ownTermEndsAt, parentEndsAt) {
|
|
|
2243
3303
|
__name(clampToParent, "clampToParent");
|
|
2244
3304
|
|
|
2245
3305
|
// src/billing/tenant-billing.controller.ts
|
|
2246
|
-
import { BadRequestException, Body, Controller as
|
|
3306
|
+
import { BadRequestException, Body, Controller as Controller3, ForbiddenException as ForbiddenException2, Get as Get3, HttpCode, HttpStatus, Inject as Inject9, Logger as Logger3, ConflictException, NotFoundException as NotFoundException3, Optional as Optional7, Post, Req, UseGuards as UseGuards2 } from "@nestjs/common";
|
|
2247
3307
|
import { AUTH_ERROR_CODES as AUTH_ERROR_CODES2, BILLING_ERROR_CODES as BILLING_ERROR_CODES3 } from "@saasicat/core";
|
|
2248
|
-
|
|
3308
|
+
|
|
3309
|
+
// src/billing/charges/record-charges-after.ts
|
|
3310
|
+
async function recordChargesAfter(charges, tenantId, change, logger) {
|
|
3311
|
+
if (!charges) return;
|
|
3312
|
+
try {
|
|
3313
|
+
await charges.recordDueCharges(tenantId);
|
|
3314
|
+
} catch (err) {
|
|
3315
|
+
logger.error(`Recording charges after ${change} failed (tenant ${tenantId}): ${String(err)}`);
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
__name(recordChargesAfter, "recordChargesAfter");
|
|
3319
|
+
|
|
3320
|
+
// src/billing/tenant-billing.controller.ts
|
|
3321
|
+
function _ts_decorate14(decorators, target, key, desc) {
|
|
2249
3322
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2250
3323
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2251
3324
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2252
3325
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2253
3326
|
}
|
|
2254
|
-
__name(
|
|
2255
|
-
function
|
|
3327
|
+
__name(_ts_decorate14, "_ts_decorate");
|
|
3328
|
+
function _ts_metadata12(k, v) {
|
|
2256
3329
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2257
3330
|
}
|
|
2258
|
-
__name(
|
|
2259
|
-
function
|
|
3331
|
+
__name(_ts_metadata12, "_ts_metadata");
|
|
3332
|
+
function _ts_param9(paramIndex, decorator) {
|
|
2260
3333
|
return function(target, key) {
|
|
2261
3334
|
decorator(target, key, paramIndex);
|
|
2262
3335
|
};
|
|
2263
3336
|
}
|
|
2264
|
-
__name(
|
|
3337
|
+
__name(_ts_param9, "_ts_param");
|
|
2265
3338
|
var TenantBillingController = class _TenantBillingController {
|
|
2266
3339
|
static {
|
|
2267
3340
|
__name(this, "TenantBillingController");
|
|
@@ -2282,7 +3355,8 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2282
3355
|
contractFreeze;
|
|
2283
3356
|
trialProjection;
|
|
2284
3357
|
cancellationNoticeDays;
|
|
2285
|
-
|
|
3358
|
+
charges;
|
|
3359
|
+
constructor(entitlements, planPreview, subscriptionUsage, usageSnapshot, subscriptionWrite, tenantIdResolver = null, userIdResolver = null, blockedPlans = null, promoCodes = null, auditService = null, userEmailResolver = null, auditContextResolver = null, subscriptionBundles = null, contractFreeze = null, trialProjection = null, cancellationNoticeDays = NO_NOTICE_PERIOD, charges = null) {
|
|
2286
3360
|
this.entitlements = entitlements;
|
|
2287
3361
|
this.planPreview = planPreview;
|
|
2288
3362
|
this.subscriptionUsage = subscriptionUsage;
|
|
@@ -2299,8 +3373,9 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2299
3373
|
this.contractFreeze = contractFreeze;
|
|
2300
3374
|
this.trialProjection = trialProjection;
|
|
2301
3375
|
this.cancellationNoticeDays = cancellationNoticeDays;
|
|
3376
|
+
this.charges = charges;
|
|
2302
3377
|
}
|
|
2303
|
-
logger = new
|
|
3378
|
+
logger = new Logger3(_TenantBillingController.name);
|
|
2304
3379
|
// ---------------------------------------------------------------------
|
|
2305
3380
|
// Reads (Phase B) — all authenticated tenant users
|
|
2306
3381
|
// ---------------------------------------------------------------------
|
|
@@ -2456,7 +3531,8 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2456
3531
|
};
|
|
2457
3532
|
if (decision.isImmediate) {
|
|
2458
3533
|
const wasTrial = sub.status === "TRIAL";
|
|
2459
|
-
const
|
|
3534
|
+
const opensPeriod = decision.proration?.basis === "newPeriod";
|
|
3535
|
+
const period = wasTrial || cancellationOutstanding || !opensPeriod ? null : initialPeriodWindow(/* @__PURE__ */ new Date(), dto.billingCycle);
|
|
2460
3536
|
const trialEndsAt = wasTrial && this.trialProjection ? await this.trialProjection.projectTrialEndsAt({
|
|
2461
3537
|
currentPlan: sub.plan,
|
|
2462
3538
|
targetPlan: dto.plan,
|
|
@@ -2486,6 +3562,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2486
3562
|
// contract it freezes still ends when the subscription does.
|
|
2487
3563
|
sub.canceledEffectiveAt ?? sub.canceledAt ?? null
|
|
2488
3564
|
);
|
|
3565
|
+
await recordChargesAfter(this.charges, tenantId, "a plan change", this.logger);
|
|
2489
3566
|
await this.auditLog(req, userId, "Subscription", tenantId, "CHANGE_PLAN", {
|
|
2490
3567
|
fromPlan: sub.plan,
|
|
2491
3568
|
fromCycle: sub.billingCycle,
|
|
@@ -2658,7 +3735,6 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2658
3735
|
}
|
|
2659
3736
|
}
|
|
2660
3737
|
}
|
|
2661
|
-
await this.tryFreezeOnPlanChange(tenantId, dto.plan, dto.billingCycle, wasTrial);
|
|
2662
3738
|
this.entitlements.invalidateTenant(tenantId);
|
|
2663
3739
|
await this.auditLog(req, userId, "Subscription", tenantId, "COMPLETE_ONBOARDING_SUBSCRIPTION", {
|
|
2664
3740
|
plan: planResult.plan,
|
|
@@ -2698,6 +3774,8 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2698
3774
|
} else if (bundleVersionIds.length > 0 && !this.subscriptionBundles) {
|
|
2699
3775
|
warnings.push("Bundle bookings were requested during onboarding, but SubscriptionBundleModule is not registered in the consumer. No bundles were created.");
|
|
2700
3776
|
}
|
|
3777
|
+
await this.tryFreezeOnPlanChange(tenantId, dto.plan, dto.billingCycle, wasTrial);
|
|
3778
|
+
await recordChargesAfter(this.charges, tenantId, "onboarding", this.logger);
|
|
2701
3779
|
return {
|
|
2702
3780
|
plan: planResult.plan,
|
|
2703
3781
|
// The adapter returns `string`; the UI expects `'MONTHLY' | 'YEARLY'`.
|
|
@@ -2976,115 +4054,117 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2976
4054
|
}
|
|
2977
4055
|
}
|
|
2978
4056
|
};
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
4057
|
+
_ts_decorate14([
|
|
4058
|
+
Get3("entitlement"),
|
|
4059
|
+
_ts_param9(0, Req()),
|
|
4060
|
+
_ts_metadata12("design:type", Function),
|
|
4061
|
+
_ts_metadata12("design:paramtypes", [
|
|
2984
4062
|
typeof RequestLike === "undefined" ? Object : RequestLike
|
|
2985
4063
|
]),
|
|
2986
|
-
|
|
4064
|
+
_ts_metadata12("design:returntype", Promise)
|
|
2987
4065
|
], TenantBillingController.prototype, "getEntitlement", null);
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
4066
|
+
_ts_decorate14([
|
|
4067
|
+
Get3("usage"),
|
|
4068
|
+
_ts_param9(0, Req()),
|
|
4069
|
+
_ts_metadata12("design:type", Function),
|
|
4070
|
+
_ts_metadata12("design:paramtypes", [
|
|
2993
4071
|
typeof RequestLike === "undefined" ? Object : RequestLike
|
|
2994
4072
|
]),
|
|
2995
|
-
|
|
4073
|
+
_ts_metadata12("design:returntype", Promise)
|
|
2996
4074
|
], TenantBillingController.prototype, "getUsage", null);
|
|
2997
|
-
|
|
4075
|
+
_ts_decorate14([
|
|
2998
4076
|
Post("plan/preview"),
|
|
2999
4077
|
HttpCode(HttpStatus.OK),
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
4078
|
+
UseGuards2(TenantAdminGuard),
|
|
4079
|
+
_ts_param9(0, Req()),
|
|
4080
|
+
_ts_param9(1, Body()),
|
|
4081
|
+
_ts_metadata12("design:type", Function),
|
|
4082
|
+
_ts_metadata12("design:paramtypes", [
|
|
3005
4083
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3006
4084
|
typeof PreviewPlanChangeDto === "undefined" ? Object : PreviewPlanChangeDto
|
|
3007
4085
|
]),
|
|
3008
|
-
|
|
4086
|
+
_ts_metadata12("design:returntype", Promise)
|
|
3009
4087
|
], TenantBillingController.prototype, "previewPlanChange", null);
|
|
3010
|
-
|
|
4088
|
+
_ts_decorate14([
|
|
3011
4089
|
Post("plan"),
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
4090
|
+
UseGuards2(TenantAdminGuard),
|
|
4091
|
+
_ts_param9(0, Req()),
|
|
4092
|
+
_ts_param9(1, Body()),
|
|
4093
|
+
_ts_metadata12("design:type", Function),
|
|
4094
|
+
_ts_metadata12("design:paramtypes", [
|
|
3017
4095
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3018
4096
|
typeof ChangePlanDto === "undefined" ? Object : ChangePlanDto
|
|
3019
4097
|
]),
|
|
3020
|
-
|
|
4098
|
+
_ts_metadata12("design:returntype", Promise)
|
|
3021
4099
|
], TenantBillingController.prototype, "changePlan", null);
|
|
3022
|
-
|
|
4100
|
+
_ts_decorate14([
|
|
3023
4101
|
Post("onboarding/initial-subscription"),
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
4102
|
+
UseGuards2(TenantAdminGuard),
|
|
4103
|
+
_ts_param9(0, Req()),
|
|
4104
|
+
_ts_param9(1, Body()),
|
|
4105
|
+
_ts_metadata12("design:type", Function),
|
|
4106
|
+
_ts_metadata12("design:paramtypes", [
|
|
3029
4107
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3030
4108
|
typeof CompleteOnboardingSubscriptionDto === "undefined" ? Object : CompleteOnboardingSubscriptionDto
|
|
3031
4109
|
]),
|
|
3032
|
-
|
|
4110
|
+
_ts_metadata12("design:returntype", Promise)
|
|
3033
4111
|
], TenantBillingController.prototype, "completeOnboardingSubscription", null);
|
|
3034
|
-
|
|
4112
|
+
_ts_decorate14([
|
|
3035
4113
|
Post("subscription/accept-pending-version"),
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
4114
|
+
UseGuards2(TenantAdminGuard),
|
|
4115
|
+
_ts_param9(0, Req()),
|
|
4116
|
+
_ts_metadata12("design:type", Function),
|
|
4117
|
+
_ts_metadata12("design:paramtypes", [
|
|
3040
4118
|
typeof RequestLike === "undefined" ? Object : RequestLike
|
|
3041
4119
|
]),
|
|
3042
|
-
|
|
4120
|
+
_ts_metadata12("design:returntype", Promise)
|
|
3043
4121
|
], TenantBillingController.prototype, "acceptPendingPlanVersion", null);
|
|
3044
|
-
|
|
4122
|
+
_ts_decorate14([
|
|
3045
4123
|
Post("cancel"),
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
4124
|
+
UseGuards2(TenantAdminGuard),
|
|
4125
|
+
_ts_param9(0, Req()),
|
|
4126
|
+
_ts_param9(1, Body()),
|
|
4127
|
+
_ts_metadata12("design:type", Function),
|
|
4128
|
+
_ts_metadata12("design:paramtypes", [
|
|
3051
4129
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3052
4130
|
typeof CancelSubscriptionDto === "undefined" ? Object : CancelSubscriptionDto
|
|
3053
4131
|
]),
|
|
3054
|
-
|
|
4132
|
+
_ts_metadata12("design:returntype", Promise)
|
|
3055
4133
|
], TenantBillingController.prototype, "cancelSubscription", null);
|
|
3056
|
-
TenantBillingController =
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
4134
|
+
TenantBillingController = _ts_decorate14([
|
|
4135
|
+
Controller3("billing"),
|
|
4136
|
+
UseGuards2(ComposedTenantAuthGuard),
|
|
4137
|
+
_ts_param9(0, Inject9(ENTITLEMENT_SERVICE_TOKEN)),
|
|
4138
|
+
_ts_param9(1, Inject9(PlanChangePreviewService)),
|
|
4139
|
+
_ts_param9(2, Inject9(SUBSCRIPTION_USAGE_PORT_TOKEN)),
|
|
4140
|
+
_ts_param9(3, Inject9(USAGE_SNAPSHOT_PORT_TOKEN)),
|
|
4141
|
+
_ts_param9(4, Inject9(SUBSCRIPTION_WRITE_PORT_TOKEN)),
|
|
4142
|
+
_ts_param9(5, Optional7()),
|
|
4143
|
+
_ts_param9(5, Inject9(TENANT_ID_RESOLVER_TOKEN)),
|
|
4144
|
+
_ts_param9(6, Optional7()),
|
|
4145
|
+
_ts_param9(6, Inject9(USER_ID_RESOLVER_TOKEN)),
|
|
4146
|
+
_ts_param9(7, Optional7()),
|
|
4147
|
+
_ts_param9(7, Inject9(SELF_SERVICE_BLOCKED_PLANS_TOKEN)),
|
|
4148
|
+
_ts_param9(8, Optional7()),
|
|
4149
|
+
_ts_param9(8, Inject9(PromoCodesService)),
|
|
4150
|
+
_ts_param9(9, Optional7()),
|
|
4151
|
+
_ts_param9(9, Inject9(AdminAuditService)),
|
|
4152
|
+
_ts_param9(10, Optional7()),
|
|
4153
|
+
_ts_param9(10, Inject9(USER_EMAIL_RESOLVER_TOKEN)),
|
|
4154
|
+
_ts_param9(11, Optional7()),
|
|
4155
|
+
_ts_param9(11, Inject9(AUDIT_CONTEXT_RESOLVER_TOKEN)),
|
|
4156
|
+
_ts_param9(12, Optional7()),
|
|
4157
|
+
_ts_param9(12, Inject9(SubscriptionBundlesService)),
|
|
4158
|
+
_ts_param9(13, Optional7()),
|
|
4159
|
+
_ts_param9(13, Inject9(CONTRACT_FREEZE_PORT_TOKEN)),
|
|
4160
|
+
_ts_param9(14, Optional7()),
|
|
4161
|
+
_ts_param9(14, Inject9(TRIAL_PROJECTION_PORT_TOKEN)),
|
|
4162
|
+
_ts_param9(15, Optional7()),
|
|
4163
|
+
_ts_param9(15, Inject9(CANCELLATION_NOTICE_DAYS_TOKEN)),
|
|
4164
|
+
_ts_param9(16, Optional7()),
|
|
4165
|
+
_ts_param9(16, Inject9(SubscriberChargeService)),
|
|
4166
|
+
_ts_metadata12("design:type", Function),
|
|
4167
|
+
_ts_metadata12("design:paramtypes", [
|
|
3088
4168
|
typeof EntitlementService === "undefined" ? Object : EntitlementService,
|
|
3089
4169
|
typeof PlanChangePreviewService === "undefined" ? Object : PlanChangePreviewService,
|
|
3090
4170
|
typeof SubscriptionUsagePort === "undefined" ? Object : SubscriptionUsagePort,
|
|
@@ -3100,20 +4180,21 @@ TenantBillingController = _ts_decorate11([
|
|
|
3100
4180
|
Object,
|
|
3101
4181
|
Object,
|
|
3102
4182
|
Object,
|
|
3103
|
-
typeof CancellationNoticePeriods === "undefined" ? Object : CancellationNoticePeriods
|
|
4183
|
+
typeof CancellationNoticePeriods === "undefined" ? Object : CancellationNoticePeriods,
|
|
4184
|
+
Object
|
|
3104
4185
|
])
|
|
3105
4186
|
], TenantBillingController);
|
|
3106
4187
|
|
|
3107
4188
|
// src/billing/tenant-billing.module.ts
|
|
3108
|
-
import { Module as
|
|
4189
|
+
import { Module as Module3 } from "@nestjs/common";
|
|
3109
4190
|
import { planCatalogSchema as planCatalogSchema2 } from "@saasicat/spec";
|
|
3110
|
-
function
|
|
4191
|
+
function _ts_decorate15(decorators, target, key, desc) {
|
|
3111
4192
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3112
4193
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
3113
4194
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
3114
4195
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3115
4196
|
}
|
|
3116
|
-
__name(
|
|
4197
|
+
__name(_ts_decorate15, "_ts_decorate");
|
|
3117
4198
|
function settingFromCatalog(catalog, key) {
|
|
3118
4199
|
const settings = catalog.tenantBilling;
|
|
3119
4200
|
const value = settings?.[key];
|
|
@@ -3183,6 +4264,13 @@ var TenantBillingModule = class _TenantBillingModule {
|
|
|
3183
4264
|
useClass: SubscriptionContractFreezeService
|
|
3184
4265
|
});
|
|
3185
4266
|
}
|
|
4267
|
+
const hasChargeJournal = Boolean(options.chargeJournal);
|
|
4268
|
+
if (options.chargeJournal) {
|
|
4269
|
+
if (!options.contractFreeze) {
|
|
4270
|
+
throw new Error("TenantBillingModule: `chargeJournal` needs `contractFreeze` \u2014 a charge points at a line of a frozen contract, and the contracts and the subscribers they are concluded with come from there.");
|
|
4271
|
+
}
|
|
4272
|
+
providers.push(asProvider(SUBSCRIBER_LEDGER_REPOSITORY_TOKEN, options.chargeJournal.ledgerRepository), SubscriberChargeService, SubscriberAccountService);
|
|
4273
|
+
}
|
|
3186
4274
|
if (options.tenantIdResolver) {
|
|
3187
4275
|
providers.push({
|
|
3188
4276
|
provide: TENANT_ID_RESOLVER_TOKEN,
|
|
@@ -3229,35 +4317,39 @@ var TenantBillingModule = class _TenantBillingModule {
|
|
|
3229
4317
|
...hasContractFreeze ? [
|
|
3230
4318
|
CONTRACT_FREEZE_PORT_TOKEN
|
|
3231
4319
|
] : [],
|
|
4320
|
+
...hasChargeJournal ? [
|
|
4321
|
+
SubscriberChargeService,
|
|
4322
|
+
SubscriberAccountService
|
|
4323
|
+
] : [],
|
|
3232
4324
|
...options.extraExports ?? []
|
|
3233
4325
|
]
|
|
3234
4326
|
};
|
|
3235
4327
|
}
|
|
3236
4328
|
};
|
|
3237
|
-
TenantBillingModule =
|
|
3238
|
-
|
|
4329
|
+
TenantBillingModule = _ts_decorate15([
|
|
4330
|
+
Module3({})
|
|
3239
4331
|
], TenantBillingModule);
|
|
3240
4332
|
|
|
3241
4333
|
// src/billing/subscription-bundle-preview.service.ts
|
|
3242
|
-
import { Inject as
|
|
4334
|
+
import { Inject as Inject10, Injectable as Injectable8, NotFoundException as NotFoundException4, Optional as Optional8 } from "@nestjs/common";
|
|
3243
4335
|
import { BILLING_ERROR_CODES as BILLING_ERROR_CODES4, CATALOG_ERROR_CODES as CATALOG_ERROR_CODES2, buildFeatureRequiresIndex as buildFeatureRequiresIndex2, collectUnsatisfiedRequires as collectUnsatisfiedRequires2 } from "@saasicat/core";
|
|
3244
|
-
function
|
|
4336
|
+
function _ts_decorate16(decorators, target, key, desc) {
|
|
3245
4337
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3246
4338
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
3247
4339
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
3248
4340
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3249
4341
|
}
|
|
3250
|
-
__name(
|
|
3251
|
-
function
|
|
4342
|
+
__name(_ts_decorate16, "_ts_decorate");
|
|
4343
|
+
function _ts_metadata13(k, v) {
|
|
3252
4344
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
3253
4345
|
}
|
|
3254
|
-
__name(
|
|
3255
|
-
function
|
|
4346
|
+
__name(_ts_metadata13, "_ts_metadata");
|
|
4347
|
+
function _ts_param10(paramIndex, decorator) {
|
|
3256
4348
|
return function(target, key) {
|
|
3257
4349
|
decorator(target, key, paramIndex);
|
|
3258
4350
|
};
|
|
3259
4351
|
}
|
|
3260
|
-
__name(
|
|
4352
|
+
__name(_ts_param10, "_ts_param");
|
|
3261
4353
|
var SubscriptionBundlePreviewService = class {
|
|
3262
4354
|
static {
|
|
3263
4355
|
__name(this, "SubscriptionBundlePreviewService");
|
|
@@ -3527,20 +4619,20 @@ var SubscriptionBundlePreviewService = class {
|
|
|
3527
4619
|
return collectUnsatisfiedRequires2(bundleVersion.features ?? [], requiresIndex).filter((key) => !covered.has(key));
|
|
3528
4620
|
}
|
|
3529
4621
|
};
|
|
3530
|
-
SubscriptionBundlePreviewService =
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
4622
|
+
SubscriptionBundlePreviewService = _ts_decorate16([
|
|
4623
|
+
Injectable8(),
|
|
4624
|
+
_ts_param10(0, Inject10(SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN)),
|
|
4625
|
+
_ts_param10(1, Inject10(BUNDLE_REPOSITORY_TOKEN)),
|
|
4626
|
+
_ts_param10(2, Optional8()),
|
|
4627
|
+
_ts_param10(2, Inject10(PLAN_REPOSITORY_TOKEN)),
|
|
4628
|
+
_ts_param10(3, Optional8()),
|
|
4629
|
+
_ts_param10(3, Inject10(CATALOG_ENTRY_REPOSITORY_TOKEN)),
|
|
4630
|
+
_ts_param10(4, Optional8()),
|
|
4631
|
+
_ts_param10(4, Inject10(SELF_SERVICE_BLOCKED_BUNDLES_TOKEN)),
|
|
4632
|
+
_ts_param10(5, Optional8()),
|
|
4633
|
+
_ts_param10(5, Inject10(SUBSCRIPTION_BUNDLE_CONFIG_TOKEN)),
|
|
4634
|
+
_ts_metadata13("design:type", Function),
|
|
4635
|
+
_ts_metadata13("design:paramtypes", [
|
|
3544
4636
|
typeof SubscriptionBundleRepository === "undefined" ? Object : SubscriptionBundleRepository,
|
|
3545
4637
|
typeof BundleRepository === "undefined" ? Object : BundleRepository,
|
|
3546
4638
|
Object,
|
|
@@ -3565,25 +4657,29 @@ function toSnapshot(bundleVersion) {
|
|
|
3565
4657
|
__name(toSnapshot, "toSnapshot");
|
|
3566
4658
|
|
|
3567
4659
|
// src/billing/tenant-subscription-bundles.controller.ts
|
|
3568
|
-
import { BadRequestException as BadRequestException2, Body as Body2, Controller as
|
|
4660
|
+
import { BadRequestException as BadRequestException2, Body as Body2, Controller as Controller4, Delete, Get as Get4, HttpCode as HttpCode2, HttpStatus as HttpStatus2, Inject as Inject11, Logger as Logger4, ConflictException as ConflictException2, NotFoundException as NotFoundException5, Optional as Optional9, Param as Param2, ParseUUIDPipe, Post as Post2, Req as Req2, UseGuards as UseGuards3 } from "@nestjs/common";
|
|
3569
4661
|
import { AUTH_ERROR_CODES as AUTH_ERROR_CODES3, BILLING_ERROR_CODES as BILLING_ERROR_CODES5 } from "@saasicat/core";
|
|
3570
|
-
function
|
|
4662
|
+
function _ts_decorate17(decorators, target, key, desc) {
|
|
3571
4663
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3572
4664
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
3573
4665
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
3574
4666
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3575
4667
|
}
|
|
3576
|
-
__name(
|
|
3577
|
-
function
|
|
4668
|
+
__name(_ts_decorate17, "_ts_decorate");
|
|
4669
|
+
function _ts_metadata14(k, v) {
|
|
3578
4670
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
3579
4671
|
}
|
|
3580
|
-
__name(
|
|
3581
|
-
function
|
|
4672
|
+
__name(_ts_metadata14, "_ts_metadata");
|
|
4673
|
+
function _ts_param11(paramIndex, decorator) {
|
|
3582
4674
|
return function(target, key) {
|
|
3583
4675
|
decorator(target, key, paramIndex);
|
|
3584
4676
|
};
|
|
3585
4677
|
}
|
|
3586
|
-
__name(
|
|
4678
|
+
__name(_ts_param11, "_ts_param");
|
|
4679
|
+
function planCycleOf2(sub) {
|
|
4680
|
+
return sub.billingCycle;
|
|
4681
|
+
}
|
|
4682
|
+
__name(planCycleOf2, "planCycleOf");
|
|
3587
4683
|
function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
3588
4684
|
let GeneratedTenantSubscriptionBundlesController = class GeneratedTenantSubscriptionBundlesController2 {
|
|
3589
4685
|
static {
|
|
@@ -3594,19 +4690,21 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3594
4690
|
subscriptionUsage;
|
|
3595
4691
|
tenantIdResolver;
|
|
3596
4692
|
contractFreeze;
|
|
3597
|
-
|
|
4693
|
+
charges;
|
|
4694
|
+
logger = new Logger4("TenantSubscriptionBundlesController");
|
|
3598
4695
|
/** Keeps the "no contractFreeze hook" warning to one line per process. */
|
|
3599
4696
|
static warnedAboutMissingFreeze = false;
|
|
3600
|
-
constructor(service, previewService, subscriptionUsage, tenantIdResolver, contractFreeze = null) {
|
|
4697
|
+
constructor(service, previewService, subscriptionUsage, tenantIdResolver, contractFreeze = null, charges = null) {
|
|
3601
4698
|
this.service = service;
|
|
3602
4699
|
this.previewService = previewService;
|
|
3603
4700
|
this.subscriptionUsage = subscriptionUsage;
|
|
3604
4701
|
this.tenantIdResolver = tenantIdResolver;
|
|
3605
4702
|
this.contractFreeze = contractFreeze;
|
|
4703
|
+
this.charges = charges;
|
|
3606
4704
|
}
|
|
3607
4705
|
async list(req) {
|
|
3608
4706
|
const sub = await this.requireSubscription(this.requireTenantId(req));
|
|
3609
|
-
return this.service.listForSubscription(this.requireSubscriptionPk(sub), sub.plan, sub
|
|
4707
|
+
return this.service.listForSubscription(this.requireSubscriptionPk(sub), sub.plan, planCycleOf2(sub));
|
|
3610
4708
|
}
|
|
3611
4709
|
/**
|
|
3612
4710
|
* List prices for the bundles the store is showing, resolved for this
|
|
@@ -3636,7 +4734,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3636
4734
|
// A bundle cannot commit past the subscription paying for it.
|
|
3637
4735
|
parentEndsAt: sub.canceledEffectiveAt ?? sub.canceledAt ?? null,
|
|
3638
4736
|
// And it runs in the plan's rhythm, on the plan's day.
|
|
3639
|
-
planCycle: sub
|
|
4737
|
+
planCycle: planCycleOf2(sub),
|
|
3640
4738
|
planPeriodEnd: sub.currentPeriodEnd ?? null,
|
|
3641
4739
|
// Resolved rather than passed through: a null here would let
|
|
3642
4740
|
// the arithmetic read the period END, which a short month has
|
|
@@ -3646,6 +4744,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3646
4744
|
billingCycle: dto.billingCycle
|
|
3647
4745
|
});
|
|
3648
4746
|
await this.refreezeContract(tenantId, sub);
|
|
4747
|
+
await recordChargesAfter(this.charges, tenantId, "an add-on booking", this.logger);
|
|
3649
4748
|
return result;
|
|
3650
4749
|
}
|
|
3651
4750
|
async preview(req, dto) {
|
|
@@ -3662,7 +4761,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3662
4761
|
subscriptionId: this.requireSubscriptionPk(sub),
|
|
3663
4762
|
// Plan KEY (compatibility.planIds is key-based) — not the planVersion UUID.
|
|
3664
4763
|
currentPlanKey: sub.plan,
|
|
3665
|
-
billingCycle: sub
|
|
4764
|
+
billingCycle: planCycleOf2(sub),
|
|
3666
4765
|
status: sub.status,
|
|
3667
4766
|
startedAt: sub.startedAt,
|
|
3668
4767
|
currentPeriodStart: sub.currentPeriodStart,
|
|
@@ -3772,7 +4871,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3772
4871
|
await this.contractFreeze.freezeOnPlanChange(
|
|
3773
4872
|
tenantId,
|
|
3774
4873
|
sub.planVersion.planId,
|
|
3775
|
-
sub
|
|
4874
|
+
planCycleOf2(sub),
|
|
3776
4875
|
/* @__PURE__ */ new Date(),
|
|
3777
4876
|
// Cancelling a bundle stays open on a cancelled
|
|
3778
4877
|
// subscription, and it re-freezes: the replacement contract
|
|
@@ -3784,93 +4883,96 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3784
4883
|
}
|
|
3785
4884
|
}
|
|
3786
4885
|
};
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
4886
|
+
_ts_decorate17([
|
|
4887
|
+
Get4(),
|
|
4888
|
+
_ts_param11(0, Req2()),
|
|
4889
|
+
_ts_metadata14("design:type", Function),
|
|
4890
|
+
_ts_metadata14("design:paramtypes", [
|
|
3792
4891
|
typeof RequestLike === "undefined" ? Object : RequestLike
|
|
3793
4892
|
]),
|
|
3794
|
-
|
|
4893
|
+
_ts_metadata14("design:returntype", Promise)
|
|
3795
4894
|
], GeneratedTenantSubscriptionBundlesController.prototype, "list", null);
|
|
3796
|
-
|
|
4895
|
+
_ts_decorate17([
|
|
3797
4896
|
Post2("prices"),
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
4897
|
+
_ts_param11(0, Req2()),
|
|
4898
|
+
_ts_param11(1, Body2()),
|
|
4899
|
+
_ts_metadata14("design:type", Function),
|
|
4900
|
+
_ts_metadata14("design:paramtypes", [
|
|
3802
4901
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3803
4902
|
typeof BundlePriceLookupDto === "undefined" ? Object : BundlePriceLookupDto
|
|
3804
4903
|
]),
|
|
3805
|
-
|
|
4904
|
+
_ts_metadata14("design:returntype", Promise)
|
|
3806
4905
|
], GeneratedTenantSubscriptionBundlesController.prototype, "prices", null);
|
|
3807
|
-
|
|
4906
|
+
_ts_decorate17([
|
|
3808
4907
|
Post2(),
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
4908
|
+
UseGuards3(TenantAdminGuard),
|
|
4909
|
+
_ts_param11(0, Req2()),
|
|
4910
|
+
_ts_param11(1, Body2()),
|
|
4911
|
+
_ts_metadata14("design:type", Function),
|
|
4912
|
+
_ts_metadata14("design:paramtypes", [
|
|
3814
4913
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3815
4914
|
typeof AddSubscriptionBundleDto === "undefined" ? Object : AddSubscriptionBundleDto
|
|
3816
4915
|
]),
|
|
3817
|
-
|
|
4916
|
+
_ts_metadata14("design:returntype", Promise)
|
|
3818
4917
|
], GeneratedTenantSubscriptionBundlesController.prototype, "add", null);
|
|
3819
|
-
|
|
4918
|
+
_ts_decorate17([
|
|
3820
4919
|
Post2("preview"),
|
|
3821
4920
|
HttpCode2(HttpStatus2.OK),
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
4921
|
+
_ts_param11(0, Req2()),
|
|
4922
|
+
_ts_param11(1, Body2()),
|
|
4923
|
+
_ts_metadata14("design:type", Function),
|
|
4924
|
+
_ts_metadata14("design:paramtypes", [
|
|
3826
4925
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3827
4926
|
typeof PreviewSubscriptionBundleDto === "undefined" ? Object : PreviewSubscriptionBundleDto
|
|
3828
4927
|
]),
|
|
3829
|
-
|
|
4928
|
+
_ts_metadata14("design:returntype", Promise)
|
|
3830
4929
|
], GeneratedTenantSubscriptionBundlesController.prototype, "preview", null);
|
|
3831
|
-
|
|
4930
|
+
_ts_decorate17([
|
|
3832
4931
|
Delete(":id"),
|
|
3833
|
-
|
|
4932
|
+
UseGuards3(TenantAdminGuard),
|
|
3834
4933
|
HttpCode2(HttpStatus2.OK),
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
4934
|
+
_ts_param11(0, Req2()),
|
|
4935
|
+
_ts_param11(1, Param2("id", new ParseUUIDPipe())),
|
|
4936
|
+
_ts_param11(2, Body2()),
|
|
4937
|
+
_ts_metadata14("design:type", Function),
|
|
4938
|
+
_ts_metadata14("design:paramtypes", [
|
|
3840
4939
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3841
4940
|
String,
|
|
3842
4941
|
typeof CancelSubscriptionBundleDto === "undefined" ? Object : CancelSubscriptionBundleDto
|
|
3843
4942
|
]),
|
|
3844
|
-
|
|
4943
|
+
_ts_metadata14("design:returntype", Promise)
|
|
3845
4944
|
], GeneratedTenantSubscriptionBundlesController.prototype, "cancel", null);
|
|
3846
|
-
|
|
4945
|
+
_ts_decorate17([
|
|
3847
4946
|
Post2(":id/reactivate"),
|
|
3848
|
-
|
|
4947
|
+
UseGuards3(TenantAdminGuard),
|
|
3849
4948
|
HttpCode2(HttpStatus2.OK),
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
4949
|
+
_ts_param11(0, Req2()),
|
|
4950
|
+
_ts_param11(1, Param2("id", new ParseUUIDPipe())),
|
|
4951
|
+
_ts_metadata14("design:type", Function),
|
|
4952
|
+
_ts_metadata14("design:paramtypes", [
|
|
3854
4953
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3855
4954
|
String
|
|
3856
4955
|
]),
|
|
3857
|
-
|
|
4956
|
+
_ts_metadata14("design:returntype", Promise)
|
|
3858
4957
|
], GeneratedTenantSubscriptionBundlesController.prototype, "reactivate", null);
|
|
3859
|
-
GeneratedTenantSubscriptionBundlesController =
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
4958
|
+
GeneratedTenantSubscriptionBundlesController = _ts_decorate17([
|
|
4959
|
+
Controller4("billing/subscription-bundles"),
|
|
4960
|
+
UseGuards3(ComposedTenantAuthGuard, ...extraGuards),
|
|
4961
|
+
_ts_param11(0, Inject11(SubscriptionBundlesService)),
|
|
4962
|
+
_ts_param11(1, Inject11(SubscriptionBundlePreviewService)),
|
|
4963
|
+
_ts_param11(2, Inject11(SUBSCRIPTION_USAGE_PORT_TOKEN)),
|
|
4964
|
+
_ts_param11(3, Inject11(TENANT_ID_RESOLVER_TOKEN)),
|
|
4965
|
+
_ts_param11(4, Optional9()),
|
|
4966
|
+
_ts_param11(4, Inject11(CONTRACT_FREEZE_PORT_TOKEN)),
|
|
4967
|
+
_ts_param11(5, Optional9()),
|
|
4968
|
+
_ts_param11(5, Inject11(SubscriberChargeService)),
|
|
4969
|
+
_ts_metadata14("design:type", Function),
|
|
4970
|
+
_ts_metadata14("design:paramtypes", [
|
|
3870
4971
|
typeof SubscriptionBundlesService === "undefined" ? Object : SubscriptionBundlesService,
|
|
3871
4972
|
typeof SubscriptionBundlePreviewService === "undefined" ? Object : SubscriptionBundlePreviewService,
|
|
3872
4973
|
typeof SubscriptionUsagePort === "undefined" ? Object : SubscriptionUsagePort,
|
|
3873
4974
|
typeof TenantIdResolver === "undefined" ? Object : TenantIdResolver,
|
|
4975
|
+
Object,
|
|
3874
4976
|
Object
|
|
3875
4977
|
])
|
|
3876
4978
|
], GeneratedTenantSubscriptionBundlesController);
|
|
@@ -3879,14 +4981,14 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3879
4981
|
__name(buildTenantSubscriptionBundlesController, "buildTenantSubscriptionBundlesController");
|
|
3880
4982
|
|
|
3881
4983
|
// src/billing/subscription-bundles.module.ts
|
|
3882
|
-
import { Module as
|
|
3883
|
-
function
|
|
4984
|
+
import { Module as Module4 } from "@nestjs/common";
|
|
4985
|
+
function _ts_decorate18(decorators, target, key, desc) {
|
|
3884
4986
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3885
4987
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
3886
4988
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
3887
4989
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3888
4990
|
}
|
|
3889
|
-
__name(
|
|
4991
|
+
__name(_ts_decorate18, "_ts_decorate");
|
|
3890
4992
|
var SubscriptionBundleModule = class _SubscriptionBundleModule {
|
|
3891
4993
|
static {
|
|
3892
4994
|
__name(this, "SubscriptionBundleModule");
|
|
@@ -3948,8 +5050,8 @@ var SubscriptionBundleModule = class _SubscriptionBundleModule {
|
|
|
3948
5050
|
};
|
|
3949
5051
|
}
|
|
3950
5052
|
};
|
|
3951
|
-
SubscriptionBundleModule =
|
|
3952
|
-
|
|
5053
|
+
SubscriptionBundleModule = _ts_decorate18([
|
|
5054
|
+
Module4({})
|
|
3953
5055
|
], SubscriptionBundleModule);
|
|
3954
5056
|
|
|
3955
5057
|
export {
|
|
@@ -3989,11 +5091,16 @@ export {
|
|
|
3989
5091
|
SELF_SERVICE_BLOCKED_PLANS_TOKEN,
|
|
3990
5092
|
SELF_SERVICE_BLOCKED_BUNDLES_TOKEN,
|
|
3991
5093
|
computeProration,
|
|
5094
|
+
computeNewPeriodCharge,
|
|
3992
5095
|
PlanChangePreviewService,
|
|
3993
5096
|
CONTRACT_FREEZE_PORT_TOKEN,
|
|
3994
5097
|
CONTRACT_FREEZE_SOURCE_PORT_TOKEN,
|
|
3995
5098
|
PendingPlanMaterializationService,
|
|
3996
5099
|
SubscriptionContractFreezeService,
|
|
5100
|
+
SUBSCRIBER_LEDGER_REPOSITORY_TOKEN,
|
|
5101
|
+
SubscriberAccountService,
|
|
5102
|
+
SubscriberAccountModule,
|
|
5103
|
+
SubscriberChargeService,
|
|
3997
5104
|
PreviewPlanChangeDto,
|
|
3998
5105
|
ChangePlanDto,
|
|
3999
5106
|
CancelSubscriptionDto,
|