@saasicat/nest 1.0.0-rc.2 → 1.0.0-rc.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -8
- package/dist/.build-stamp +1 -1
- package/dist/_entries.cjs +10214 -4796
- package/dist/admin/index.d.cts +5 -4
- package/dist/admin/index.d.ts +5 -4
- package/dist/admin/index.js +13 -9
- package/dist/{admin-resources.module-CpvzcfCc.d.cts → admin-resources.module-B4XNvdH-.d.cts} +1 -2
- package/dist/{admin-resources.module-DF5_Q7RD.d.ts → admin-resources.module-CWqdI9BV.d.ts} +1 -2
- package/dist/{admin-stats.service-TYiSUwIR.d.ts → admin-stats.service-CsLNt19Z.d.ts} +11 -7
- package/dist/{admin-stats.service-DfKupywR.d.cts → admin-stats.service-DrZrU8IJ.d.cts} +11 -7
- package/dist/{aggregation-B3CD0v_d.d.cts → aggregation-ChpZDh0g.d.ts} +39 -6
- package/dist/{aggregation-BFzW07DE.d.ts → aggregation-OpnhwzF5.d.cts} +39 -6
- package/dist/billing/index.d.cts +448 -108
- package/dist/billing/index.d.ts +448 -108
- package/dist/billing/index.js +108 -41
- package/dist/catalog/index.d.cts +74 -45
- package/dist/catalog/index.d.ts +74 -45
- package/dist/catalog/index.js +21 -13
- package/dist/catalog.module-C9O7BxRq.d.ts +180 -0
- package/dist/catalog.module-T-I5Ricz.d.cts +180 -0
- package/dist/checkout-offer/index.d.cts +17 -22
- package/dist/checkout-offer/index.d.ts +17 -22
- package/dist/checkout-offer/index.js +21 -7
- package/dist/checkout-offer.module-DFhGy6JO.d.cts +58 -0
- package/dist/checkout-offer.module-x7SP_dX4.d.ts +58 -0
- package/dist/checkout-offer.service-BeHgYikI.d.ts +242 -0
- package/dist/checkout-offer.service-CCVxG9b2.d.cts +242 -0
- package/dist/chunk-34XVPR6P.js +222 -0
- package/dist/{chunk-AOQJEYOL.js → chunk-3QVGA6JX.js} +3 -1
- package/dist/chunk-3RLWML2S.js +896 -0
- package/dist/{chunk-TXC3LHHB.js → chunk-4SDSYV4A.js} +21 -13
- package/dist/chunk-55QEDAMX.js +946 -0
- package/dist/chunk-5CKC7O52.js +140 -0
- package/dist/chunk-6PJE7EWO.js +185 -0
- package/dist/chunk-7NJKVC5X.js +353 -0
- package/dist/{chunk-RUNZ3X4C.js → chunk-AOS2JPDD.js} +1263 -185
- package/dist/{chunk-WOVQPXV4.js → chunk-CQ2ZZMTD.js} +702 -725
- package/dist/{chunk-NA6O63B7.js → chunk-F5X66HF5.js} +5 -5
- package/dist/chunk-FEQZCWUL.js +174 -0
- package/dist/{chunk-VIJ5NJWC.js → chunk-G6EZWECL.js} +107 -31
- package/dist/chunk-G7RQO2XO.js +0 -0
- package/dist/{chunk-N3L3AICU.js → chunk-GPQWGA6B.js} +5 -6
- package/dist/chunk-GZTL64QK.js +7 -0
- package/dist/{chunk-SABTXESR.js → chunk-J7NJRK3K.js} +17 -1
- package/dist/{chunk-SEPN52AD.js → chunk-JBCC6C3M.js} +566 -307
- package/dist/{chunk-I7GTA3RX.js → chunk-JQRA724W.js} +1 -1
- package/dist/{chunk-WXYJHZCN.js → chunk-JVAEKTJ4.js} +2 -14
- package/dist/chunk-KPEMTBOP.js +26 -0
- package/dist/chunk-LF6J4YYN.js +301 -0
- package/dist/{chunk-LTT736P3.js → chunk-LLYVYRGJ.js} +228 -387
- package/dist/{chunk-6Z7JR4EW.js → chunk-M47BNEY2.js} +1897 -633
- package/dist/{chunk-KFT5AIIH.js → chunk-NDLC5GYK.js} +206 -24
- package/dist/{chunk-O2J2HDXA.js → chunk-OOTEXP47.js} +3 -8
- package/dist/chunk-QPVDCKYS.js +702 -0
- package/dist/{chunk-NHVDCYK5.js → chunk-R5YCJBHY.js} +71 -106
- package/dist/{chunk-XBYAFEOR.js → chunk-S33SO5XX.js} +1 -1
- package/dist/chunk-SZ7RFPXA.js +10 -0
- package/dist/chunk-TBBZWZQT.js +98 -0
- package/dist/chunk-TOEFN7DN.js +295 -0
- package/dist/{chunk-7ZEGFL42.js → chunk-WHJSYKNC.js} +6 -6
- package/dist/chunk-WOEJ6K7M.js +55 -0
- package/dist/{chunk-AU3OOREM.js → chunk-XSSWYPP5.js} +16 -3
- package/dist/contract-line-item-money-B0Z3Ogur.d.cts +43 -0
- package/dist/contract-line-item-money-B0Z3Ogur.d.ts +43 -0
- package/dist/discovery/index.d.cts +2 -2
- package/dist/discovery/index.d.ts +2 -2
- package/dist/discovery/index.js +6 -6
- package/dist/{discovery.scanner-9cMqF95o.d.cts → discovery.scanner-DXKc6JkV.d.cts} +1 -1
- package/dist/{discovery.scanner-9cMqF95o.d.ts → discovery.scanner-DXKc6JkV.d.ts} +1 -1
- package/dist/{enforce-quota.interceptor-Df0e3OWe.d.cts → enforce-quota.interceptor-BFyVdWe8.d.cts} +6 -6
- package/dist/{enforce-quota.interceptor-DW3etVyI.d.ts → enforce-quota.interceptor-GaBXboGx.d.ts} +6 -6
- package/dist/entitlement/index.d.cts +27 -4
- package/dist/entitlement/index.d.ts +27 -4
- package/dist/entitlement/index.js +13 -8
- package/dist/index.d.cts +209 -28
- package/dist/index.d.ts +209 -28
- package/dist/index.js +285 -163
- package/dist/issuer-identity.check-CBO0vcsq.d.cts +197 -0
- package/dist/issuer-identity.check-Cz9CEMkZ.d.ts +197 -0
- package/dist/{module-options-COSEb0VW.d.ts → module-options-DmQ3G4sZ.d.ts} +135 -41
- package/dist/{module-options-BG3MzQva.d.cts → module-options-qAOwinHR.d.cts} +135 -41
- package/dist/payment-callback.service-CR84Xw1Z.d.cts +125 -0
- package/dist/payment-callback.service-CR84Xw1Z.d.ts +125 -0
- package/dist/payments/index.cjs +4 -0
- package/dist/payments/index.d.cts +187 -0
- package/dist/payments/index.d.ts +187 -0
- package/dist/payments/index.js +141 -0
- package/dist/payments.module-BdUq9ot_.d.cts +57 -0
- package/dist/payments.module-CQGv_VG7.d.ts +57 -0
- package/dist/plan-catalog-source-DWe-BGY1.d.cts +21 -0
- package/dist/plan-catalog-source-DWe-BGY1.d.ts +21 -0
- package/dist/{plan-resolution-Cgo_TR1H.d.cts → plan-resolution-CwUy_OqC.d.cts} +14 -0
- package/dist/{plan-resolution-Cgo_TR1H.d.ts → plan-resolution-CwUy_OqC.d.ts} +14 -0
- package/dist/{plan-versions.service-DChhbK6h.d.ts → plan-versions.service-C0N-Em2W.d.ts} +38 -64
- package/dist/{plan-versions.service-TPEtbN0r.d.cts → plan-versions.service-DARLh-qI.d.cts} +38 -64
- package/dist/platform/index.d.cts +52 -23
- package/dist/platform/index.d.ts +52 -23
- package/dist/platform/index.js +57 -36
- package/dist/promo/index.d.cts +23 -8
- package/dist/promo/index.d.ts +23 -8
- package/dist/promo/index.js +15 -7
- package/dist/{promo.module-DtvIycpt.d.cts → promo.module-CKkECmU8.d.cts} +9 -3
- package/dist/{promo.module-Z8h1PNX-.d.ts → promo.module-DuIJdK3U.d.ts} +9 -3
- package/dist/promo.service-BYBu6dy3.d.cts +215 -0
- package/dist/promo.service-CFjfF0Xm.d.ts +215 -0
- package/dist/registration/index.d.cts +104 -47
- package/dist/registration/index.d.ts +104 -47
- package/dist/registration/index.js +15 -9
- package/dist/subscriber/index.cjs +4 -0
- package/dist/subscriber/index.d.cts +28 -0
- package/dist/subscriber/index.d.ts +28 -0
- package/dist/subscriber/index.js +16 -0
- package/dist/subscriber.service-5W6Gi-1B.d.cts +68 -0
- package/dist/subscriber.service-5W6Gi-1B.d.ts +68 -0
- package/dist/subscription-contract/index.d.cts +4 -2
- package/dist/subscription-contract/index.d.ts +4 -2
- package/dist/subscription-contract/index.js +13 -5
- package/dist/{subscription-contract.module-fDFdQ0jm.d.ts → subscription-contract.module-BfIRpc1o.d.ts} +8 -2
- package/dist/{subscription-contract.module-CEK8HS5-.d.cts → subscription-contract.module-DTMuUJYd.d.cts} +8 -2
- package/dist/{subscription-contract.service-hD87MKyg.d.cts → subscription-contract.service-CPZrTM9C.d.ts} +32 -3
- package/dist/{subscription-contract.service-hD87MKyg.d.ts → subscription-contract.service-CfNApLuP.d.cts} +32 -3
- package/dist/tenant-billing.controller-BLqbsONe.d.ts +812 -0
- package/dist/tenant-billing.controller-DKbAqTbM.d.cts +812 -0
- package/dist/tenant-billing.module-ClbjzocC.d.cts +364 -0
- package/dist/tenant-billing.module-DohgJJ2m.d.ts +364 -0
- package/dist/tenant-billing.tokens-G-1xOlMr.d.cts +129 -0
- package/dist/tenant-billing.tokens-G-1xOlMr.d.ts +129 -0
- package/dist/testing/index.d.cts +44 -17
- package/dist/testing/index.d.ts +44 -17
- package/dist/testing/index.js +189 -40
- package/package.json +24 -4
- package/dist/catalog.module-BDDO6iwq.d.cts +0 -103
- package/dist/catalog.module-BTnMsE6u.d.ts +0 -103
- package/dist/checkout-offer.module-CMtiQJTT.d.ts +0 -39
- package/dist/checkout-offer.module-CVpWrzbe.d.cts +0 -39
- package/dist/checkout-offer.service-BLOv2HOo.d.cts +0 -49
- package/dist/checkout-offer.service-BLOv2HOo.d.ts +0 -49
- package/dist/chunk-57V6ZTI6.js +0 -22
- package/dist/chunk-BSK6YBLI.js +0 -87
- package/dist/chunk-DQKCK7DX.js +0 -217
- package/dist/chunk-VXEYLNIB.js +0 -632
- package/dist/chunk-WUDYIPYH.js +0 -715
- package/dist/define-saasicat-DROBe-b1.d.ts +0 -69
- package/dist/define-saasicat-vGBCkFys.d.cts +0 -69
- package/dist/promo.service-BJbKAmw3.d.cts +0 -112
- package/dist/promo.service-BJbKAmw3.d.ts +0 -112
- package/dist/tenant-billing.controller-BQ67mlmI.d.ts +0 -438
- package/dist/tenant-billing.controller-DS8kB8a7.d.cts +0 -438
- package/dist/tenant-billing.module-BznC3XtW.d.cts +0 -299
- package/dist/tenant-billing.module-wUbsQSFG.d.ts +0 -299
- /package/dist/{chunk-2FR6ZL7R.js → chunk-BHZOH2DY.js} +0 -0
- /package/dist/{chunk-2SLTRKXC.js → chunk-DFOW3JVO.js} +0 -0
- /package/dist/{chunk-DBZGV3HC.js → chunk-DU56UKEH.js} +0 -0
- /package/dist/{chunk-OYNHOY45.js → chunk-GAUEVIAE.js} +0 -0
|
@@ -13,6 +13,7 @@ import { mkdirSync, writeFileSync } from "fs";
|
|
|
13
13
|
import { dirname } from "path";
|
|
14
14
|
import { Inject, Injectable, Logger, Optional } from "@nestjs/common";
|
|
15
15
|
import { DiscoveryService, MetadataScanner, Reflector } from "@nestjs/core";
|
|
16
|
+
import { canonicalJson } from "@saasicat/core";
|
|
16
17
|
function _ts_decorate(decorators, target, key, desc) {
|
|
17
18
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
18
19
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -288,23 +289,10 @@ function computeSnapshotHash(snapshot) {
|
|
|
288
289
|
features: snapshot.features,
|
|
289
290
|
quotas: snapshot.quotas
|
|
290
291
|
};
|
|
291
|
-
const json =
|
|
292
|
+
const json = canonicalJson(stableInput);
|
|
292
293
|
return `sha256-${createHash("sha256").update(json).digest("hex")}`;
|
|
293
294
|
}
|
|
294
295
|
__name(computeSnapshotHash, "computeSnapshotHash");
|
|
295
|
-
function canonicalStringify(value) {
|
|
296
|
-
return JSON.stringify(value, (_key, val) => {
|
|
297
|
-
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
298
|
-
const sorted = {};
|
|
299
|
-
for (const k of Object.keys(val).sort()) {
|
|
300
|
-
sorted[k] = val[k];
|
|
301
|
-
}
|
|
302
|
-
return sorted;
|
|
303
|
-
}
|
|
304
|
-
return val;
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
__name(canonicalStringify, "canonicalStringify");
|
|
308
296
|
|
|
309
297
|
export {
|
|
310
298
|
DISCOVERY_APP_INFO_TOKEN,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-SHUYVCID.js";
|
|
4
|
+
|
|
5
|
+
// src/billing/bundle-price.ts
|
|
6
|
+
function resolveBundlePriceNet(bundleVersion, planKey, billingCycle) {
|
|
7
|
+
const override = (bundleVersion.pricingOverrides ?? []).find((o) => o.planId === planKey);
|
|
8
|
+
const yearly = billingCycle === "YEARLY";
|
|
9
|
+
const raw = yearly ? override?.yearlyNet !== void 0 ? override.yearlyNet : bundleVersion.yearlyNet : override?.monthlyNet !== void 0 ? override.monthlyNet : bundleVersion.monthlyNet;
|
|
10
|
+
if (raw === null || raw === void 0) return null;
|
|
11
|
+
const parsed = Number.parseFloat(raw);
|
|
12
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
13
|
+
}
|
|
14
|
+
__name(resolveBundlePriceNet, "resolveBundlePriceNet");
|
|
15
|
+
function cyclesSoldFor(planVersion) {
|
|
16
|
+
const cycles = [];
|
|
17
|
+
if (planVersion.monthlyNet != null) cycles.push("MONTHLY");
|
|
18
|
+
if (planVersion.yearlyNet != null) cycles.push("YEARLY");
|
|
19
|
+
return cycles;
|
|
20
|
+
}
|
|
21
|
+
__name(cyclesSoldFor, "cyclesSoldFor");
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
resolveBundlePriceNet,
|
|
25
|
+
cyclesSoldFor
|
|
26
|
+
};
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PLAN_CATALOG_SETTINGS_TOKEN
|
|
3
|
+
} from "./chunk-FEQZCWUL.js";
|
|
4
|
+
import {
|
|
5
|
+
codedError
|
|
6
|
+
} from "./chunk-J7NJRK3K.js";
|
|
7
|
+
import {
|
|
8
|
+
__name
|
|
9
|
+
} from "./chunk-SHUYVCID.js";
|
|
10
|
+
|
|
11
|
+
// src/subscriber/subscriber.tokens.ts
|
|
12
|
+
var SUBSCRIBER_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SubscriberRepository");
|
|
13
|
+
|
|
14
|
+
// src/subscriber/subscriber.service.ts
|
|
15
|
+
import { ConflictException, Inject, Injectable, NotFoundException, UnprocessableEntityException as UnprocessableEntityException2 } from "@nestjs/common";
|
|
16
|
+
import { SUBSCRIBER_ERROR_CODES as SUBSCRIBER_ERROR_CODES2, contractPartiesOf } from "@saasicat/core";
|
|
17
|
+
|
|
18
|
+
// src/subscriber/subscriber-details.ts
|
|
19
|
+
import { UnprocessableEntityException } from "@nestjs/common";
|
|
20
|
+
import { SUBSCRIBER_ERROR_CODES, LEGAL_IDENTITY_FIELDS } from "@saasicat/core";
|
|
21
|
+
var COUNTRY_CODE = /^[A-Z]{2}$/;
|
|
22
|
+
var MAX_EMAIL_LENGTH = 254;
|
|
23
|
+
var INVOICE_ADDRESS_FIELDS = [
|
|
24
|
+
"addressLine1",
|
|
25
|
+
"postalCode",
|
|
26
|
+
"city",
|
|
27
|
+
"country"
|
|
28
|
+
];
|
|
29
|
+
var CONTACT_FIELDS = [
|
|
30
|
+
"addressLine1",
|
|
31
|
+
"addressLine2",
|
|
32
|
+
"postalCode",
|
|
33
|
+
"city",
|
|
34
|
+
"country",
|
|
35
|
+
"invoiceEmail"
|
|
36
|
+
];
|
|
37
|
+
function settleNewSubscriberDetails(details) {
|
|
38
|
+
return {
|
|
39
|
+
legalName: settleLegalName(details.legalName),
|
|
40
|
+
vatId: settleText("vatId", details.vatId),
|
|
41
|
+
taxNumber: settleText("taxNumber", details.taxNumber),
|
|
42
|
+
...settleContact(details, CONTACT_FIELDS)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
__name(settleNewSubscriberDetails, "settleNewSubscriberDetails");
|
|
46
|
+
function settleContactChange(change) {
|
|
47
|
+
const identity = LEGAL_IDENTITY_FIELDS.find((field) => change[field] !== void 0);
|
|
48
|
+
if (identity) {
|
|
49
|
+
throw new UnprocessableEntityException(codedError(SUBSCRIBER_ERROR_CODES.SUBSCRIBER_IDENTITY_NOT_A_CONTACT, {
|
|
50
|
+
field: identity
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
const named = CONTACT_FIELDS.filter((field) => change[field] !== void 0);
|
|
54
|
+
return settleContact(change, named);
|
|
55
|
+
}
|
|
56
|
+
__name(settleContactChange, "settleContactChange");
|
|
57
|
+
function settleIdentityCorrection(correction) {
|
|
58
|
+
const values = {};
|
|
59
|
+
for (const field of LEGAL_IDENTITY_FIELDS) {
|
|
60
|
+
if (correction[field] === void 0) continue;
|
|
61
|
+
values[field] = settleIdentityValue(field, correction[field]);
|
|
62
|
+
}
|
|
63
|
+
return values;
|
|
64
|
+
}
|
|
65
|
+
__name(settleIdentityCorrection, "settleIdentityCorrection");
|
|
66
|
+
function settleIdentityValue(field, value) {
|
|
67
|
+
return field === "legalName" ? settleLegalName(value) : settleText(field, value);
|
|
68
|
+
}
|
|
69
|
+
__name(settleIdentityValue, "settleIdentityValue");
|
|
70
|
+
function settleLegalName(value) {
|
|
71
|
+
const legalName = settleText("legalName", value);
|
|
72
|
+
if (legalName === null) {
|
|
73
|
+
throw new UnprocessableEntityException(codedError(SUBSCRIBER_ERROR_CODES.SUBSCRIBER_LEGAL_NAME_REQUIRED));
|
|
74
|
+
}
|
|
75
|
+
return legalName;
|
|
76
|
+
}
|
|
77
|
+
__name(settleLegalName, "settleLegalName");
|
|
78
|
+
function settleContact(source, fields) {
|
|
79
|
+
const contact = {};
|
|
80
|
+
for (const field of fields) {
|
|
81
|
+
contact[field] = settleContactValue(field, source[field]);
|
|
82
|
+
}
|
|
83
|
+
return contact;
|
|
84
|
+
}
|
|
85
|
+
__name(settleContact, "settleContact");
|
|
86
|
+
function settleContactValue(field, value) {
|
|
87
|
+
const text = settleText(field, value);
|
|
88
|
+
if (text === null) return null;
|
|
89
|
+
if (field === "country") {
|
|
90
|
+
const country = text.toUpperCase();
|
|
91
|
+
if (!COUNTRY_CODE.test(country)) throw invalid(field);
|
|
92
|
+
return country;
|
|
93
|
+
}
|
|
94
|
+
if (field === "invoiceEmail" && !isEmailShaped(text)) throw invalid(field);
|
|
95
|
+
return text;
|
|
96
|
+
}
|
|
97
|
+
__name(settleContactValue, "settleContactValue");
|
|
98
|
+
function settleText(field, value) {
|
|
99
|
+
if (value === void 0 || value === null) return null;
|
|
100
|
+
if (typeof value !== "string") throw invalid(field);
|
|
101
|
+
const trimmed = value.trim();
|
|
102
|
+
return trimmed === "" ? null : trimmed;
|
|
103
|
+
}
|
|
104
|
+
__name(settleText, "settleText");
|
|
105
|
+
function isEmailShaped(value) {
|
|
106
|
+
if (value.length > MAX_EMAIL_LENGTH) return false;
|
|
107
|
+
const at = value.indexOf("@");
|
|
108
|
+
if (at <= 0 || at !== value.lastIndexOf("@")) return false;
|
|
109
|
+
const domain = value.slice(at + 1);
|
|
110
|
+
const dot = domain.lastIndexOf(".");
|
|
111
|
+
if (dot <= 0 || dot === domain.length - 1) return false;
|
|
112
|
+
return !/\s/.test(value);
|
|
113
|
+
}
|
|
114
|
+
__name(isEmailShaped, "isEmailShaped");
|
|
115
|
+
function invalid(field) {
|
|
116
|
+
return new UnprocessableEntityException(codedError(SUBSCRIBER_ERROR_CODES.SUBSCRIBER_DETAIL_INVALID, {
|
|
117
|
+
field
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
__name(invalid, "invalid");
|
|
121
|
+
|
|
122
|
+
// src/subscriber/subscriber.service.ts
|
|
123
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
124
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
125
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
126
|
+
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;
|
|
127
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
128
|
+
}
|
|
129
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
130
|
+
function _ts_metadata(k, v) {
|
|
131
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
132
|
+
}
|
|
133
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
134
|
+
function _ts_param(paramIndex, decorator) {
|
|
135
|
+
return function(target, key) {
|
|
136
|
+
decorator(target, key, paramIndex);
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
__name(_ts_param, "_ts_param");
|
|
140
|
+
var KEPT_BY_A_TENANT = [
|
|
141
|
+
...INVOICE_ADDRESS_FIELDS,
|
|
142
|
+
"invoiceEmail"
|
|
143
|
+
];
|
|
144
|
+
var SubscriberService = class {
|
|
145
|
+
static {
|
|
146
|
+
__name(this, "SubscriberService");
|
|
147
|
+
}
|
|
148
|
+
repo;
|
|
149
|
+
settings;
|
|
150
|
+
constructor(repo, settings) {
|
|
151
|
+
this.repo = repo;
|
|
152
|
+
this.settings = settings;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Creates the tenant's subscriber and assigns its customer number, behind
|
|
156
|
+
* the prefix `config/saas.yaml` names. With `tx` it is written on that
|
|
157
|
+
* transaction and undone with it — pass the one the tenant is created on.
|
|
158
|
+
*
|
|
159
|
+
* Refused with `SUBSCRIBER_ALREADY_EXISTS` when the tenant has one: a second
|
|
160
|
+
* party for the same tenant is not a correction of the first.
|
|
161
|
+
*/
|
|
162
|
+
async createForTenant(tenantId, details, tx) {
|
|
163
|
+
const settled = settleNewSubscriberDetails(details);
|
|
164
|
+
const created = await this.repo.createForTenant({
|
|
165
|
+
...settled,
|
|
166
|
+
tenantId,
|
|
167
|
+
customerNumberPrefix: this.settings.subscribers?.customerNumberPrefix ?? ""
|
|
168
|
+
}, tx);
|
|
169
|
+
if (!created) {
|
|
170
|
+
throw new ConflictException(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_ALREADY_EXISTS, {
|
|
171
|
+
tenantId
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
return created;
|
|
175
|
+
}
|
|
176
|
+
/** The tenant's subscriber, or `null` when it has none. */
|
|
177
|
+
findByTenantId(tenantId, tx) {
|
|
178
|
+
return this.repo.findByTenantId(tenantId, tx);
|
|
179
|
+
}
|
|
180
|
+
/** The tenant's subscriber, refused with `SUBSCRIBER_REQUIRED` when it has none. */
|
|
181
|
+
async requireForTenant(tenantId, tx) {
|
|
182
|
+
const subscriber = await this.repo.findByTenantId(tenantId, tx);
|
|
183
|
+
if (!subscriber) throw subscriberRequired(tenantId);
|
|
184
|
+
return subscriber;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Who a contract concluded for this tenant now is between: its subscriber
|
|
188
|
+
* as the record stands, and the issuer as the running configuration names
|
|
189
|
+
* it. Refused with `SUBSCRIBER_REQUIRED` when the tenant has no subscriber.
|
|
190
|
+
*/
|
|
191
|
+
async contractPartiesFor(tenantId, tx) {
|
|
192
|
+
const subscriber = await this.requireForTenant(tenantId, tx);
|
|
193
|
+
return contractPartiesOf(subscriber, this.settings.issuer);
|
|
194
|
+
}
|
|
195
|
+
async getById(subscriberId) {
|
|
196
|
+
const subscriber = await this.repo.findById(subscriberId);
|
|
197
|
+
if (!subscriber) throw subscriberNotFound(subscriberId);
|
|
198
|
+
return subscriber;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Changes how the subscriber is reached — the address, the country, the
|
|
202
|
+
* invoice email — at any time. A contract keeps the copy it was concluded
|
|
203
|
+
* with; what comes later reads the new details. The legal name and the tax
|
|
204
|
+
* identifiers are refused here: they change by `correctIdentity`.
|
|
205
|
+
*/
|
|
206
|
+
async changeContact(subscriberId, change) {
|
|
207
|
+
return this.writeContact(subscriberId, settleContactChange(change));
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* A tenant's own change of how its subscriber is reached, from its billing
|
|
211
|
+
* area. The address and the invoice email can be changed but not cleared —
|
|
212
|
+
* `SUBSCRIBER_DETAIL_INVALID` names the field — since without them nothing
|
|
213
|
+
* can be invoiced. The legal name and the tax identifiers are refused as
|
|
214
|
+
* with `changeContact`: they are the party, and only the operator corrects
|
|
215
|
+
* them.
|
|
216
|
+
*/
|
|
217
|
+
async changeContactOfTenant(tenantId, change) {
|
|
218
|
+
const subscriber = await this.requireForTenant(tenantId);
|
|
219
|
+
const settled = settleContactChange(change);
|
|
220
|
+
const cleared = KEPT_BY_A_TENANT.find((field) => settled[field] === null);
|
|
221
|
+
if (cleared) {
|
|
222
|
+
throw new UnprocessableEntityException2(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_DETAIL_INVALID, {
|
|
223
|
+
field: cleared
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
return this.writeContact(subscriber.id, settled);
|
|
227
|
+
}
|
|
228
|
+
/** Writes contact details already settled; settling twice would check one copy and write another. */
|
|
229
|
+
async writeContact(subscriberId, settled) {
|
|
230
|
+
const updated = await this.repo.updateContact(subscriberId, settled);
|
|
231
|
+
if (!updated) throw subscriberNotFound(subscriberId);
|
|
232
|
+
return updated;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Corrects the legal identity of the same legal entity — a misspelt name, a
|
|
236
|
+
* wrong tax identifier, a change of name that entity went through — and
|
|
237
|
+
* records the values it replaced, the reason and who made it. A contract
|
|
238
|
+
* keeps the copy it was concluded with.
|
|
239
|
+
*
|
|
240
|
+
* The operator declares what the change is, because nothing here can tell:
|
|
241
|
+
* another legal entity taking over is a transfer, and is refused with
|
|
242
|
+
* `SUBSCRIBER_TAKEOVER_IS_A_TRANSFER` rather than recorded as an edit.
|
|
243
|
+
*/
|
|
244
|
+
async correctIdentity(subscriberId, correction) {
|
|
245
|
+
if (correction.kind !== "correction") {
|
|
246
|
+
throw new UnprocessableEntityException2(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_TAKEOVER_IS_A_TRANSFER));
|
|
247
|
+
}
|
|
248
|
+
const reason = typeof correction.reason === "string" ? correction.reason.trim() : "";
|
|
249
|
+
if (reason === "") {
|
|
250
|
+
throw new UnprocessableEntityException2(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_CORRECTION_REASON_REQUIRED));
|
|
251
|
+
}
|
|
252
|
+
const correctedBy = typeof correction.correctedBy === "string" ? correction.correctedBy.trim() : "";
|
|
253
|
+
if (correctedBy === "") {
|
|
254
|
+
throw new UnprocessableEntityException2(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_CORRECTION_ACTOR_REQUIRED));
|
|
255
|
+
}
|
|
256
|
+
const result = await this.repo.correctIdentity(subscriberId, {
|
|
257
|
+
corrected: settleIdentityCorrection(correction),
|
|
258
|
+
reason,
|
|
259
|
+
correctedBy,
|
|
260
|
+
correctedAt: /* @__PURE__ */ new Date()
|
|
261
|
+
});
|
|
262
|
+
if (!result) throw subscriberNotFound(subscriberId);
|
|
263
|
+
if (!result.correction) {
|
|
264
|
+
throw new UnprocessableEntityException2(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_CORRECTION_CHANGES_NOTHING));
|
|
265
|
+
}
|
|
266
|
+
return result.correction;
|
|
267
|
+
}
|
|
268
|
+
/** Every correction of the subscriber's legal identity, the latest first. */
|
|
269
|
+
listCorrections(subscriberId) {
|
|
270
|
+
return this.repo.listCorrections(subscriberId);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
SubscriberService = _ts_decorate([
|
|
274
|
+
Injectable(),
|
|
275
|
+
_ts_param(0, Inject(SUBSCRIBER_REPOSITORY_TOKEN)),
|
|
276
|
+
_ts_param(1, Inject(PLAN_CATALOG_SETTINGS_TOKEN)),
|
|
277
|
+
_ts_metadata("design:type", Function),
|
|
278
|
+
_ts_metadata("design:paramtypes", [
|
|
279
|
+
typeof SubscriberRepository === "undefined" ? Object : SubscriberRepository,
|
|
280
|
+
typeof PlanCatalogSettings === "undefined" ? Object : PlanCatalogSettings
|
|
281
|
+
])
|
|
282
|
+
], SubscriberService);
|
|
283
|
+
function subscriberRequired(tenantId) {
|
|
284
|
+
return new ConflictException(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_REQUIRED, {
|
|
285
|
+
tenantId
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
__name(subscriberRequired, "subscriberRequired");
|
|
289
|
+
function subscriberNotFound(subscriberId) {
|
|
290
|
+
return new NotFoundException(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_NOT_FOUND, {
|
|
291
|
+
subscriberId
|
|
292
|
+
}));
|
|
293
|
+
}
|
|
294
|
+
__name(subscriberNotFound, "subscriberNotFound");
|
|
295
|
+
|
|
296
|
+
export {
|
|
297
|
+
INVOICE_ADDRESS_FIELDS,
|
|
298
|
+
settleNewSubscriberDetails,
|
|
299
|
+
SUBSCRIBER_REPOSITORY_TOKEN,
|
|
300
|
+
SubscriberService
|
|
301
|
+
};
|