@saasicat/core 1.0.0-rc.15 → 1.0.0-rc.16
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/index.cjs +193 -0
- package/dist/index.d.cts +369 -10
- package/dist/index.d.ts +369 -10
- package/dist/index.js +184 -0
- package/package.json +1 -1
package/dist/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
ac1a4c0280cf9333a264b4d84b290ab32ab44dd67287ec6d1abd99c01bc863b9
|
package/dist/index.cjs
CHANGED
|
@@ -49,6 +49,8 @@ __export(index_exports, {
|
|
|
49
49
|
REGISTRATION_STEP_BY_STATUS: () => REGISTRATION_STEP_BY_STATUS,
|
|
50
50
|
SETTINGS_ERROR_CODES: () => SETTINGS_ERROR_CODES,
|
|
51
51
|
SETUP_ERROR_CODES: () => SETUP_ERROR_CODES,
|
|
52
|
+
SUBSCRIBER_ERROR_CODES: () => SUBSCRIBER_ERROR_CODES,
|
|
53
|
+
SUBSCRIBER_IDENTITY_FIELDS: () => SUBSCRIBER_IDENTITY_FIELDS,
|
|
52
54
|
applyPromo: () => applyPromo,
|
|
53
55
|
assertPersistenceCapabilities: () => assertPersistenceCapabilities,
|
|
54
56
|
buildActivePlanVersionWhere: () => buildActivePlanVersionWhere,
|
|
@@ -60,16 +62,20 @@ __export(index_exports, {
|
|
|
60
62
|
classifyBundleVersionDiff: () => classifyBundleVersionDiff,
|
|
61
63
|
classifyPlanDiff: () => classifyPlanDiff,
|
|
62
64
|
collectUnsatisfiedRequires: () => collectUnsatisfiedRequires,
|
|
65
|
+
contractPartiesOf: () => contractPartiesOf,
|
|
63
66
|
coverageExcludingSelf: () => coverageExcludingSelf,
|
|
64
67
|
definedFields: () => definedFields,
|
|
65
68
|
diffSettings: () => diffSettings,
|
|
69
|
+
formatCustomerNumber: () => formatCustomerNumber,
|
|
66
70
|
formatErrorMessage: () => formatErrorMessage,
|
|
71
|
+
identityCorrectionDelta: () => identityCorrectionDelta,
|
|
67
72
|
isBundleRedundant: () => isBundleRedundant,
|
|
68
73
|
isPlatformUserExistsError: () => isPlatformUserExistsError,
|
|
69
74
|
isVersionEditable: () => isVersionEditable,
|
|
70
75
|
keepOneRecommended: () => keepOneRecommended,
|
|
71
76
|
missingRequiresFor: () => missingRequiresFor,
|
|
72
77
|
pickActivePromo: () => pickActivePromo,
|
|
78
|
+
planCatalogSettingsOf: () => planCatalogSettingsOf,
|
|
73
79
|
previousUtcDay: () => previousUtcDay,
|
|
74
80
|
promoStatus: () => promoStatus,
|
|
75
81
|
readQuotaRecord: () => readQuotaRecord,
|
|
@@ -79,10 +85,13 @@ __export(index_exports, {
|
|
|
79
85
|
selectChargeableBundles: () => selectChargeableBundles,
|
|
80
86
|
settingsSubtreeOf: () => settingsSubtreeOf,
|
|
81
87
|
startOfUtcDay: () => startOfUtcDay,
|
|
88
|
+
subscriberFromRegistration: () => subscriberFromRegistration,
|
|
82
89
|
toBundleStemRow: () => toBundleStemRow,
|
|
83
90
|
toContractLineItemRecord: () => toContractLineItemRecord,
|
|
84
91
|
toPlanRow: () => toPlanRow,
|
|
85
92
|
toPlanVersionRow: () => toPlanVersionRow,
|
|
93
|
+
toSubscriberCorrectionRecord: () => toSubscriberCorrectionRecord,
|
|
94
|
+
toSubscriberRecord: () => toSubscriberRecord,
|
|
86
95
|
toSubscriptionContractRecord: () => toSubscriptionContractRecord
|
|
87
96
|
});
|
|
88
97
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -364,6 +373,9 @@ var CATALOGUE_KEYS = /* @__PURE__ */ new Set([
|
|
|
364
373
|
"features",
|
|
365
374
|
"plans"
|
|
366
375
|
]);
|
|
376
|
+
function planCatalogSettingsOf(catalog) {
|
|
377
|
+
return settingsSubtreeOf(catalog);
|
|
378
|
+
}
|
|
367
379
|
function settingsSubtreeOf(catalog) {
|
|
368
380
|
const settings = {};
|
|
369
381
|
for (const [key, value] of Object.entries(catalog)) {
|
|
@@ -674,6 +686,27 @@ var CONTRACT_ERROR_CODES = {
|
|
|
674
686
|
NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT",
|
|
675
687
|
SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED"
|
|
676
688
|
};
|
|
689
|
+
var SUBSCRIBER_ERROR_CODES = {
|
|
690
|
+
/**
|
|
691
|
+
* A contract, a plan change or a booking for a tenant that has no
|
|
692
|
+
* subscriber. Nothing is agreed or charged without the party to it.
|
|
693
|
+
* Carries `tenantId`.
|
|
694
|
+
*/
|
|
695
|
+
SUBSCRIBER_REQUIRED: "SUBSCRIBER_REQUIRED",
|
|
696
|
+
/** The tenant already has a live subscriber. Carries `tenantId`. */
|
|
697
|
+
SUBSCRIBER_ALREADY_EXISTS: "SUBSCRIBER_ALREADY_EXISTS",
|
|
698
|
+
SUBSCRIBER_NOT_FOUND: "SUBSCRIBER_NOT_FOUND",
|
|
699
|
+
SUBSCRIBER_LEGAL_NAME_REQUIRED: "SUBSCRIBER_LEGAL_NAME_REQUIRED",
|
|
700
|
+
/** A detail that has a form — the country, the invoice email — is not in it. Carries `field`. */
|
|
701
|
+
SUBSCRIBER_DETAIL_INVALID: "SUBSCRIBER_DETAIL_INVALID",
|
|
702
|
+
/** A contact change named a field of the legal identity. Carries `field`. */
|
|
703
|
+
SUBSCRIBER_IDENTITY_NOT_A_CONTACT: "SUBSCRIBER_IDENTITY_NOT_A_CONTACT",
|
|
704
|
+
SUBSCRIBER_CORRECTION_REASON_REQUIRED: "SUBSCRIBER_CORRECTION_REASON_REQUIRED",
|
|
705
|
+
SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "SUBSCRIBER_CORRECTION_ACTOR_REQUIRED",
|
|
706
|
+
SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "SUBSCRIBER_CORRECTION_CHANGES_NOTHING",
|
|
707
|
+
/** The operator declared another legal entity: that is a transfer, not an edit. */
|
|
708
|
+
SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "SUBSCRIBER_TAKEOVER_IS_A_TRANSFER"
|
|
709
|
+
};
|
|
677
710
|
var REGISTRATION_ERROR_CODES = {
|
|
678
711
|
PENDING_REGISTRATION_NOT_FOUND: "PENDING_REGISTRATION_NOT_FOUND",
|
|
679
712
|
PENDING_REGISTRATION_EXPIRED: "PENDING_REGISTRATION_EXPIRED",
|
|
@@ -737,6 +770,7 @@ var PLATFORM_ERROR_CODES = {
|
|
|
737
770
|
...CATALOG_ERROR_CODES,
|
|
738
771
|
...BILLING_ERROR_CODES,
|
|
739
772
|
...CONTRACT_ERROR_CODES,
|
|
773
|
+
...SUBSCRIBER_ERROR_CODES,
|
|
740
774
|
...REGISTRATION_ERROR_CODES,
|
|
741
775
|
...SETTINGS_ERROR_CODES
|
|
742
776
|
};
|
|
@@ -896,11 +930,113 @@ function toQuotaEffects(value) {
|
|
|
896
930
|
return quotas;
|
|
897
931
|
}
|
|
898
932
|
|
|
933
|
+
// src/subscriber-mapping.ts
|
|
934
|
+
var SUBSCRIBER_IDENTITY_FIELDS = [
|
|
935
|
+
"legalName",
|
|
936
|
+
"vatId",
|
|
937
|
+
"taxNumber"
|
|
938
|
+
];
|
|
939
|
+
function formatCustomerNumber(prefix, sequence) {
|
|
940
|
+
return `${prefix}${sequence}`;
|
|
941
|
+
}
|
|
942
|
+
function toSubscriberRecord(row, tenantId) {
|
|
943
|
+
return {
|
|
944
|
+
id: row.id,
|
|
945
|
+
customerNumber: formatCustomerNumber(row.customerNumberPrefix, row.customerSequence),
|
|
946
|
+
legalName: row.legalName,
|
|
947
|
+
addressLine1: row.addressLine1,
|
|
948
|
+
addressLine2: row.addressLine2,
|
|
949
|
+
postalCode: row.postalCode,
|
|
950
|
+
city: row.city,
|
|
951
|
+
country: row.country,
|
|
952
|
+
vatId: row.vatId,
|
|
953
|
+
taxNumber: row.taxNumber,
|
|
954
|
+
invoiceEmail: row.invoiceEmail,
|
|
955
|
+
tenantId,
|
|
956
|
+
migrated: row.migrated,
|
|
957
|
+
createdAt: row.createdAt,
|
|
958
|
+
updatedAt: row.updatedAt
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
function toSubscriberCorrectionRecord(row) {
|
|
962
|
+
return {
|
|
963
|
+
id: row.id,
|
|
964
|
+
subscriberId: row.subscriberId,
|
|
965
|
+
previous: toIdentityValues(row.previous),
|
|
966
|
+
corrected: toIdentityValues(row.corrected),
|
|
967
|
+
reason: row.reason,
|
|
968
|
+
correctedBy: row.correctedBy,
|
|
969
|
+
correctedAt: row.correctedAt
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
function identityCorrectionDelta(current, corrected) {
|
|
973
|
+
const previous = {};
|
|
974
|
+
const next = {};
|
|
975
|
+
for (const field of SUBSCRIBER_IDENTITY_FIELDS) {
|
|
976
|
+
const value = corrected[field];
|
|
977
|
+
if (value === void 0 || value === current[field]) continue;
|
|
978
|
+
previous[field] = current[field];
|
|
979
|
+
next[field] = value;
|
|
980
|
+
}
|
|
981
|
+
return {
|
|
982
|
+
previous,
|
|
983
|
+
corrected: next
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
function contractPartiesOf(subscriber, issuer) {
|
|
987
|
+
const party = {
|
|
988
|
+
customerNumber: subscriber.customerNumber,
|
|
989
|
+
legalName: subscriber.legalName,
|
|
990
|
+
vatId: subscriber.vatId,
|
|
991
|
+
taxNumber: subscriber.taxNumber,
|
|
992
|
+
addressLine1: subscriber.addressLine1,
|
|
993
|
+
addressLine2: subscriber.addressLine2,
|
|
994
|
+
postalCode: subscriber.postalCode,
|
|
995
|
+
city: subscriber.city,
|
|
996
|
+
country: subscriber.country
|
|
997
|
+
};
|
|
998
|
+
return {
|
|
999
|
+
subscriberId: subscriber.id,
|
|
1000
|
+
subscriber: party,
|
|
1001
|
+
issuer: issuer ? issuerPartyOf(issuer) : null
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
function issuerPartyOf(issuer) {
|
|
1005
|
+
return {
|
|
1006
|
+
legalName: issuer.legalName,
|
|
1007
|
+
vatId: issuer.vatId ?? null,
|
|
1008
|
+
taxNumber: issuer.taxNumber ?? null,
|
|
1009
|
+
addressLine1: issuer.addressLine1 ?? null,
|
|
1010
|
+
addressLine2: issuer.addressLine2 ?? null,
|
|
1011
|
+
postalCode: issuer.postalCode ?? null,
|
|
1012
|
+
city: issuer.city ?? null,
|
|
1013
|
+
country: issuer.country ?? null
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
function subscriberFromRegistration(pending) {
|
|
1017
|
+
return { legalName: pending.tenantName, invoiceEmail: pending.email };
|
|
1018
|
+
}
|
|
1019
|
+
function toIdentityValues(value) {
|
|
1020
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
|
|
1021
|
+
const source = value;
|
|
1022
|
+
const values = {};
|
|
1023
|
+
for (const field of SUBSCRIBER_IDENTITY_FIELDS) {
|
|
1024
|
+
if (!Object.prototype.hasOwnProperty.call(source, field)) continue;
|
|
1025
|
+
const entry = source[field];
|
|
1026
|
+
values[field] = typeof entry === "string" ? entry : null;
|
|
1027
|
+
}
|
|
1028
|
+
return values;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
899
1031
|
// src/subscription-contract-mapping.ts
|
|
900
1032
|
function toSubscriptionContractRecord(row, lineItems) {
|
|
901
1033
|
return {
|
|
902
1034
|
id: row.id,
|
|
903
1035
|
tenantId: row.tenantId,
|
|
1036
|
+
subscriberId: row.subscriberId,
|
|
1037
|
+
subscriber: toSubscriberParty(row.subscriberSnapshot),
|
|
1038
|
+
issuer: isPlainObject2(row.issuerSnapshot) ? toIssuerParty(row.issuerSnapshot) : null,
|
|
1039
|
+
partiesMigrated: row.partiesMigrated,
|
|
904
1040
|
status: row.status,
|
|
905
1041
|
effectiveFrom: row.effectiveFrom,
|
|
906
1042
|
effectiveUntil: row.effectiveUntil,
|
|
@@ -941,6 +1077,32 @@ function toContractLineItemRecord(row) {
|
|
|
941
1077
|
createdAt: row.createdAt
|
|
942
1078
|
};
|
|
943
1079
|
}
|
|
1080
|
+
function toSubscriberParty(value) {
|
|
1081
|
+
const source = isPlainObject2(value) ? value : {};
|
|
1082
|
+
return {
|
|
1083
|
+
customerNumber: stringOr(source.customerNumber, ""),
|
|
1084
|
+
...toIssuerParty(source)
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
function toIssuerParty(value) {
|
|
1088
|
+
const source = value;
|
|
1089
|
+
return {
|
|
1090
|
+
legalName: stringOr(source.legalName, ""),
|
|
1091
|
+
vatId: stringOrNull(source.vatId),
|
|
1092
|
+
taxNumber: stringOrNull(source.taxNumber),
|
|
1093
|
+
addressLine1: stringOrNull(source.addressLine1),
|
|
1094
|
+
addressLine2: stringOrNull(source.addressLine2),
|
|
1095
|
+
postalCode: stringOrNull(source.postalCode),
|
|
1096
|
+
city: stringOrNull(source.city),
|
|
1097
|
+
country: stringOrNull(source.country)
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
function stringOr(value, fallback) {
|
|
1101
|
+
return typeof value === "string" ? value : fallback;
|
|
1102
|
+
}
|
|
1103
|
+
function stringOrNull(value) {
|
|
1104
|
+
return typeof value === "string" ? value : null;
|
|
1105
|
+
}
|
|
944
1106
|
function isPlainObject2(value) {
|
|
945
1107
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
946
1108
|
}
|
|
@@ -1157,6 +1319,17 @@ var ERROR_MESSAGES_EN = {
|
|
|
1157
1319
|
SUBSCRIPTION_CONTRACT_NOT_FOUND: "SubscriptionContract '{contractId}' not found",
|
|
1158
1320
|
NO_ACTIVE_SUBSCRIPTION_CONTRACT: "No active subscription contract for tenant {tenantId}",
|
|
1159
1321
|
SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SubscriptionContract '{contractId}' is already closed",
|
|
1322
|
+
// ── subscriber ──
|
|
1323
|
+
SUBSCRIBER_REQUIRED: "Tenant '{tenantId}' has no subscriber. Nothing is agreed or charged without the party to it: create the tenant's subscriber first.",
|
|
1324
|
+
SUBSCRIBER_ALREADY_EXISTS: "Tenant '{tenantId}' already has a subscriber.",
|
|
1325
|
+
SUBSCRIBER_NOT_FOUND: "Subscriber '{subscriberId}' not found",
|
|
1326
|
+
SUBSCRIBER_LEGAL_NAME_REQUIRED: "A subscriber needs its legal name.",
|
|
1327
|
+
SUBSCRIBER_DETAIL_INVALID: "The subscriber's {field} is not valid.",
|
|
1328
|
+
SUBSCRIBER_IDENTITY_NOT_A_CONTACT: "{field} is part of the subscriber's legal identity and changes only as a correction, with a reason.",
|
|
1329
|
+
SUBSCRIBER_CORRECTION_REASON_REQUIRED: "A correction of the legal identity needs a reason.",
|
|
1330
|
+
SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "A correction of the legal identity has to say who makes it.",
|
|
1331
|
+
SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "The correction changes nothing: every value it names is already recorded.",
|
|
1332
|
+
SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "Another legal entity taking over a subscriber is a transfer, not a correction, and cannot be recorded as an edit.",
|
|
1160
1333
|
// ── registration ──
|
|
1161
1334
|
PENDING_REGISTRATION_NOT_FOUND: "This registration could not be found. It may have already been completed or discarded.",
|
|
1162
1335
|
PENDING_REGISTRATION_EXPIRED: "This registration has expired. Please start again.",
|
|
@@ -1347,6 +1520,17 @@ var ERROR_MESSAGES_DE = {
|
|
|
1347
1520
|
SUBSCRIPTION_CONTRACT_NOT_FOUND: "SubscriptionContract '{contractId}' nicht gefunden",
|
|
1348
1521
|
NO_ACTIVE_SUBSCRIPTION_CONTRACT: "Kein aktiver Abo-Vertrag f\xFCr Mandant {tenantId}",
|
|
1349
1522
|
SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SubscriptionContract '{contractId}' ist bereits geschlossen",
|
|
1523
|
+
// ── subscriber ──
|
|
1524
|
+
SUBSCRIBER_REQUIRED: "Mandant '{tenantId}' hat keinen Vertragspartner. Ohne ihn wird nichts vereinbart oder berechnet: Zuerst muss der Vertragspartner des Mandanten angelegt werden.",
|
|
1525
|
+
SUBSCRIBER_ALREADY_EXISTS: "Mandant '{tenantId}' hat bereits einen Vertragspartner.",
|
|
1526
|
+
SUBSCRIBER_NOT_FOUND: "Vertragspartner '{subscriberId}' nicht gefunden",
|
|
1527
|
+
SUBSCRIBER_LEGAL_NAME_REQUIRED: "Ein Vertragspartner braucht seinen rechtlichen Namen.",
|
|
1528
|
+
SUBSCRIBER_DETAIL_INVALID: "Das Feld {field} des Vertragspartners ist ung\xFCltig.",
|
|
1529
|
+
SUBSCRIBER_IDENTITY_NOT_A_CONTACT: "{field} geh\xF6rt zur rechtlichen Identit\xE4t des Vertragspartners und \xE4ndert sich nur als Korrektur mit Begr\xFCndung.",
|
|
1530
|
+
SUBSCRIBER_CORRECTION_REASON_REQUIRED: "Eine Korrektur der rechtlichen Identit\xE4t braucht eine Begr\xFCndung.",
|
|
1531
|
+
SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "Eine Korrektur der rechtlichen Identit\xE4t muss nennen, wer sie vornimmt.",
|
|
1532
|
+
SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "Die Korrektur \xE4ndert nichts: Jeder genannte Wert ist bereits erfasst.",
|
|
1533
|
+
SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "\xDCbernimmt eine andere Rechtsperson, ist das eine \xDCbertragung und keine Korrektur; sie l\xE4sst sich nicht als \xC4nderung erfassen.",
|
|
1350
1534
|
// ── registration ──
|
|
1351
1535
|
PENDING_REGISTRATION_NOT_FOUND: "Diese Registrierung konnten wir nicht finden. Vielleicht ist sie bereits abgeschlossen oder verworfen.",
|
|
1352
1536
|
PENDING_REGISTRATION_EXPIRED: "Diese Registrierung ist abgelaufen. Bitte fange noch einmal von vorn an.",
|
|
@@ -1398,6 +1582,8 @@ var ERROR_MESSAGES_DE = {
|
|
|
1398
1582
|
REGISTRATION_STEP_BY_STATUS,
|
|
1399
1583
|
SETTINGS_ERROR_CODES,
|
|
1400
1584
|
SETUP_ERROR_CODES,
|
|
1585
|
+
SUBSCRIBER_ERROR_CODES,
|
|
1586
|
+
SUBSCRIBER_IDENTITY_FIELDS,
|
|
1401
1587
|
applyPromo,
|
|
1402
1588
|
assertPersistenceCapabilities,
|
|
1403
1589
|
buildActivePlanVersionWhere,
|
|
@@ -1409,16 +1595,20 @@ var ERROR_MESSAGES_DE = {
|
|
|
1409
1595
|
classifyBundleVersionDiff,
|
|
1410
1596
|
classifyPlanDiff,
|
|
1411
1597
|
collectUnsatisfiedRequires,
|
|
1598
|
+
contractPartiesOf,
|
|
1412
1599
|
coverageExcludingSelf,
|
|
1413
1600
|
definedFields,
|
|
1414
1601
|
diffSettings,
|
|
1602
|
+
formatCustomerNumber,
|
|
1415
1603
|
formatErrorMessage,
|
|
1604
|
+
identityCorrectionDelta,
|
|
1416
1605
|
isBundleRedundant,
|
|
1417
1606
|
isPlatformUserExistsError,
|
|
1418
1607
|
isVersionEditable,
|
|
1419
1608
|
keepOneRecommended,
|
|
1420
1609
|
missingRequiresFor,
|
|
1421
1610
|
pickActivePromo,
|
|
1611
|
+
planCatalogSettingsOf,
|
|
1422
1612
|
previousUtcDay,
|
|
1423
1613
|
promoStatus,
|
|
1424
1614
|
readQuotaRecord,
|
|
@@ -1428,9 +1618,12 @@ var ERROR_MESSAGES_DE = {
|
|
|
1428
1618
|
selectChargeableBundles,
|
|
1429
1619
|
settingsSubtreeOf,
|
|
1430
1620
|
startOfUtcDay,
|
|
1621
|
+
subscriberFromRegistration,
|
|
1431
1622
|
toBundleStemRow,
|
|
1432
1623
|
toContractLineItemRecord,
|
|
1433
1624
|
toPlanRow,
|
|
1434
1625
|
toPlanVersionRow,
|
|
1626
|
+
toSubscriberCorrectionRecord,
|
|
1627
|
+
toSubscriberRecord,
|
|
1435
1628
|
toSubscriptionContractRecord
|
|
1436
1629
|
});
|