@saasicat/core 1.0.0-rc.24 → 1.0.0-rc.26
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 +1281 -17
- package/dist/index.d.cts +3167 -489
- package/dist/index.d.ts +3167 -489
- package/dist/index.js +1221 -16
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
AUTH_ERROR_CODES: () => AUTH_ERROR_CODES,
|
|
25
25
|
BILLING_ERROR_CODES: () => BILLING_ERROR_CODES,
|
|
26
26
|
BUNDLE_PRICE_LOOKUP_LIMIT: () => BUNDLE_PRICE_LOOKUP_LIMIT,
|
|
27
|
+
BUNDLE_VERSION_RETIREMENT_CAPABILITY: () => BUNDLE_VERSION_RETIREMENT_CAPABILITY,
|
|
27
28
|
CATALOGUE_KEYS: () => CATALOGUE_KEYS,
|
|
28
29
|
CATALOG_ERROR_CODES: () => CATALOG_ERROR_CODES,
|
|
29
30
|
CONTRACT_ERROR_CODES: () => CONTRACT_ERROR_CODES,
|
|
@@ -31,7 +32,13 @@ __export(index_exports, {
|
|
|
31
32
|
ERROR_MESSAGES_DE: () => ERROR_MESSAGES_DE,
|
|
32
33
|
ERROR_MESSAGES_EN: () => ERROR_MESSAGES_EN,
|
|
33
34
|
FEATURE_NOT_LICENSED: () => FEATURE_NOT_LICENSED,
|
|
35
|
+
FEATURE_WITHDRAWAL_CAPABILITY: () => FEATURE_WITHDRAWAL_CAPABILITY,
|
|
36
|
+
FEATURE_WITHDRAWAL_REASON_MAX_LENGTH: () => FEATURE_WITHDRAWAL_REASON_MAX_LENGTH,
|
|
34
37
|
ForeignPaymentMethodReferenceError: () => ForeignPaymentMethodReferenceError,
|
|
38
|
+
INVOICE_ARCHIVE_TRIGGERS: () => INVOICE_ARCHIVE_TRIGGERS,
|
|
39
|
+
INVOICE_DOCUMENT_CAPABILITY: () => INVOICE_DOCUMENT_CAPABILITY,
|
|
40
|
+
INVOICE_ERROR_CODES: () => INVOICE_ERROR_CODES,
|
|
41
|
+
INVOICE_SEQUENCE_DIGITS: () => INVOICE_SEQUENCE_DIGITS,
|
|
35
42
|
LEGAL_IDENTITY_FIELDS: () => LEGAL_IDENTITY_FIELDS,
|
|
36
43
|
MAINTENANCE_CAPABILITY: () => MAINTENANCE_CAPABILITY,
|
|
37
44
|
MAINTENANCE_ERROR_CODES: () => MAINTENANCE_ERROR_CODES,
|
|
@@ -64,9 +71,21 @@ __export(index_exports, {
|
|
|
64
71
|
SETTINGS_ERROR_CODES: () => SETTINGS_ERROR_CODES,
|
|
65
72
|
SETUP_ERROR_CODES: () => SETUP_ERROR_CODES,
|
|
66
73
|
SUBSCRIBER_ACCOUNT_CAPABILITY: () => SUBSCRIBER_ACCOUNT_CAPABILITY,
|
|
74
|
+
SUBSCRIBER_ATTENTION_CAPABILITY: () => SUBSCRIBER_ATTENTION_CAPABILITY,
|
|
75
|
+
SUBSCRIBER_ATTENTION_PAGE_SIZE: () => SUBSCRIBER_ATTENTION_PAGE_SIZE,
|
|
76
|
+
SUBSCRIBER_CHARGE_ORIGINS: () => SUBSCRIBER_CHARGE_ORIGINS,
|
|
77
|
+
SUBSCRIBER_CHARGE_SOURCES: () => SUBSCRIBER_CHARGE_SOURCES,
|
|
78
|
+
SUBSCRIBER_CORRECTION_CAPABILITY: () => SUBSCRIBER_CORRECTION_CAPABILITY,
|
|
67
79
|
SUBSCRIBER_ERROR_CODES: () => SUBSCRIBER_ERROR_CODES,
|
|
80
|
+
SUBSCRIBER_INVOICE_ADDRESS_FIELDS: () => SUBSCRIBER_INVOICE_ADDRESS_FIELDS,
|
|
81
|
+
SUBSCRIBER_STANDING_CAPABILITY: () => SUBSCRIBER_STANDING_CAPABILITY,
|
|
82
|
+
SUBSCRIBER_TAX_ORIGIN_FIELDS: () => SUBSCRIBER_TAX_ORIGIN_FIELDS,
|
|
83
|
+
TAX_ERROR_CODES: () => TAX_ERROR_CODES,
|
|
84
|
+
TAX_TREATMENT_KINDS: () => TAX_TREATMENT_KINDS,
|
|
68
85
|
VERSION_RETIREMENT_CAPABILITY: () => VERSION_RETIREMENT_CAPABILITY,
|
|
86
|
+
addDaysToDay: () => addDaysToDay,
|
|
69
87
|
applyPromo: () => applyPromo,
|
|
88
|
+
asXmlReadsIt: () => asXmlReadsIt,
|
|
70
89
|
assertPersistenceCapabilities: () => assertPersistenceCapabilities,
|
|
71
90
|
buildActivePlanVersionWhere: () => buildActivePlanVersionWhere,
|
|
72
91
|
buildActiveVersionWhere: () => buildActiveVersionWhere,
|
|
@@ -75,6 +94,7 @@ __export(index_exports, {
|
|
|
75
94
|
bundleKeyTaken: () => bundleKeyTaken,
|
|
76
95
|
bundleStemDefaults: () => bundleStemDefaults,
|
|
77
96
|
canonicalJson: () => canonicalJson,
|
|
97
|
+
canonicalVatId: () => canonicalVatId,
|
|
78
98
|
catalogDraftExists: () => catalogDraftExists,
|
|
79
99
|
catalogVersionAlreadyPublished: () => catalogVersionAlreadyPublished,
|
|
80
100
|
catalogVersionGone: () => catalogVersionGone,
|
|
@@ -89,14 +109,28 @@ __export(index_exports, {
|
|
|
89
109
|
contractPartiesOf: () => contractPartiesOf,
|
|
90
110
|
coverageExcludingSelf: () => coverageExcludingSelf,
|
|
91
111
|
customLimitsReader: () => customLimitsReader,
|
|
112
|
+
dayInZone: () => dayInZone,
|
|
92
113
|
definedFields: () => definedFields,
|
|
93
114
|
diffSettings: () => diffSettings,
|
|
115
|
+
draftSubscriptionInvoice: () => draftSubscriptionInvoice,
|
|
116
|
+
endedAtOnceSubjectOf: () => endedAtOnceSubjectOf,
|
|
117
|
+
featureWithdrawalRowOf: () => featureWithdrawalRowOf,
|
|
118
|
+
featuresWithdrawnAt: () => featuresWithdrawnAt,
|
|
94
119
|
formatCustomerNumber: () => formatCustomerNumber,
|
|
95
120
|
formatErrorMessage: () => formatErrorMessage,
|
|
121
|
+
formatInvoiceNumber: () => formatInvoiceNumber,
|
|
96
122
|
grossFromNet: () => grossFromNet,
|
|
123
|
+
holdsOnlyXmlCharacters: () => holdsOnlyXmlCharacters,
|
|
97
124
|
identityCorrectionDelta: () => identityCorrectionDelta,
|
|
125
|
+
invoiceArchiveProtectionProblem: () => invoiceArchiveProtectionProblem,
|
|
126
|
+
invoiceContentDraftOf: () => invoiceContentDraftOf,
|
|
127
|
+
invoiceFooterOf: () => invoiceFooterOf,
|
|
128
|
+
invoiceGroupsOf: () => invoiceGroupsOf,
|
|
129
|
+
invoiceIssuerOf: () => invoiceIssuerOf,
|
|
98
130
|
isBundleRedundant: () => isBundleRedundant,
|
|
131
|
+
isFeatureWithdrawnAt: () => isFeatureWithdrawnAt,
|
|
99
132
|
isForeignPaymentMethodReferenceError: () => isForeignPaymentMethodReferenceError,
|
|
133
|
+
isInvoiceDocumentChecksum: () => isInvoiceDocumentChecksum,
|
|
100
134
|
isMaintenanceAnnouncementLapsed: () => isMaintenanceAnnouncementLapsed,
|
|
101
135
|
isMaintenanceOverrun: () => isMaintenanceOverrun,
|
|
102
136
|
isPaymentCallbackRejectedError: () => isPaymentCallbackRejectedError,
|
|
@@ -106,6 +140,8 @@ __export(index_exports, {
|
|
|
106
140
|
isVersionEditable: () => isVersionEditable,
|
|
107
141
|
issuerIdentityOf: () => issuerIdentityOf,
|
|
108
142
|
keepOneRecommended: () => keepOneRecommended,
|
|
143
|
+
keepsVatIdCheck: () => keepsVatIdCheck,
|
|
144
|
+
lastDayInZone: () => lastDayInZone,
|
|
109
145
|
maintenanceRetryAfterSeconds: () => maintenanceRetryAfterSeconds,
|
|
110
146
|
maintenanceStatusOf: () => maintenanceStatusOf,
|
|
111
147
|
maintenanceWindowStatusOf: () => maintenanceWindowStatusOf,
|
|
@@ -115,6 +151,7 @@ __export(index_exports, {
|
|
|
115
151
|
missingRequiresFor: () => missingRequiresFor,
|
|
116
152
|
movedIdentityFields: () => movedIdentityFields,
|
|
117
153
|
netFromGross: () => netFromGross,
|
|
154
|
+
nextWithdrawalChange: () => nextWithdrawalChange,
|
|
118
155
|
noActivePlanVersion: () => noActivePlanVersion,
|
|
119
156
|
parseZonedInstant: () => parseZonedInstant,
|
|
120
157
|
percentOf: () => percentOf,
|
|
@@ -151,11 +188,22 @@ __export(index_exports, {
|
|
|
151
188
|
subscriptionBundleGone: () => subscriptionBundleGone,
|
|
152
189
|
subscriptionContractGone: () => subscriptionContractGone,
|
|
153
190
|
subscriptionGone: () => subscriptionGone,
|
|
191
|
+
subscriptionInvoiceChargeInvoiced: () => subscriptionInvoiceChargeInvoiced,
|
|
192
|
+
subscriptionInvoiceColumns: () => subscriptionInvoiceColumns,
|
|
193
|
+
subscriptionInvoiceDocumentChanged: () => subscriptionInvoiceDocumentChanged,
|
|
194
|
+
subscriptionInvoiceLineColumns: () => subscriptionInvoiceLineColumns,
|
|
154
195
|
sumToCents: () => sumToCents,
|
|
196
|
+
taxOriginOf: () => taxOriginOf,
|
|
197
|
+
taxOriginWrite: () => taxOriginWrite,
|
|
198
|
+
taxPerRate: () => taxPerRate,
|
|
199
|
+
taxTreatmentToJson: () => taxTreatmentToJson,
|
|
200
|
+
toArchivedInvoiceDocument: () => toArchivedInvoiceDocument,
|
|
155
201
|
toBundleStemRow: () => toBundleStemRow,
|
|
202
|
+
toBundleVersionRetirementRecord: () => toBundleVersionRetirementRecord,
|
|
156
203
|
toCents: () => toCents,
|
|
157
204
|
toContractLineItemRecord: () => toContractLineItemRecord,
|
|
158
205
|
toDecimalString: () => toDecimalString,
|
|
206
|
+
toFeatureWithdrawalRecord: () => toFeatureWithdrawalRecord,
|
|
159
207
|
toMaintenanceWindowRecord: () => toMaintenanceWindowRecord,
|
|
160
208
|
toPlanRow: () => toPlanRow,
|
|
161
209
|
toPlanVersionRow: () => toPlanVersionRow,
|
|
@@ -164,13 +212,24 @@ __export(index_exports, {
|
|
|
164
212
|
toSubscriberCorrectionRecord: () => toSubscriberCorrectionRecord,
|
|
165
213
|
toSubscriberPaymentMethodRecord: () => toSubscriberPaymentMethodRecord,
|
|
166
214
|
toSubscriberRecord: () => toSubscriberRecord,
|
|
215
|
+
toSubscriberTaxOriginChangeRecord: () => toSubscriberTaxOriginChangeRecord,
|
|
216
|
+
toSubscriberVatIdCheckRecord: () => toSubscriberVatIdCheckRecord,
|
|
167
217
|
toSubscriptionBundleRecord: () => toSubscriptionBundleRecord,
|
|
168
218
|
toSubscriptionContractRecord: () => toSubscriptionContractRecord,
|
|
219
|
+
toSubscriptionInvoiceDocumentRecord: () => toSubscriptionInvoiceDocumentRecord,
|
|
220
|
+
toSubscriptionInvoiceRecord: () => toSubscriptionInvoiceRecord,
|
|
169
221
|
toSubscriptionNoticeRecord: () => toSubscriptionNoticeRecord,
|
|
222
|
+
toTaxOriginValues: () => toTaxOriginValues,
|
|
223
|
+
toTaxTreatment: () => toTaxTreatment,
|
|
170
224
|
toVersionRetirementRecord: () => toVersionRetirementRecord,
|
|
225
|
+
utcMidnightOf: () => utcMidnightOf,
|
|
226
|
+
vatCategoryOf: () => vatCategoryOf,
|
|
227
|
+
vatIdCheckFromStore: () => vatIdCheckFromStore,
|
|
171
228
|
versionOnSale: () => versionOnSale,
|
|
172
229
|
versionOnSaleOrNext: () => versionOnSaleOrNext,
|
|
173
|
-
versionSale: () => versionSale
|
|
230
|
+
versionSale: () => versionSale,
|
|
231
|
+
withdrawnFeaturesOf: () => withdrawnFeaturesOf,
|
|
232
|
+
yearOfDay: () => yearOfDay
|
|
174
233
|
});
|
|
175
234
|
module.exports = __toCommonJS(index_exports);
|
|
176
235
|
|
|
@@ -333,6 +392,22 @@ function computeIncludedVat(gross, vatRate) {
|
|
|
333
392
|
const rate = exactDecimal(vatRate);
|
|
334
393
|
return amountOf(cents(exactDecimal(gross), rate, sum(HUNDRED, rate)));
|
|
335
394
|
}
|
|
395
|
+
function taxPerRate(lines) {
|
|
396
|
+
const nets = /* @__PURE__ */ new Map();
|
|
397
|
+
for (const line of lines) {
|
|
398
|
+
const key = String(line.rate);
|
|
399
|
+
const entry = nets.get(key) ?? { rate: line.rate, terms: [] };
|
|
400
|
+
entry.terms.push(line.net);
|
|
401
|
+
nets.set(key, entry);
|
|
402
|
+
}
|
|
403
|
+
const rates = [...nets.values()].sort((a, b) => a.rate - b.rate).map(({ rate, terms }) => {
|
|
404
|
+
const net2 = sumToCents(...terms);
|
|
405
|
+
return { rate, net: net2, tax: percentOf(net2, rate) };
|
|
406
|
+
});
|
|
407
|
+
const net = sumToCents(...rates.map((entry) => entry.net));
|
|
408
|
+
const tax = sumToCents(...rates.map((entry) => entry.tax));
|
|
409
|
+
return { rates, net, tax, gross: sumToCents(net, tax) };
|
|
410
|
+
}
|
|
336
411
|
|
|
337
412
|
// src/promotion.types.ts
|
|
338
413
|
function promoStatus(promo, today = /* @__PURE__ */ new Date()) {
|
|
@@ -580,7 +655,13 @@ var TABLE = "subscription_notices";
|
|
|
580
655
|
var KINDS = {
|
|
581
656
|
"version-offered": true,
|
|
582
657
|
"version-retired": true,
|
|
583
|
-
"version-retirement-reminder": true
|
|
658
|
+
"version-retirement-reminder": true,
|
|
659
|
+
"bundle-version-retired": true,
|
|
660
|
+
"bundle-version-retirement-reminder": true,
|
|
661
|
+
"bundle-version-offered": true,
|
|
662
|
+
"feature-withdrawn": true,
|
|
663
|
+
"feature-withdrawal-lifted": true,
|
|
664
|
+
"ended-at-once": true
|
|
584
665
|
};
|
|
585
666
|
function toSubscriptionNoticeRecord(row) {
|
|
586
667
|
return {
|
|
@@ -689,6 +770,128 @@ function toVersionRetirementRecord(row) {
|
|
|
689
770
|
};
|
|
690
771
|
}
|
|
691
772
|
|
|
773
|
+
// src/bundle-version-retirement.types.ts
|
|
774
|
+
var BUNDLE_VERSION_RETIREMENT_CAPABILITY = "bundleVersions.retire";
|
|
775
|
+
|
|
776
|
+
// src/bundle-version-retirement-mapping.ts
|
|
777
|
+
function toBundleVersionRetirementRecord(row) {
|
|
778
|
+
return {
|
|
779
|
+
id: row.id,
|
|
780
|
+
retired: {
|
|
781
|
+
bundleVersionId: row.retiredBundleVersionId,
|
|
782
|
+
bundleKey: row.retiredBundleKey,
|
|
783
|
+
version: row.retiredVersion
|
|
784
|
+
},
|
|
785
|
+
replacement: {
|
|
786
|
+
bundleVersionId: row.replacementBundleVersionId,
|
|
787
|
+
bundleKey: row.replacementBundleKey,
|
|
788
|
+
version: row.replacementVersion
|
|
789
|
+
},
|
|
790
|
+
announcedAt: row.announcedAt,
|
|
791
|
+
announcedBy: row.announcedBy
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/feature-withdrawal.types.ts
|
|
796
|
+
var FEATURE_WITHDRAWAL_REASON_MAX_LENGTH = 1e3;
|
|
797
|
+
function isFeatureWithdrawnAt(withdrawal, at) {
|
|
798
|
+
return withdrawal.effectiveFrom <= at && (withdrawal.liftedFrom === null || at < withdrawal.liftedFrom);
|
|
799
|
+
}
|
|
800
|
+
function featuresWithdrawnAt(withdrawals, at) {
|
|
801
|
+
return new Set(
|
|
802
|
+
withdrawals.filter((withdrawal) => isFeatureWithdrawnAt(withdrawal, at)).map((withdrawal) => withdrawal.featureKey)
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
function nextWithdrawalChange(withdrawals, at) {
|
|
806
|
+
let next = null;
|
|
807
|
+
for (const { effectiveFrom, liftedFrom } of withdrawals) {
|
|
808
|
+
for (const moment of [effectiveFrom, liftedFrom]) {
|
|
809
|
+
if (moment === null || moment <= at) continue;
|
|
810
|
+
if (next === null || moment < next) next = moment;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
return next;
|
|
814
|
+
}
|
|
815
|
+
var FEATURE_WITHDRAWAL_CAPABILITY = "features.withdraw";
|
|
816
|
+
function featureWithdrawalRowOf(record) {
|
|
817
|
+
return {
|
|
818
|
+
id: record.id,
|
|
819
|
+
featureKey: record.featureKey,
|
|
820
|
+
reason: record.reason,
|
|
821
|
+
effectiveFrom: record.effectiveFrom.toISOString(),
|
|
822
|
+
liftedFrom: record.liftedFrom?.toISOString() ?? null,
|
|
823
|
+
reductions: record.reductions,
|
|
824
|
+
announcedAt: record.announcedAt.toISOString(),
|
|
825
|
+
announcedBy: record.announcedBy,
|
|
826
|
+
liftedAt: record.liftedAt?.toISOString() ?? null,
|
|
827
|
+
liftedBy: record.liftedBy,
|
|
828
|
+
toldAt: record.toldAt?.toISOString() ?? null
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
function withdrawnFeaturesOf(withdrawals, now) {
|
|
832
|
+
return withdrawals.filter(
|
|
833
|
+
({ effectiveFrom, liftedFrom }) => liftedFrom === null || liftedFrom > now && effectiveFrom < liftedFrom
|
|
834
|
+
).sort((a, b) => a.effectiveFrom.getTime() - b.effectiveFrom.getTime()).map((withdrawal) => ({
|
|
835
|
+
featureKey: withdrawal.featureKey,
|
|
836
|
+
reason: withdrawal.reason,
|
|
837
|
+
effectiveFrom: withdrawal.effectiveFrom.toISOString(),
|
|
838
|
+
liftedFrom: withdrawal.liftedFrom?.toISOString() ?? null
|
|
839
|
+
}));
|
|
840
|
+
}
|
|
841
|
+
function endedAtOnceSubjectOf(subscriptionOrBookingId, at) {
|
|
842
|
+
return `${subscriptionOrBookingId}@${at.toISOString()}`;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// src/feature-withdrawal-mapping.ts
|
|
846
|
+
var TABLE2 = "feature_withdrawals";
|
|
847
|
+
var KINDS2 = { plan: true, bundle: true };
|
|
848
|
+
var CYCLES = { MONTHLY: true, YEARLY: true };
|
|
849
|
+
function toFeatureWithdrawalRecord(row) {
|
|
850
|
+
return {
|
|
851
|
+
id: row.id,
|
|
852
|
+
featureKey: row.featureKey,
|
|
853
|
+
reason: row.reason,
|
|
854
|
+
effectiveFrom: row.effectiveFrom,
|
|
855
|
+
liftedFrom: row.liftedFrom,
|
|
856
|
+
reductions: reductionsOf(row),
|
|
857
|
+
announcedAt: row.announcedAt,
|
|
858
|
+
announcedBy: row.announcedBy,
|
|
859
|
+
liftedAt: row.liftedAt,
|
|
860
|
+
liftedBy: row.liftedBy,
|
|
861
|
+
toldAt: row.toldAt
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
function reductionsOf(row) {
|
|
865
|
+
if (!Array.isArray(row.reductions)) {
|
|
866
|
+
throw new Error(`${TABLE2} row '${row.id}' holds reductions that are not a list.`);
|
|
867
|
+
}
|
|
868
|
+
return row.reductions.map((entry, index) => {
|
|
869
|
+
const column = `reductions[${index}]`;
|
|
870
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) {
|
|
871
|
+
throw new Error(`${TABLE2} row '${row.id}' holds ${column} that is not an object.`);
|
|
872
|
+
}
|
|
873
|
+
const { kind, key, billingCycle, amountNet } = entry;
|
|
874
|
+
if (typeof kind !== "string" || typeof key !== "string" || typeof billingCycle !== "string" || typeof amountNet !== "number" || !Number.isFinite(amountNet)) {
|
|
875
|
+
throw new Error(
|
|
876
|
+
`${TABLE2} row '${row.id}' holds ${column} without a kind, a key, a billing cycle and a finite amount.`
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
const source = { table: TABLE2, id: row.id };
|
|
880
|
+
return {
|
|
881
|
+
kind: oneOf(Object.keys(KINDS2), kind, {
|
|
882
|
+
...source,
|
|
883
|
+
column: `${column}.kind`
|
|
884
|
+
}),
|
|
885
|
+
key,
|
|
886
|
+
billingCycle: oneOf(Object.keys(CYCLES), billingCycle, {
|
|
887
|
+
...source,
|
|
888
|
+
column: `${column}.billingCycle`
|
|
889
|
+
}),
|
|
890
|
+
amountNet
|
|
891
|
+
};
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
|
|
692
895
|
// src/scheduled-change-after-write.ts
|
|
693
896
|
var NO_SCHEDULED_CHANGE = {
|
|
694
897
|
pendingPlan: null,
|
|
@@ -825,6 +1028,37 @@ function parseZonedInstant(text) {
|
|
|
825
1028
|
return Number.isNaN(moment.getTime()) ? null : moment;
|
|
826
1029
|
}
|
|
827
1030
|
|
|
1031
|
+
// src/zoned-day.ts
|
|
1032
|
+
function dayInZone(at, timeZone) {
|
|
1033
|
+
if (typeof timeZone !== "string" || timeZone === "") {
|
|
1034
|
+
throw new RangeError("A day is read in a named time zone.");
|
|
1035
|
+
}
|
|
1036
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
1037
|
+
timeZone,
|
|
1038
|
+
year: "numeric",
|
|
1039
|
+
month: "2-digit",
|
|
1040
|
+
day: "2-digit"
|
|
1041
|
+
}).formatToParts(at);
|
|
1042
|
+
const part = (type) => parts.find((candidate) => candidate.type === type)?.value;
|
|
1043
|
+
return `${part("year")}-${part("month")}-${part("day")}`;
|
|
1044
|
+
}
|
|
1045
|
+
function lastDayInZone(period, timeZone) {
|
|
1046
|
+
if (!(period.until.getTime() > period.from.getTime())) {
|
|
1047
|
+
throw new RangeError("A period ends after it begins.");
|
|
1048
|
+
}
|
|
1049
|
+
return dayInZone(new Date(period.until.getTime() - 1), timeZone);
|
|
1050
|
+
}
|
|
1051
|
+
function addDaysToDay(day, days) {
|
|
1052
|
+
if (!Number.isInteger(days)) throw new RangeError("Days are counted in whole days.");
|
|
1053
|
+
const [year, month, date] = day.split("-").map(Number);
|
|
1054
|
+
if (!year || !month || !date) throw new RangeError(`${day} is not a day.`);
|
|
1055
|
+
const moved = new Date(Date.UTC(year, month - 1, date + days));
|
|
1056
|
+
return moved.toISOString().slice(0, 10);
|
|
1057
|
+
}
|
|
1058
|
+
function yearOfDay(day) {
|
|
1059
|
+
return Number(day.slice(0, 4));
|
|
1060
|
+
}
|
|
1061
|
+
|
|
828
1062
|
// src/settings-subtree.ts
|
|
829
1063
|
var CATALOGUE_KEYS = /* @__PURE__ */ new Set([
|
|
830
1064
|
"schemaVersion",
|
|
@@ -996,6 +1230,13 @@ var CATALOG_ERROR_CODES = {
|
|
|
996
1230
|
PLAN_NOT_FOUND: "PLAN_NOT_FOUND",
|
|
997
1231
|
PLAN_VERSION_NOT_FOUND: "PLAN_VERSION_NOT_FOUND",
|
|
998
1232
|
BUNDLE_NOT_FOUND: "BUNDLE_NOT_FOUND",
|
|
1233
|
+
/**
|
|
1234
|
+
* Bookings told that their add-on version is being retired have still to
|
|
1235
|
+
* move onto a version of this add-on — waiting for their notice, for their
|
|
1236
|
+
* date, or past it — and a deleted add-on is booked by nothing, the move
|
|
1237
|
+
* included. Carries how many, and the add-on's key.
|
|
1238
|
+
*/
|
|
1239
|
+
BUNDLE_DELETE_WHILE_RETIREMENT_MOVES_PENDING: "BUNDLE_DELETE_WHILE_RETIREMENT_MOVES_PENDING",
|
|
999
1240
|
BUNDLE_VERSION_NOT_FOUND: "BUNDLE_VERSION_NOT_FOUND",
|
|
1000
1241
|
FEATURE_NOT_FOUND: "FEATURE_NOT_FOUND",
|
|
1001
1242
|
QUOTA_NOT_FOUND: "QUOTA_NOT_FOUND",
|
|
@@ -1186,6 +1427,16 @@ var BILLING_ERROR_CODES = {
|
|
|
1186
1427
|
* to pick, so the way past it is the add-on ending.
|
|
1187
1428
|
*/
|
|
1188
1429
|
RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW: "RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW",
|
|
1430
|
+
/**
|
|
1431
|
+
* As `RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW`, where only the version the
|
|
1432
|
+
* add-on continues on from a retirement's date cannot run beside the
|
|
1433
|
+
* replacement's plan. The version it is on can, so cancelling it — it then
|
|
1434
|
+
* ends before that date — lets the switch through. Given while that date
|
|
1435
|
+
* is ahead and the add-on is not cancelled yet; otherwise the earlier code
|
|
1436
|
+
* names the day it can end. Carries the add-on, that version, its date and
|
|
1437
|
+
* the plan.
|
|
1438
|
+
*/
|
|
1439
|
+
RETIREMENT_SWITCH_BUNDLE_REPLACEMENT_CANNOT_FOLLOW: "RETIREMENT_SWITCH_BUNDLE_REPLACEMENT_CANNOT_FOLLOW",
|
|
1189
1440
|
/**
|
|
1190
1441
|
* The subscription takes no switch now: a change is scheduled, it has
|
|
1191
1442
|
* ended, or its plan is held for a special contract.
|
|
@@ -1196,6 +1447,149 @@ var BILLING_ERROR_CODES = {
|
|
|
1196
1447
|
* the retirement as it now stands.
|
|
1197
1448
|
*/
|
|
1198
1449
|
RETIREMENT_SWITCH_CHANGED: "RETIREMENT_SWITCH_CHANGED",
|
|
1450
|
+
// ── retiring an add-on version for running bookings ──
|
|
1451
|
+
//
|
|
1452
|
+
// An add-on retirement answers with the plan retirement's codes where the
|
|
1453
|
+
// sentence is the same — terms not confirmed, a version named as its own
|
|
1454
|
+
// replacement, twelve months, a preview that changed — and with these
|
|
1455
|
+
// where it names an add-on rather than a plan.
|
|
1456
|
+
/**
|
|
1457
|
+
* The add-on version is still on sale: a booking made after the
|
|
1458
|
+
* announcement would be on it without having been told. Carries the
|
|
1459
|
+
* add-on key and the version.
|
|
1460
|
+
*/
|
|
1461
|
+
BUNDLE_RETIREMENT_VERSION_ON_SALE: "BUNDLE_RETIREMENT_VERSION_ON_SALE",
|
|
1462
|
+
/** The replacement is not on sale, so no booking can continue on it. Carries add-on key and version. */
|
|
1463
|
+
BUNDLE_RETIREMENT_REPLACEMENT_NOT_ON_SALE: "BUNDLE_RETIREMENT_REPLACEMENT_NOT_ON_SALE",
|
|
1464
|
+
/**
|
|
1465
|
+
* The replacement is a version of another add-on. A booking continues on
|
|
1466
|
+
* a version of its own add-on, so it stays the same booking with its term.
|
|
1467
|
+
* Carries both add-on keys.
|
|
1468
|
+
*/
|
|
1469
|
+
BUNDLE_RETIREMENT_REPLACEMENT_OF_ANOTHER_BUNDLE: "BUNDLE_RETIREMENT_REPLACEMENT_OF_ANOTHER_BUNDLE",
|
|
1470
|
+
/**
|
|
1471
|
+
* Some of the bookings it reaches run, at their date, beside a plan the
|
|
1472
|
+
* replacement cannot run beside: not allowed there, without a price there
|
|
1473
|
+
* in the booking's rhythm, or in a longer rhythm than the plan's. Carries
|
|
1474
|
+
* how many, and the replacement's add-on key and version.
|
|
1475
|
+
*/
|
|
1476
|
+
BUNDLE_RETIREMENT_REPLACEMENT_CANNOT_RUN: "BUNDLE_RETIREMENT_REPLACEMENT_CANNOT_RUN",
|
|
1477
|
+
/** No running booking is on the version: there is nobody to tell. Carries add-on key and version. */
|
|
1478
|
+
BUNDLE_RETIREMENT_NOTHING_AFFECTED: "BUNDLE_RETIREMENT_NOTHING_AFFECTED",
|
|
1479
|
+
/**
|
|
1480
|
+
* The booking is on an add-on version being retired, and was cancelled to
|
|
1481
|
+
* end before it would move, so it was never told and nothing moves it.
|
|
1482
|
+
* Reinstated, it would run on past the date on a version nobody sells;
|
|
1483
|
+
* booking the replacement once it has ended is the way. Carries the add-on
|
|
1484
|
+
* key, the version, the replacement's version and the day it can be booked
|
|
1485
|
+
* from.
|
|
1486
|
+
*/
|
|
1487
|
+
BUNDLE_RETIREMENT_REINSTATE_REFUSED: "BUNDLE_RETIREMENT_REINSTATE_REFUSED",
|
|
1488
|
+
/**
|
|
1489
|
+
* As `BUNDLE_RETIREMENT_REINSTATE_REFUSED`, where the replacement cannot
|
|
1490
|
+
* run beside the plan the subscription is on when the booking ends, or
|
|
1491
|
+
* beside one it is already set to move to after that, in any rhythm it
|
|
1492
|
+
* could be booked in, so there is no version of the add-on to book.
|
|
1493
|
+
* Carries the add-on key, the version and the replacement's version.
|
|
1494
|
+
*/
|
|
1495
|
+
BUNDLE_RETIREMENT_REINSTATE_REPLACEMENT_CANNOT_RUN: "BUNDLE_RETIREMENT_REINSTATE_REPLACEMENT_CANNOT_RUN",
|
|
1496
|
+
/**
|
|
1497
|
+
* As `BUNDLE_RETIREMENT_REINSTATE_REFUSED`, where the subscription ends by
|
|
1498
|
+
* the day the replacement could be booked from, so there is no day to
|
|
1499
|
+
* name. Carries the add-on key, the version and the replacement's version.
|
|
1500
|
+
*/
|
|
1501
|
+
BUNDLE_RETIREMENT_REINSTATE_SUBSCRIPTION_ENDS: "BUNDLE_RETIREMENT_REINSTATE_SUBSCRIPTION_ENDS",
|
|
1502
|
+
/**
|
|
1503
|
+
* The plan the add-on runs beside, or the rhythm it is billed in, changes
|
|
1504
|
+
* before the date the booking was told — by a change scheduled, or by a
|
|
1505
|
+
* retirement told that moves the subscription to another plan — so the
|
|
1506
|
+
* price a switch now would hold is not the one the booking pays until
|
|
1507
|
+
* then. Switching once the plan has changed, or waiting for the
|
|
1508
|
+
* date, is the way. Carries the add-on and the date.
|
|
1509
|
+
*/
|
|
1510
|
+
BUNDLE_RETIREMENT_SWITCH_PLAN_CHANGES: "BUNDLE_RETIREMENT_SWITCH_PLAN_CHANGES",
|
|
1511
|
+
/**
|
|
1512
|
+
* The add-on version the caller asked to switch a booking to is no longer
|
|
1513
|
+
* the one offered beside it — another is on sale, the booking moved, or
|
|
1514
|
+
* there is no offer. Nothing was switched. Carries the version named
|
|
1515
|
+
* (`bundleVersionId`) and the current `offer`, or `null`, so the page can
|
|
1516
|
+
* show it instead of guessing.
|
|
1517
|
+
*/
|
|
1518
|
+
BUNDLE_VERSION_OFFER_CHANGED: "BUNDLE_VERSION_OFFER_CHANGED",
|
|
1519
|
+
// ── withdrawing a feature for an external reason ──
|
|
1520
|
+
/**
|
|
1521
|
+
* Withdrawing a feature is not offered: the installation's stores cannot
|
|
1522
|
+
* list everybody a withdrawal would reach.
|
|
1523
|
+
*/
|
|
1524
|
+
FEATURE_WITHDRAWAL_UNAVAILABLE: "FEATURE_WITHDRAWAL_UNAVAILABLE",
|
|
1525
|
+
/** The catalogue knows no feature of that key, so there is nothing to withdraw. Carries `featureKey`. */
|
|
1526
|
+
FEATURE_WITHDRAWAL_FEATURE_UNKNOWN: "FEATURE_WITHDRAWAL_FEATURE_UNKNOWN",
|
|
1527
|
+
/**
|
|
1528
|
+
* The date names a moment before now. A feature is withdrawn from the
|
|
1529
|
+
* moment it is announced or from a later date: the days before were
|
|
1530
|
+
* delivered.
|
|
1531
|
+
*/
|
|
1532
|
+
FEATURE_WITHDRAWAL_DATE_IN_PAST: "FEATURE_WITHDRAWAL_DATE_IN_PAST",
|
|
1533
|
+
/** A withdrawal of the feature is not lifted yet; one at a time. Carries `featureKey`. */
|
|
1534
|
+
FEATURE_WITHDRAWAL_OPEN: "FEATURE_WITHDRAWAL_OPEN",
|
|
1535
|
+
/**
|
|
1536
|
+
* A withdrawal of the feature is lifted only from a date after the one
|
|
1537
|
+
* named, so the two would overlap. Carries `featureKey` and the `date` a
|
|
1538
|
+
* new one may begin on.
|
|
1539
|
+
*/
|
|
1540
|
+
FEATURE_WITHDRAWAL_OVERLAPS: "FEATURE_WITHDRAWAL_OVERLAPS",
|
|
1541
|
+
/**
|
|
1542
|
+
* A reduction names a plan or an add-on, in a rhythm, that no line the
|
|
1543
|
+
* withdrawal reaches is. Carries `kind`, `key` and `billingCycle`.
|
|
1544
|
+
*/
|
|
1545
|
+
FEATURE_WITHDRAWAL_REDUCTION_NOT_REACHED: "FEATURE_WITHDRAWAL_REDUCTION_NOT_REACHED",
|
|
1546
|
+
/** A reduction is named twice. Carries `kind`, `key` and `billingCycle`. */
|
|
1547
|
+
FEATURE_WITHDRAWAL_REDUCTION_NAMED_TWICE: "FEATURE_WITHDRAWAL_REDUCTION_NAMED_TWICE",
|
|
1548
|
+
/**
|
|
1549
|
+
* A reduction is more than the lowest price among the lines it reduces:
|
|
1550
|
+
* a price is reduced to nothing at most. Carries `key`, `billingCycle` and
|
|
1551
|
+
* that `price`.
|
|
1552
|
+
*/
|
|
1553
|
+
FEATURE_WITHDRAWAL_REDUCTION_EXCEEDS_PRICE: "FEATURE_WITHDRAWAL_REDUCTION_EXCEEDS_PRICE",
|
|
1554
|
+
/**
|
|
1555
|
+
* The subscriptions the withdrawal reaches changed since the preview the
|
|
1556
|
+
* operator looked at. Nothing was announced; carries the current `preview`.
|
|
1557
|
+
*/
|
|
1558
|
+
FEATURE_WITHDRAWAL_PREVIEW_CHANGED: "FEATURE_WITHDRAWAL_PREVIEW_CHANGED",
|
|
1559
|
+
/** No withdrawal has that id. Carries `withdrawalId`. */
|
|
1560
|
+
FEATURE_WITHDRAWAL_NOT_FOUND: "FEATURE_WITHDRAWAL_NOT_FOUND",
|
|
1561
|
+
/** The withdrawal was lifted already. Carries the `date` it is lifted from. */
|
|
1562
|
+
FEATURE_WITHDRAWAL_ALREADY_LIFTED: "FEATURE_WITHDRAWAL_ALREADY_LIFTED",
|
|
1563
|
+
/**
|
|
1564
|
+
* Nobody the withdrawal reaches has been told of it yet, and telling them
|
|
1565
|
+
* failed just now: a withdrawal is lifted only once they were. Nothing was
|
|
1566
|
+
* lifted; the next try, or the quarter-hourly run, tells them first.
|
|
1567
|
+
*/
|
|
1568
|
+
FEATURE_WITHDRAWAL_NOT_TOLD_YET: "FEATURE_WITHDRAWAL_NOT_TOLD_YET",
|
|
1569
|
+
/**
|
|
1570
|
+
* The date a withdrawal would be lifted from lies before now: what was
|
|
1571
|
+
* withdrawn until then was withdrawn.
|
|
1572
|
+
*/
|
|
1573
|
+
FEATURE_WITHDRAWAL_LIFT_IN_PAST: "FEATURE_WITHDRAWAL_LIFT_IN_PAST",
|
|
1574
|
+
/**
|
|
1575
|
+
* The withdrawal does not take its feature away now — its date is ahead,
|
|
1576
|
+
* or it was lifted — so nothing ends at once because of it. Carries
|
|
1577
|
+
* `featureKey`.
|
|
1578
|
+
*/
|
|
1579
|
+
FEATURE_WITHDRAWAL_NOT_IN_EFFECT: "FEATURE_WITHDRAWAL_NOT_IN_EFFECT",
|
|
1580
|
+
/**
|
|
1581
|
+
* The withdrawal did not reach the subscription, or the line to end: it
|
|
1582
|
+
* was not running at the announcement, or no longer holds the feature.
|
|
1583
|
+
*/
|
|
1584
|
+
FEATURE_WITHDRAWAL_DOES_NOT_REACH: "FEATURE_WITHDRAWAL_DOES_NOT_REACH",
|
|
1585
|
+
/** What was to be ended at once has ended already. */
|
|
1586
|
+
FEATURE_WITHDRAWAL_ALREADY_ENDED: "FEATURE_WITHDRAWAL_ALREADY_ENDED",
|
|
1587
|
+
/**
|
|
1588
|
+
* A cancellation is declared for a later date, and the installation's
|
|
1589
|
+
* subscription write or booking store cannot bring it forward (`endNow`).
|
|
1590
|
+
* It ends as declared. Carries that `date`.
|
|
1591
|
+
*/
|
|
1592
|
+
FEATURE_WITHDRAWAL_END_NOW_UNSUPPORTED: "FEATURE_WITHDRAWAL_END_NOW_UNSUPPORTED",
|
|
1199
1593
|
// ── the preview routes' own blockers and warnings ──
|
|
1200
1594
|
//
|
|
1201
1595
|
// These travel inside a 200 response, in `blockers[]` and `warnings[]`, not
|
|
@@ -1242,6 +1636,16 @@ var BILLING_ERROR_CODES = {
|
|
|
1242
1636
|
* day the booking can end.
|
|
1243
1637
|
*/
|
|
1244
1638
|
BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN: "BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN",
|
|
1639
|
+
/**
|
|
1640
|
+
* A bundle the tenant already holds can run on the plan they are moving
|
|
1641
|
+
* to, but the version it continues on from a retirement's date cannot.
|
|
1642
|
+
* Cancelling it lets the change through at once: the booking then ends
|
|
1643
|
+
* before that date and never reaches the version. Given while that date is
|
|
1644
|
+
* ahead and the booking is not cancelled yet; otherwise
|
|
1645
|
+
* `BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN` names the day it can end.
|
|
1646
|
+
* Carries the bundle, that version, its date and the plan.
|
|
1647
|
+
*/
|
|
1648
|
+
BUNDLE_REPLACEMENT_DOES_NOT_FIT_TARGET_PLAN: "BUNDLE_REPLACEMENT_DOES_NOT_FIT_TARGET_PLAN",
|
|
1245
1649
|
/**
|
|
1246
1650
|
* Features of the previewed bundle are already covered by the plan or by
|
|
1247
1651
|
* another booked bundle. A warning rather than a blocker: paying twice is
|
|
@@ -1311,6 +1715,21 @@ var CONTRACT_ERROR_CODES = {
|
|
|
1311
1715
|
* describes. Nothing was written; load the offer and conclude it again.
|
|
1312
1716
|
*/
|
|
1313
1717
|
CHECKOUT_OFFER_CHANGED: "CHECKOUT_OFFER_CHANGED",
|
|
1718
|
+
/**
|
|
1719
|
+
* An offer concludes a tenant's first contract, and this tenant has a
|
|
1720
|
+
* contract in force at the moment the offer's would take effect, or one
|
|
1721
|
+
* beginning after it. Concluded, the two would run side by side. Nothing
|
|
1722
|
+
* was written; a running subscription changes through its plan and its
|
|
1723
|
+
* add-ons. Carries the offer and the contract that runs.
|
|
1724
|
+
*/
|
|
1725
|
+
CHECKOUT_OFFER_CONTRACT_IN_FORCE: "CHECKOUT_OFFER_CONTRACT_IN_FORCE",
|
|
1726
|
+
/**
|
|
1727
|
+
* The offer names a version of an add-on the tenant has booked in another
|
|
1728
|
+
* version. Concluded, the contract would name a version the booking is not
|
|
1729
|
+
* on. Nothing was written; a booking changes its version through the offer
|
|
1730
|
+
* beside it. Carries the offer, the add-on, the booking and both versions.
|
|
1731
|
+
*/
|
|
1732
|
+
CHECKOUT_OFFER_ADD_ON_BOOKED_IN_ANOTHER_VERSION: "CHECKOUT_OFFER_ADD_ON_BOOKED_IN_ANOTHER_VERSION",
|
|
1314
1733
|
SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND",
|
|
1315
1734
|
NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT",
|
|
1316
1735
|
SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED",
|
|
@@ -1321,7 +1740,61 @@ var CONTRACT_ERROR_CODES = {
|
|
|
1321
1740
|
* second attempt, or a contract begins after the moment the successor
|
|
1322
1741
|
* would take effect. Nothing was written.
|
|
1323
1742
|
*/
|
|
1324
|
-
SUBSCRIPTION_CONTRACT_CHANGED: "SUBSCRIPTION_CONTRACT_CHANGED"
|
|
1743
|
+
SUBSCRIPTION_CONTRACT_CHANGED: "SUBSCRIPTION_CONTRACT_CHANGED",
|
|
1744
|
+
/**
|
|
1745
|
+
* A contract states a tax rate — `field` names where — other than the one
|
|
1746
|
+
* the installation's tax adapter decides for its subscriber.
|
|
1747
|
+
*/
|
|
1748
|
+
SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_DECIDED: "SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_DECIDED"
|
|
1749
|
+
};
|
|
1750
|
+
var INVOICE_ERROR_CODES = {
|
|
1751
|
+
/**
|
|
1752
|
+
* A charge already stands on an invoice: a second run issuing the same
|
|
1753
|
+
* charges lost the race. Nothing is written and no number is drawn.
|
|
1754
|
+
*/
|
|
1755
|
+
SUBSCRIPTION_INVOICE_CHARGE_INVOICED: "SUBSCRIPTION_INVOICE_CHARGE_INVOICED",
|
|
1756
|
+
/**
|
|
1757
|
+
* The invoice lacks content the tax adapter requires of it — `missing`
|
|
1758
|
+
* names the fields, `adapter` the adapter. It draws no number and waits
|
|
1759
|
+
* until what is missing is supplied (`SC-PRIC-027`).
|
|
1760
|
+
*/
|
|
1761
|
+
SUBSCRIPTION_INVOICE_CONTENT_INCOMPLETE: "SUBSCRIPTION_INVOICE_CONTENT_INCOMPLETE",
|
|
1762
|
+
/**
|
|
1763
|
+
* The contract's parties were copied by a migration and the operator has
|
|
1764
|
+
* not confirmed them yet; its charges are not invoiced until then
|
|
1765
|
+
* (`SC-AUD-012`).
|
|
1766
|
+
*/
|
|
1767
|
+
SUBSCRIPTION_INVOICE_PARTIES_UNCONFIRMED: "SUBSCRIPTION_INVOICE_PARTIES_UNCONFIRMED",
|
|
1768
|
+
/**
|
|
1769
|
+
* A file of the invoice's document has another checksum than the one
|
|
1770
|
+
* recorded or archived for it (`invoiceId`, `recorded`, `rendered`), and
|
|
1771
|
+
* the first stays. The run takes the archived file as the one issued, or —
|
|
1772
|
+
* where nothing is archived — records the new rendering in place of the
|
|
1773
|
+
* old (`SC-AUD-019`); the invoice waits only where another run changed the
|
|
1774
|
+
* record or the archive in between, and the next run settles it.
|
|
1775
|
+
*/
|
|
1776
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_CHANGED: "SUBSCRIPTION_INVOICE_DOCUMENT_CHANGED",
|
|
1777
|
+
/**
|
|
1778
|
+
* The tax adapter refuses the rendered document — `missing` names what it
|
|
1779
|
+
* lacks or disagrees with, `adapter` the adapter. The invoice keeps its
|
|
1780
|
+
* number and waits for a document that passes (`SC-PRIC-042`).
|
|
1781
|
+
*/
|
|
1782
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_REFUSED: "SUBSCRIPTION_INVOICE_DOCUMENT_REFUSED",
|
|
1783
|
+
/**
|
|
1784
|
+
* The archived document does not match the checksum recorded when it was
|
|
1785
|
+
* rendered (`invoiceId`). It is not handed out (`SC-AUD-019`).
|
|
1786
|
+
*/
|
|
1787
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_MISMATCH: "SUBSCRIPTION_INVOICE_DOCUMENT_MISMATCH",
|
|
1788
|
+
/** The invoice's document is not archived yet (`invoiceId`); nothing is offered until it is (`SC-AUD-014`). */
|
|
1789
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_NOT_ARCHIVED: "SUBSCRIPTION_INVOICE_DOCUMENT_NOT_ARCHIVED",
|
|
1790
|
+
/** No invoice with this id (`invoiceId`). */
|
|
1791
|
+
SUBSCRIPTION_INVOICE_NOT_FOUND: "SUBSCRIPTION_INVOICE_NOT_FOUND",
|
|
1792
|
+
/**
|
|
1793
|
+
* The subscriber's record holds no invoice email (`subscriberId`), so the
|
|
1794
|
+
* archived invoice cannot be sent (`SC-PRIC-047`); it is sent once one is
|
|
1795
|
+
* entered.
|
|
1796
|
+
*/
|
|
1797
|
+
SUBSCRIPTION_INVOICE_NO_INVOICE_EMAIL: "SUBSCRIPTION_INVOICE_NO_INVOICE_EMAIL"
|
|
1325
1798
|
};
|
|
1326
1799
|
var SUBSCRIBER_ERROR_CODES = {
|
|
1327
1800
|
/**
|
|
@@ -1345,7 +1818,30 @@ var SUBSCRIBER_ERROR_CODES = {
|
|
|
1345
1818
|
SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "SUBSCRIBER_CORRECTION_ACTOR_REQUIRED",
|
|
1346
1819
|
SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "SUBSCRIBER_CORRECTION_CHANGES_NOTHING",
|
|
1347
1820
|
/** The operator declared another legal entity: that is a transfer, not an edit. */
|
|
1348
|
-
SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "SUBSCRIBER_TAKEOVER_IS_A_TRANSFER"
|
|
1821
|
+
SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "SUBSCRIBER_TAKEOVER_IS_A_TRANSFER",
|
|
1822
|
+
/**
|
|
1823
|
+
* A contact change named whether the subscriber is a business. That is part
|
|
1824
|
+
* of its tax origin and changes as a recorded change naming who made it.
|
|
1825
|
+
*/
|
|
1826
|
+
SUBSCRIBER_BUSINESS_STATUS_NOT_A_CONTACT: "SUBSCRIBER_BUSINESS_STATUS_NOT_A_CONTACT",
|
|
1827
|
+
/** A change of the subscriber's contact details or business status did not say who makes it. */
|
|
1828
|
+
SUBSCRIBER_CHANGE_ACTOR_REQUIRED: "SUBSCRIBER_CHANGE_ACTOR_REQUIRED",
|
|
1829
|
+
/**
|
|
1830
|
+
* Where a tax adapter decides, a contract names its subscriber only once
|
|
1831
|
+
* the address an invoice names is complete (`SC-PRIC-032`): a party copied
|
|
1832
|
+
* onto a contract incomplete cannot be completed afterwards. Carries
|
|
1833
|
+
* `missing`, the empty fields, for a screen to name by their labels; the
|
|
1834
|
+
* shipped sentence names all four rather than the keys.
|
|
1835
|
+
*/
|
|
1836
|
+
SUBSCRIBER_IDENTITY_INCOMPLETE: "SUBSCRIBER_IDENTITY_INCOMPLETE",
|
|
1837
|
+
/**
|
|
1838
|
+
* A change of whether the subscriber is a business states no reason. It
|
|
1839
|
+
* decides the tax treatment of the next invoice, so the change log keeps
|
|
1840
|
+
* why it moved (`SC-PRIC-043`).
|
|
1841
|
+
*/
|
|
1842
|
+
SUBSCRIBER_BUSINESS_STATUS_REASON_REQUIRED: "SUBSCRIBER_BUSINESS_STATUS_REASON_REQUIRED",
|
|
1843
|
+
/** A check of the subscriber's VAT identification number was asked for, and it holds none. */
|
|
1844
|
+
SUBSCRIBER_VAT_ID_MISSING: "SUBSCRIBER_VAT_ID_MISSING"
|
|
1349
1845
|
};
|
|
1350
1846
|
var REGISTRATION_ERROR_CODES = {
|
|
1351
1847
|
PENDING_REGISTRATION_NOT_FOUND: "PENDING_REGISTRATION_NOT_FOUND",
|
|
@@ -1450,6 +1946,29 @@ var MAINTENANCE_ERROR_CODES = {
|
|
|
1450
1946
|
/** The message is longer than `MAINTENANCE_MESSAGE_MAX_LENGTH`. */
|
|
1451
1947
|
MAINTENANCE_MESSAGE_TOO_LONG: "MAINTENANCE_MESSAGE_TOO_LONG"
|
|
1452
1948
|
};
|
|
1949
|
+
var TAX_ERROR_CODES = {
|
|
1950
|
+
/**
|
|
1951
|
+
* The tax adapter answers that it does not support the subscriber's case;
|
|
1952
|
+
* `adapter` names it and `reason` is its sentence. Nothing is concluded with
|
|
1953
|
+
* a guessed tax (`SC-PRIC-039`).
|
|
1954
|
+
*/
|
|
1955
|
+
TAX_TREATMENT_NOT_SUPPORTED: "TAX_TREATMENT_NOT_SUPPORTED",
|
|
1956
|
+
/**
|
|
1957
|
+
* The tax adapter needs the VAT identification number checked to treat the
|
|
1958
|
+
* case, and the check did not complete — the service is unavailable, timed
|
|
1959
|
+
* out, or answered in a way the adapter cannot read (`503`). Nothing is
|
|
1960
|
+
* decided in the subscriber's favour on a number not checked
|
|
1961
|
+
* (`SC-PRIC-040`): try again later. `adapter` names the adapter and
|
|
1962
|
+
* `reason` says why.
|
|
1963
|
+
*/
|
|
1964
|
+
TAX_VAT_ID_CHECK_NOT_COMPLETED: "TAX_VAT_ID_CHECK_NOT_COMPLETED",
|
|
1965
|
+
/**
|
|
1966
|
+
* A VAT identification number was to be checked, and `config/saas.yaml`
|
|
1967
|
+
* names no tax adapter, which is what names the service to check with
|
|
1968
|
+
* (`409`).
|
|
1969
|
+
*/
|
|
1970
|
+
TAX_VAT_ID_CHECK_NOT_AVAILABLE: "TAX_VAT_ID_CHECK_NOT_AVAILABLE"
|
|
1971
|
+
};
|
|
1453
1972
|
var PLATFORM_ERROR_CODES = {
|
|
1454
1973
|
...SETUP_ERROR_CODES,
|
|
1455
1974
|
...AUTH_ERROR_CODES,
|
|
@@ -1457,11 +1976,13 @@ var PLATFORM_ERROR_CODES = {
|
|
|
1457
1976
|
...CATALOG_ERROR_CODES,
|
|
1458
1977
|
...BILLING_ERROR_CODES,
|
|
1459
1978
|
...CONTRACT_ERROR_CODES,
|
|
1979
|
+
...INVOICE_ERROR_CODES,
|
|
1460
1980
|
...SUBSCRIBER_ERROR_CODES,
|
|
1461
1981
|
...REGISTRATION_ERROR_CODES,
|
|
1462
1982
|
...PAYMENT_ERROR_CODES,
|
|
1463
1983
|
...SETTINGS_ERROR_CODES,
|
|
1464
|
-
...MAINTENANCE_ERROR_CODES
|
|
1984
|
+
...MAINTENANCE_ERROR_CODES,
|
|
1985
|
+
...TAX_ERROR_CODES
|
|
1465
1986
|
};
|
|
1466
1987
|
|
|
1467
1988
|
// src/errors.ts
|
|
@@ -1508,7 +2029,14 @@ var OPTIONAL_CANONICAL_MODELS = {
|
|
|
1508
2029
|
MaintenanceWindow: ["core.maintenanceWindows"],
|
|
1509
2030
|
SubscriptionNotice: ["tenantBilling.subscriptionNotices"],
|
|
1510
2031
|
VersionRetirement: ["tenantBilling.versionRetirements"],
|
|
2032
|
+
BundleVersionRetirement: ["tenantBilling.bundleVersionRetirements"],
|
|
2033
|
+
FeatureWithdrawal: ["tenantBilling.featureWithdrawals"],
|
|
1511
2034
|
SubscriberLedgerEntry: ["entitlement.subscriberLedgerRepository"],
|
|
2035
|
+
SubscriptionInvoice: ["entitlement.subscriptionInvoiceRepository"],
|
|
2036
|
+
SubscriptionInvoiceLine: ["entitlement.subscriptionInvoiceRepository"],
|
|
2037
|
+
SubscriptionInvoiceNumber: ["entitlement.subscriptionInvoiceRepository"],
|
|
2038
|
+
SubscriptionInvoiceDocument: ["entitlement.subscriptionInvoiceRepository"],
|
|
2039
|
+
SubscriptionInvoiceArchive: ["entitlement.subscriptionInvoiceArchive"],
|
|
1512
2040
|
PromoCodeHold: ["promo.holdRepository"]
|
|
1513
2041
|
};
|
|
1514
2042
|
function membersLeftOut(notAdopted = []) {
|
|
@@ -1625,6 +2153,7 @@ var ERROR_MESSAGES_EN = {
|
|
|
1625
2153
|
PLAN_NOT_FOUND: "Plan '{planId}' not found",
|
|
1626
2154
|
PLAN_VERSION_NOT_FOUND: "PlanVersion '{versionId}' not found",
|
|
1627
2155
|
BUNDLE_NOT_FOUND: "Bundle '{bundleId}' not found",
|
|
2156
|
+
BUNDLE_DELETE_WHILE_RETIREMENT_MOVES_PENDING: "{count} bookings still move onto a version of {bundleKey}, as a retirement told them. The add-on can be deleted once they have.",
|
|
1628
2157
|
BUNDLE_VERSION_NOT_FOUND: "BundleVersion '{bundleVersionId}' not found",
|
|
1629
2158
|
FEATURE_NOT_FOUND: "Feature '{featureKey}' not found",
|
|
1630
2159
|
QUOTA_NOT_FOUND: "Quota '{quotaKey}' not found",
|
|
@@ -1680,9 +2209,37 @@ var ERROR_MESSAGES_EN = {
|
|
|
1680
2209
|
RETIREMENT_NOTHING_AFFECTED: "No running subscription is on version {version} of {planKey}, so there is nobody to tell.",
|
|
1681
2210
|
RETIREMENT_WITHIN_TWELVE_MONTHS: "{count} of these subscriptions were reached by a retirement within the last twelve months. A subscription is reached at most once a year.",
|
|
1682
2211
|
RETIREMENT_PREVIEW_CHANGED: "The subscriptions this retirement reaches changed since they were shown. Look at them again before announcing it.",
|
|
2212
|
+
BUNDLE_RETIREMENT_VERSION_ON_SALE: "Version {version} of {bundleKey} is still on sale. Publish the version that replaces it, and retire this one once its sale has ended, so nobody books it after the announcement.",
|
|
2213
|
+
BUNDLE_RETIREMENT_REPLACEMENT_NOT_ON_SALE: "Version {version} of {bundleKey} is not on sale, so bookings cannot continue on it.",
|
|
2214
|
+
BUNDLE_RETIREMENT_REPLACEMENT_OF_ANOTHER_BUNDLE: "The replacement is a version of {replacementBundleKey}, not of {bundleKey}. A booking continues on a version of its own add-on.",
|
|
2215
|
+
BUNDLE_RETIREMENT_REPLACEMENT_CANNOT_RUN: "{count} of these bookings run beside a plan that version {version} of {bundleKey} cannot run beside, so they cannot continue on it.",
|
|
2216
|
+
BUNDLE_RETIREMENT_NOTHING_AFFECTED: "No running booking is on version {version} of {bundleKey}, so there is nobody to tell.",
|
|
2217
|
+
BUNDLE_RETIREMENT_REINSTATE_REFUSED: "Version {version} of {bundleKey} is being retired, and this booking ends before it would move. Book version {replacementVersion} from {bookableFrom}, when this booking has ended.",
|
|
2218
|
+
BUNDLE_RETIREMENT_REINSTATE_REPLACEMENT_CANNOT_RUN: "Version {version} of {bundleKey} is being retired, and this booking ends before it would move. Version {replacementVersion}, which replaces it, cannot run beside your plan, or beside one your subscription is set to move to.",
|
|
2219
|
+
BUNDLE_RETIREMENT_REINSTATE_SUBSCRIPTION_ENDS: "Version {version} of {bundleKey} is being retired, and this booking ends before it would move. Your subscription ends by then as well.",
|
|
2220
|
+
BUNDLE_RETIREMENT_SWITCH_PLAN_CHANGES: "{bundleName} moves to its new version on {date}, and your plan changes before then, so the price a switch would keep is not known yet. Switch once your plan has changed, or let it move on that date.",
|
|
2221
|
+
BUNDLE_VERSION_OFFER_CHANGED: "The offer changed since it was shown. Look at the current one before switching.",
|
|
2222
|
+
FEATURE_WITHDRAWAL_UNAVAILABLE: "Withdrawing a feature is not offered here: the stores cannot list everybody a withdrawal reaches.",
|
|
2223
|
+
FEATURE_WITHDRAWAL_FEATURE_UNKNOWN: "The catalogue knows no feature {featureKey}.",
|
|
2224
|
+
FEATURE_WITHDRAWAL_DATE_IN_PAST: "A feature is withdrawn from now on or from a later date, never from a date already past.",
|
|
2225
|
+
FEATURE_WITHDRAWAL_OPEN: "{featureKey} is withdrawn already, and that withdrawal is not lifted. Lift it before announcing another.",
|
|
2226
|
+
FEATURE_WITHDRAWAL_OVERLAPS: "{featureKey} is withdrawn until {date}. Another withdrawal can begin on that date at the earliest.",
|
|
2227
|
+
FEATURE_WITHDRAWAL_REDUCTION_NOT_REACHED: "The reduction for {key} billed {billingCycle} names nothing this withdrawal reaches.",
|
|
2228
|
+
FEATURE_WITHDRAWAL_REDUCTION_NAMED_TWICE: "The reduction for {key} billed {billingCycle} is named twice.",
|
|
2229
|
+
FEATURE_WITHDRAWAL_REDUCTION_EXCEEDS_PRICE: "The reduction for {key} billed {billingCycle} is more than the lowest price it reduces, {price}.",
|
|
2230
|
+
FEATURE_WITHDRAWAL_PREVIEW_CHANGED: "The subscriptions this withdrawal reaches changed since they were shown. Look at them again before announcing it.",
|
|
2231
|
+
FEATURE_WITHDRAWAL_NOT_FOUND: "Feature withdrawal {withdrawalId} not found.",
|
|
2232
|
+
FEATURE_WITHDRAWAL_ALREADY_LIFTED: "This withdrawal is lifted already, from {date}.",
|
|
2233
|
+
FEATURE_WITHDRAWAL_NOT_TOLD_YET: "Nobody has been told of this withdrawal yet, and it is not lifted before they are. Try again in a moment.",
|
|
2234
|
+
FEATURE_WITHDRAWAL_LIFT_IN_PAST: "A withdrawal is lifted from now on or from a later date, never from a date already past.",
|
|
2235
|
+
FEATURE_WITHDRAWAL_NOT_IN_EFFECT: "{featureKey} is not withdrawn now, so nothing can be ended at once because of it.",
|
|
2236
|
+
FEATURE_WITHDRAWAL_DOES_NOT_REACH: "This withdrawal does not reach your subscription, or no longer this booking.",
|
|
2237
|
+
FEATURE_WITHDRAWAL_ALREADY_ENDED: "This has ended already.",
|
|
2238
|
+
FEATURE_WITHDRAWAL_END_NOW_UNSUPPORTED: "Your cancellation for {date} is recorded, and it cannot be brought forward here. It ends on that date, and until then the reduction applies.",
|
|
1683
2239
|
RETIREMENT_SWITCH_NOT_PENDING: "No retirement of your version is waiting for its date, so there is nothing to switch to.",
|
|
1684
2240
|
RETIREMENT_SWITCH_IN_TRIAL: "The switch opens when your trial ends.",
|
|
1685
2241
|
RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW: "{bundleName} cannot run on {planName} and runs until {until} at the earliest. Once it is cancelled, the switch can be made from that day.",
|
|
2242
|
+
RETIREMENT_SWITCH_BUNDLE_REPLACEMENT_CANNOT_FOLLOW: "{bundleName} continues on version {version} from {from}, which cannot run on {planName}. Once it is cancelled, the switch can be made.",
|
|
1686
2243
|
RETIREMENT_SWITCH_NOT_OPEN: "This subscription cannot switch now: a change is scheduled, it has ended, or its plan is held for a special contract.",
|
|
1687
2244
|
RETIREMENT_SWITCH_CHANGED: "The retirement changed since it was shown. Look at it again before switching.",
|
|
1688
2245
|
SUBSCRIPTION_ENDED: "This subscription has ended. Its plan can no longer be changed.",
|
|
@@ -1695,6 +2252,7 @@ var ERROR_MESSAGES_EN = {
|
|
|
1695
2252
|
CYCLE_SHORTENS_AT_TERM_END: "A monthly {planName} cannot start inside the yearly term you are in. The upgrade takes effect when that term ends; to have it today, keep the yearly cycle.",
|
|
1696
2253
|
BUNDLE_BOOKING_OUTLASTS_TARGET_CYCLE: "{bundleName} is billed yearly and runs until {until} at the earliest, which a monthly plan cannot carry. Once it is cancelled, a change that takes effect on or after that day goes through \u2014 or keep the yearly cycle.",
|
|
1697
2254
|
BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN: "{bundleName} cannot run on {planName} and runs until {until} at the earliest. Once it is cancelled, a change that takes effect on or after that day goes through \u2014 or choose another plan.",
|
|
2255
|
+
BUNDLE_REPLACEMENT_DOES_NOT_FIT_TARGET_PLAN: "{bundleName} continues on version {version} from {from}, which cannot run on {planName}. Cancel it, and the change goes through \u2014 or choose another plan.",
|
|
1698
2256
|
REDUNDANT_FEATURES: "The plan or another booked bundle already includes {count} of the features in this bundle \u2014 booking it pays for them twice.",
|
|
1699
2257
|
MINIMUM_TERM_BINDS: "The minimum term extends beyond the end of the period \u2014 the cancellation only takes effect when the minimum term ends.",
|
|
1700
2258
|
BUNDLE_FEATURE_DEPENDENCY_UNSATISFIED: "The bundle requires [{features}] \u2014 present neither in the plan nor in the active bundles.",
|
|
@@ -1719,6 +2277,16 @@ var ERROR_MESSAGES_EN = {
|
|
|
1719
2277
|
PROMO_WOULD_PRODUCE_ZERO_INVOICE: "For absolute amounts the discount must stay below the lowest applicable plan price, or allowZeroInvoice must be enabled.",
|
|
1720
2278
|
PROMO_MAX_REDEMPTIONS_LOWERED: "maxRedemptions cannot be lowered.",
|
|
1721
2279
|
// ── contract ──
|
|
2280
|
+
SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_DECIDED: "The contract states {stated} % in {field}, and the tax adapter decides {decided} %.",
|
|
2281
|
+
SUBSCRIPTION_INVOICE_CHARGE_INVOICED: "Charge '{chargeId}' already stands on an invoice.",
|
|
2282
|
+
SUBSCRIPTION_INVOICE_CONTENT_INCOMPLETE: "The invoice lacks what the tax adapter {adapter} requires of it: {missing}. It is issued once that is supplied.",
|
|
2283
|
+
SUBSCRIPTION_INVOICE_PARTIES_UNCONFIRMED: "Contract {contractId} names no confirmed issuer and subscriber \u2014 a migration copied its parties, or it names no issuer \u2014 so its charges are not invoiced.",
|
|
2284
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_CHANGED: "The document of invoice {invoiceId} differs from the one recorded or archived for it ({rendered} instead of {recorded}); the first stays, and the next run settles which one the invoice keeps.",
|
|
2285
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_REFUSED: "The tax adapter {adapter} refuses the rendered invoice: {missing}. The invoice keeps its number and waits for a document that passes.",
|
|
2286
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_MISMATCH: "The archived document of invoice {invoiceId} does not match the checksum recorded when it was rendered, and is not handed out.",
|
|
2287
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_NOT_ARCHIVED: "The document of invoice {invoiceId} is not archived yet.",
|
|
2288
|
+
SUBSCRIPTION_INVOICE_NOT_FOUND: "No invoice '{invoiceId}'.",
|
|
2289
|
+
SUBSCRIPTION_INVOICE_NO_INVOICE_EMAIL: "Subscriber {subscriberId} has no invoice email, so its invoice cannot be sent; it is sent once one is entered.",
|
|
1722
2290
|
CHECKOUT_OFFER_LINE_ITEMS_REQUIRED: "A checkout offer can yield only one contract, and only once its line items are frozen.",
|
|
1723
2291
|
CHECKOUT_OFFER_PLAN_LINE_ITEM_REQUIRED: "A checkout offer requires a frozen plan line item.",
|
|
1724
2292
|
CHECKOUT_OFFER_BUNDLE_LINE_ITEMS_REQUIRED: "Every selected bundle version requires a frozen bundle line item.",
|
|
@@ -1743,6 +2311,8 @@ var ERROR_MESSAGES_EN = {
|
|
|
1743
2311
|
CHECKOUT_OFFER_ALREADY_CONSUMED: "Checkout offer '{offerId}' has already been consumed and cannot be {action}",
|
|
1744
2312
|
CHECKOUT_OFFER_NOT_CONSUMED: "CheckoutOffer '{offerId}' must be consumed before the contract is created",
|
|
1745
2313
|
CHECKOUT_OFFER_CHANGED: "Checkout offer '{offerId}' changed while it was being concluded. Load it again.",
|
|
2314
|
+
CHECKOUT_OFFER_CONTRACT_IN_FORCE: "Checkout offer '{offerId}' concludes a first contract, and this tenant already has one. A running subscription changes through its plan and its add-ons.",
|
|
2315
|
+
CHECKOUT_OFFER_ADD_ON_BOOKED_IN_ANOTHER_VERSION: "Checkout offer '{offerId}' names version {offeredVersion} of add-on '{bundleKey}', which this tenant has booked in version {bookedVersion} (booking {subscriptionBundleId}). Its version changes through the offer beside the add-on.",
|
|
1746
2316
|
SUBSCRIPTION_CONTRACT_NOT_FOUND: "SubscriptionContract '{contractId}' not found",
|
|
1747
2317
|
NO_ACTIVE_SUBSCRIPTION_CONTRACT: "No active subscription contract for tenant {tenantId}",
|
|
1748
2318
|
SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SubscriptionContract '{contractId}' is already closed",
|
|
@@ -1753,11 +2323,16 @@ var ERROR_MESSAGES_EN = {
|
|
|
1753
2323
|
SUBSCRIBER_NOT_FOUND: "Subscriber '{subscriberId}' not found",
|
|
1754
2324
|
SUBSCRIBER_LEGAL_NAME_REQUIRED: "A subscriber needs its legal name.",
|
|
1755
2325
|
SUBSCRIBER_DETAIL_INVALID: "The subscriber's {field} is not valid.",
|
|
2326
|
+
SUBSCRIBER_IDENTITY_INCOMPLETE: "The subscriber's billing address is not complete yet: a contract names it only with street and number, postal code, city and country.",
|
|
1756
2327
|
SUBSCRIBER_IDENTITY_NOT_A_CONTACT: "{field} is part of the subscriber's legal identity and changes only as a correction, with a reason.",
|
|
2328
|
+
SUBSCRIBER_BUSINESS_STATUS_REASON_REQUIRED: "A change of whether the subscriber is a business needs a reason.",
|
|
2329
|
+
SUBSCRIBER_VAT_ID_MISSING: "The subscriber has no VAT identification number to check.",
|
|
1757
2330
|
SUBSCRIBER_CORRECTION_REASON_REQUIRED: "A correction of the legal identity needs a reason.",
|
|
1758
2331
|
SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "A correction of the legal identity has to say who makes it.",
|
|
1759
2332
|
SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "The correction changes nothing: every value it names is already recorded.",
|
|
1760
2333
|
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.",
|
|
2334
|
+
SUBSCRIBER_BUSINESS_STATUS_NOT_A_CONTACT: "Whether the subscriber is a business is part of its tax origin and changes only as a recorded change that names who made it.",
|
|
2335
|
+
SUBSCRIBER_CHANGE_ACTOR_REQUIRED: "A change of the subscriber's details has to say who makes it.",
|
|
1761
2336
|
// ── registration ──
|
|
1762
2337
|
PENDING_REGISTRATION_NOT_FOUND: "This registration could not be found. It may have already been completed or discarded.",
|
|
1763
2338
|
PENDING_REGISTRATION_EXPIRED: "This registration has expired. Please start again.",
|
|
@@ -1791,7 +2366,11 @@ var ERROR_MESSAGES_EN = {
|
|
|
1791
2366
|
MAINTENANCE_WINDOW_END_NOT_AFTER_START: "The end of a maintenance window has to be after its start.",
|
|
1792
2367
|
MAINTENANCE_WINDOW_END_IN_PAST: "The end of a maintenance window cannot be in the past.",
|
|
1793
2368
|
MAINTENANCE_TIME_INVALID: "The {field} has to be a date and time with its zone, such as 2026-10-02T22:00+02:00.",
|
|
1794
|
-
MAINTENANCE_MESSAGE_TOO_LONG: "The message may be at most {max} characters long."
|
|
2369
|
+
MAINTENANCE_MESSAGE_TOO_LONG: "The message may be at most {max} characters long.",
|
|
2370
|
+
// ── tax ──
|
|
2371
|
+
TAX_TREATMENT_NOT_SUPPORTED: "The tax adapter {adapter} does not support this case: {reason}",
|
|
2372
|
+
TAX_VAT_ID_CHECK_NOT_COMPLETED: "The VAT identification number could not be checked just now ({reason}). Please try again later.",
|
|
2373
|
+
TAX_VAT_ID_CHECK_NOT_AVAILABLE: "This installation names no tax adapter, so no VAT identification number is checked."
|
|
1795
2374
|
};
|
|
1796
2375
|
function formatErrorMessage(template, params = {}) {
|
|
1797
2376
|
return template.replace(/\{(\w+)\}/g, (match, name) => {
|
|
@@ -2148,18 +2727,22 @@ var ORIGINS = {
|
|
|
2148
2727
|
renewal: true,
|
|
2149
2728
|
planChange: true,
|
|
2150
2729
|
bundleBooking: true,
|
|
2730
|
+
bundleChange: true,
|
|
2151
2731
|
credit: true,
|
|
2152
|
-
correction: true
|
|
2732
|
+
correction: true,
|
|
2733
|
+
reductionTakenBack: true
|
|
2153
2734
|
};
|
|
2154
2735
|
var SOURCES = {
|
|
2155
2736
|
plan: true,
|
|
2156
2737
|
bundle: true,
|
|
2157
2738
|
discount: true
|
|
2158
2739
|
};
|
|
2159
|
-
var
|
|
2740
|
+
var SUBSCRIBER_CHARGE_ORIGINS = keysOf(ORIGINS);
|
|
2741
|
+
var SUBSCRIBER_CHARGE_SOURCES = keysOf(SOURCES);
|
|
2742
|
+
var TABLE3 = "subscriber_ledger_entries";
|
|
2160
2743
|
var CENT_TOLERANCE = 1e-6;
|
|
2161
2744
|
function toSubscriberChargeRecord(row) {
|
|
2162
|
-
const where = (column) => ({ table:
|
|
2745
|
+
const where = (column) => ({ table: TABLE3, column, id: row.id });
|
|
2163
2746
|
return {
|
|
2164
2747
|
id: row.id,
|
|
2165
2748
|
subscriberId: row.subscriberId,
|
|
@@ -2167,8 +2750,8 @@ function toSubscriberChargeRecord(row) {
|
|
|
2167
2750
|
subscriptionId: row.subscriptionId,
|
|
2168
2751
|
contractId: row.contractId,
|
|
2169
2752
|
contractLineItemId: row.contractLineItemId,
|
|
2170
|
-
origin: oneOf(
|
|
2171
|
-
source: oneOf(
|
|
2753
|
+
origin: oneOf(SUBSCRIBER_CHARGE_ORIGINS, row.origin, where("origin")),
|
|
2754
|
+
source: oneOf(SUBSCRIBER_CHARGE_SOURCES, row.source, where("source")),
|
|
2172
2755
|
sourceRef: row.sourceRef,
|
|
2173
2756
|
periodStart: row.periodStart,
|
|
2174
2757
|
periodEnd: row.periodEnd,
|
|
@@ -2208,6 +2791,560 @@ function keysOf(record) {
|
|
|
2208
2791
|
// src/subscriber-ledger.types.ts
|
|
2209
2792
|
var SUBSCRIBER_ACCOUNT_CAPABILITY = "charges.read";
|
|
2210
2793
|
|
|
2794
|
+
// src/subscription-invoice.types.ts
|
|
2795
|
+
var INVOICE_SEQUENCE_DIGITS = 6;
|
|
2796
|
+
function formatInvoiceNumber(prefix, year, sequence) {
|
|
2797
|
+
if (!Number.isInteger(sequence) || sequence < 1) {
|
|
2798
|
+
throw new RangeError(`An invoice number's sequence starts at 1; ${sequence} is not one.`);
|
|
2799
|
+
}
|
|
2800
|
+
return `${prefix}-${year}-${String(sequence).padStart(INVOICE_SEQUENCE_DIGITS, "0")}`;
|
|
2801
|
+
}
|
|
2802
|
+
|
|
2803
|
+
// src/subscriber.types.ts
|
|
2804
|
+
var SUBSCRIBER_INVOICE_ADDRESS_FIELDS = [
|
|
2805
|
+
"addressLine1",
|
|
2806
|
+
"postalCode",
|
|
2807
|
+
"city",
|
|
2808
|
+
"country"
|
|
2809
|
+
];
|
|
2810
|
+
var SUBSCRIBER_STANDING_CAPABILITY = "subscribers.read";
|
|
2811
|
+
var SUBSCRIBER_ATTENTION_CAPABILITY = "subscribers.attention";
|
|
2812
|
+
var SUBSCRIBER_ATTENTION_PAGE_SIZE = 200;
|
|
2813
|
+
var SUBSCRIBER_CORRECTION_CAPABILITY = "subscribers.correct";
|
|
2814
|
+
var SUBSCRIBER_TAX_ORIGIN_FIELDS = ["country", "business", "vatId"];
|
|
2815
|
+
|
|
2816
|
+
// src/tax.types.ts
|
|
2817
|
+
var TAX_TREATMENT_KINDS = [
|
|
2818
|
+
"standard",
|
|
2819
|
+
"reduced",
|
|
2820
|
+
"exempt",
|
|
2821
|
+
"reverse-charge",
|
|
2822
|
+
"not-taxable",
|
|
2823
|
+
"small-business"
|
|
2824
|
+
];
|
|
2825
|
+
|
|
2826
|
+
// src/tax-origin.ts
|
|
2827
|
+
var VAT_ID_SEPARATORS = /[\s.-]/g;
|
|
2828
|
+
function canonicalVatId(written) {
|
|
2829
|
+
const vatId = written.replace(VAT_ID_SEPARATORS, "").toUpperCase();
|
|
2830
|
+
return vatId === "" ? null : vatId;
|
|
2831
|
+
}
|
|
2832
|
+
function taxOriginOf(subscriber, currentCheck) {
|
|
2833
|
+
const validated = subscriber.vatId !== null && currentCheck?.valid === true && currentCheck.vatId === subscriber.vatId;
|
|
2834
|
+
return {
|
|
2835
|
+
country: subscriber.country,
|
|
2836
|
+
business: subscriber.business,
|
|
2837
|
+
vatId: subscriber.vatId,
|
|
2838
|
+
validatedVatId: validated ? subscriber.vatId : null
|
|
2839
|
+
};
|
|
2840
|
+
}
|
|
2841
|
+
function keepsVatIdCheck(held, counting, check) {
|
|
2842
|
+
if (held.vatId === null || check.vatId !== held.vatId) return false;
|
|
2843
|
+
if (held.vatIdSince !== null && check.checkedAt.getTime() < held.vatIdSince.getTime()) {
|
|
2844
|
+
return false;
|
|
2845
|
+
}
|
|
2846
|
+
if (counting === null || counting.vatId !== held.vatId) return true;
|
|
2847
|
+
return counting.checkedAt.getTime() <= check.checkedAt.getTime();
|
|
2848
|
+
}
|
|
2849
|
+
function toSubscriberVatIdCheckRecord(row) {
|
|
2850
|
+
return {
|
|
2851
|
+
id: row.id,
|
|
2852
|
+
subscriberId: row.subscriberId,
|
|
2853
|
+
vatId: row.vatId,
|
|
2854
|
+
checkedAt: row.checkedAt,
|
|
2855
|
+
valid: row.valid,
|
|
2856
|
+
service: row.service,
|
|
2857
|
+
confirmation: textEntries(row.confirmation),
|
|
2858
|
+
recordedAt: row.recordedAt
|
|
2859
|
+
};
|
|
2860
|
+
}
|
|
2861
|
+
function taxTreatmentToJson(treatment) {
|
|
2862
|
+
return {
|
|
2863
|
+
kind: treatment.kind,
|
|
2864
|
+
rate: treatment.rate,
|
|
2865
|
+
note: treatment.note,
|
|
2866
|
+
adapter: { name: treatment.adapter.name, version: treatment.adapter.version }
|
|
2867
|
+
};
|
|
2868
|
+
}
|
|
2869
|
+
function toTaxTreatment(value) {
|
|
2870
|
+
if (!isObject(value)) return null;
|
|
2871
|
+
const { kind, rate, note, adapter } = value;
|
|
2872
|
+
if (!isTreatmentKind(kind)) return null;
|
|
2873
|
+
if (typeof rate !== "number" || !Number.isFinite(rate)) return null;
|
|
2874
|
+
if (note !== null && typeof note !== "string") return null;
|
|
2875
|
+
if (!isObject(adapter)) return null;
|
|
2876
|
+
if (typeof adapter.name !== "string" || typeof adapter.version !== "string") return null;
|
|
2877
|
+
return { kind, rate, note, adapter: { name: adapter.name, version: adapter.version } };
|
|
2878
|
+
}
|
|
2879
|
+
function taxOriginWrite(current, next) {
|
|
2880
|
+
const previous = {};
|
|
2881
|
+
const changed = {};
|
|
2882
|
+
for (const field of SUBSCRIBER_TAX_ORIGIN_FIELDS) {
|
|
2883
|
+
const value = next[field];
|
|
2884
|
+
if (value === void 0 || value === current[field]) continue;
|
|
2885
|
+
previous[field] = current[field];
|
|
2886
|
+
changed[field] = value;
|
|
2887
|
+
}
|
|
2888
|
+
return {
|
|
2889
|
+
previous,
|
|
2890
|
+
changed,
|
|
2891
|
+
moved: Object.keys(changed).length > 0,
|
|
2892
|
+
endsCountingVatIdCheck: Object.prototype.hasOwnProperty.call(changed, "vatId")
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2895
|
+
function toTaxOriginValues(value) {
|
|
2896
|
+
if (!isObject(value)) return {};
|
|
2897
|
+
const values = {};
|
|
2898
|
+
for (const field of SUBSCRIBER_TAX_ORIGIN_FIELDS) {
|
|
2899
|
+
if (!Object.prototype.hasOwnProperty.call(value, field)) continue;
|
|
2900
|
+
const entry = value[field];
|
|
2901
|
+
if (field === "business") {
|
|
2902
|
+
values[field] = typeof entry === "boolean" ? entry : null;
|
|
2903
|
+
} else {
|
|
2904
|
+
values[field] = typeof entry === "string" ? entry : null;
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
return values;
|
|
2908
|
+
}
|
|
2909
|
+
function isTreatmentKind(value) {
|
|
2910
|
+
return TAX_TREATMENT_KINDS.includes(value);
|
|
2911
|
+
}
|
|
2912
|
+
function isObject(value) {
|
|
2913
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2914
|
+
}
|
|
2915
|
+
function vatIdCheckFromStore(value) {
|
|
2916
|
+
if (!isObject(value)) return null;
|
|
2917
|
+
const { vatId, checkedAt, valid, service, confirmation } = value;
|
|
2918
|
+
const at = checkedAt instanceof Date ? checkedAt : new Date(String(checkedAt));
|
|
2919
|
+
if (typeof vatId !== "string" || typeof valid !== "boolean" || typeof service !== "string") {
|
|
2920
|
+
return null;
|
|
2921
|
+
}
|
|
2922
|
+
if (checkedAt === void 0 || checkedAt === null || Number.isNaN(at.getTime())) return null;
|
|
2923
|
+
return { vatId, checkedAt: at, valid, service, confirmation: textEntries(confirmation) };
|
|
2924
|
+
}
|
|
2925
|
+
function textEntries(value) {
|
|
2926
|
+
if (!isObject(value)) return {};
|
|
2927
|
+
const entries = {};
|
|
2928
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
2929
|
+
if (typeof entry === "string") entries[key] = entry;
|
|
2930
|
+
}
|
|
2931
|
+
return entries;
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2934
|
+
// src/subscription-invoice-mapping.ts
|
|
2935
|
+
var INVOICES = "subscription_invoices";
|
|
2936
|
+
var LINES = "subscription_invoice_lines";
|
|
2937
|
+
var CENT_TOLERANCE2 = 1e-6;
|
|
2938
|
+
function toSubscriptionInvoiceRecord(row, lines) {
|
|
2939
|
+
const where = (column) => ({ table: INVOICES, column, id: row.id });
|
|
2940
|
+
const treatment = toTaxTreatment(row.taxTreatment);
|
|
2941
|
+
if (!treatment) {
|
|
2942
|
+
throw new Error(`${INVOICES}.taxTreatment of ${row.id} is not a tax treatment.`);
|
|
2943
|
+
}
|
|
2944
|
+
return {
|
|
2945
|
+
id: row.id,
|
|
2946
|
+
number: row.number,
|
|
2947
|
+
numberPrefix: row.numberPrefix,
|
|
2948
|
+
numberYear: row.numberYear,
|
|
2949
|
+
numberSequence: row.numberSequence,
|
|
2950
|
+
tenantId: row.tenantId,
|
|
2951
|
+
subscriberId: row.subscriberId,
|
|
2952
|
+
subscriptionId: row.subscriptionId,
|
|
2953
|
+
contractId: row.contractId,
|
|
2954
|
+
issuedAt: row.issuedAt,
|
|
2955
|
+
issueDate: dayOf2(row.issueDate, where("issueDate")),
|
|
2956
|
+
dueDate: dayOf2(row.dueDate, where("dueDate")),
|
|
2957
|
+
servicePeriodFrom: dayOf2(row.servicePeriodFrom, where("servicePeriodFrom")),
|
|
2958
|
+
servicePeriodUntil: dayOf2(row.servicePeriodUntil, where("servicePeriodUntil")),
|
|
2959
|
+
currency: row.currency,
|
|
2960
|
+
issuer: issuerOf(row.issuerParty, where("issuerParty")),
|
|
2961
|
+
subscriber: subscriberOf(row.subscriberParty, where("subscriberParty")),
|
|
2962
|
+
footer: footerOf(row.footer, where("footer")),
|
|
2963
|
+
taxTreatment: treatment,
|
|
2964
|
+
taxes: taxesOf(row.taxes, where("taxes")),
|
|
2965
|
+
totalNet: amountOf2(row.totalNet, where("totalNet")),
|
|
2966
|
+
totalTax: amountOf2(row.totalTax, where("totalTax")),
|
|
2967
|
+
totalGross: amountOf2(row.totalGross, where("totalGross")),
|
|
2968
|
+
lines: [...lines].sort((a, b) => a.position - b.position).map((line) => toSubscriptionInvoiceLineRecord(line)),
|
|
2969
|
+
createdAt: row.createdAt
|
|
2970
|
+
};
|
|
2971
|
+
}
|
|
2972
|
+
function toSubscriptionInvoiceLineRecord(row) {
|
|
2973
|
+
const where = (column) => ({ table: LINES, column, id: row.id });
|
|
2974
|
+
return {
|
|
2975
|
+
id: row.id,
|
|
2976
|
+
invoiceId: row.invoiceId,
|
|
2977
|
+
position: row.position,
|
|
2978
|
+
chargeId: row.chargeId,
|
|
2979
|
+
contractLineItemId: row.contractLineItemId,
|
|
2980
|
+
title: row.title,
|
|
2981
|
+
origin: oneOf(SUBSCRIBER_CHARGE_ORIGINS, row.origin, where("origin")),
|
|
2982
|
+
source: oneOf(SUBSCRIBER_CHARGE_SOURCES, row.source, where("source")),
|
|
2983
|
+
periodFrom: dayOf2(row.periodFrom, where("periodFrom")),
|
|
2984
|
+
periodUntil: dayOf2(row.periodUntil, where("periodUntil")),
|
|
2985
|
+
amountNet: amountOf2(row.amountNet, where("amountNet")),
|
|
2986
|
+
taxRate: amountOf2(row.taxRate, where("taxRate"))
|
|
2987
|
+
};
|
|
2988
|
+
}
|
|
2989
|
+
function subscriptionInvoiceColumns(invoice, drawn) {
|
|
2990
|
+
return {
|
|
2991
|
+
number: drawn.number,
|
|
2992
|
+
numberPrefix: invoice.numberPrefix,
|
|
2993
|
+
numberYear: invoice.numberYear,
|
|
2994
|
+
numberSequence: drawn.numberSequence,
|
|
2995
|
+
tenantId: invoice.tenantId,
|
|
2996
|
+
subscriberId: invoice.subscriberId,
|
|
2997
|
+
subscriptionId: invoice.subscriptionId,
|
|
2998
|
+
contractId: invoice.contractId,
|
|
2999
|
+
issuedAt: invoice.issuedAt,
|
|
3000
|
+
issueDate: invoice.issueDate,
|
|
3001
|
+
dueDate: invoice.dueDate,
|
|
3002
|
+
servicePeriodFrom: invoice.servicePeriodFrom,
|
|
3003
|
+
servicePeriodUntil: invoice.servicePeriodUntil,
|
|
3004
|
+
currency: invoice.currency,
|
|
3005
|
+
issuerParty: { ...invoice.issuer },
|
|
3006
|
+
subscriberParty: { ...invoice.subscriber },
|
|
3007
|
+
footer: [...invoice.footer],
|
|
3008
|
+
taxTreatment: taxTreatmentToJson(invoice.taxTreatment),
|
|
3009
|
+
taxes: invoice.taxes.map((entry) => ({ rate: entry.rate, net: entry.net, tax: entry.tax })),
|
|
3010
|
+
totalNet: centsText(invoice.totalNet, "totalNet"),
|
|
3011
|
+
totalTax: centsText(invoice.totalTax, "totalTax"),
|
|
3012
|
+
totalGross: centsText(invoice.totalGross, "totalGross")
|
|
3013
|
+
};
|
|
3014
|
+
}
|
|
3015
|
+
function subscriptionInvoiceLineColumns(line, invoiceId) {
|
|
3016
|
+
return {
|
|
3017
|
+
invoiceId,
|
|
3018
|
+
position: line.position,
|
|
3019
|
+
chargeId: line.chargeId,
|
|
3020
|
+
contractLineItemId: line.contractLineItemId,
|
|
3021
|
+
title: line.title,
|
|
3022
|
+
origin: line.origin,
|
|
3023
|
+
source: line.source,
|
|
3024
|
+
periodFrom: line.periodFrom,
|
|
3025
|
+
periodUntil: line.periodUntil,
|
|
3026
|
+
amountNet: centsText(line.amountNet, "amountNet"),
|
|
3027
|
+
taxRate: centsText(line.taxRate, "taxRate")
|
|
3028
|
+
};
|
|
3029
|
+
}
|
|
3030
|
+
function utcMidnightOf(day) {
|
|
3031
|
+
return /* @__PURE__ */ new Date(`${day}T00:00:00.000Z`);
|
|
3032
|
+
}
|
|
3033
|
+
var DAY_LENGTH = "YYYY-MM-DD".length;
|
|
3034
|
+
function dayOf2(value, where) {
|
|
3035
|
+
if (value instanceof Date && !Number.isNaN(value.getTime())) {
|
|
3036
|
+
return value.toISOString().slice(0, DAY_LENGTH);
|
|
3037
|
+
}
|
|
3038
|
+
if (typeof value === "string" && value.length === DAY_LENGTH && !Number.isNaN(Date.parse(value))) {
|
|
3039
|
+
return value;
|
|
3040
|
+
}
|
|
3041
|
+
throw new Error(`${where.table}.${where.column} of ${where.id} is not a day.`);
|
|
3042
|
+
}
|
|
3043
|
+
function footerOf(value, where) {
|
|
3044
|
+
if (!Array.isArray(value) || !value.every((line) => typeof line === "string")) {
|
|
3045
|
+
throw new Error(`${where.table}.${where.column} of ${where.id} is not a list of lines.`);
|
|
3046
|
+
}
|
|
3047
|
+
return [...value];
|
|
3048
|
+
}
|
|
3049
|
+
function amountOf2(value, where) {
|
|
3050
|
+
const amount = Number(value === null || value === void 0 ? NaN : String(value));
|
|
3051
|
+
if (!Number.isFinite(amount)) {
|
|
3052
|
+
throw new Error(`${where.table}.${where.column} of ${where.id} is not an amount.`);
|
|
3053
|
+
}
|
|
3054
|
+
return amount;
|
|
3055
|
+
}
|
|
3056
|
+
function centsText(amount, field) {
|
|
3057
|
+
const cents2 = amount * 100;
|
|
3058
|
+
if (!Number.isFinite(cents2) || Math.abs(cents2 - Math.round(cents2)) > CENT_TOLERANCE2) {
|
|
3059
|
+
throw new Error(
|
|
3060
|
+
`An invoice's ${field} of ${amount} is not a whole number of cents; it is rounded once, where the invoice is drafted, before it is written.`
|
|
3061
|
+
);
|
|
3062
|
+
}
|
|
3063
|
+
return amount.toFixed(2);
|
|
3064
|
+
}
|
|
3065
|
+
function textOrNull2(source, key, where) {
|
|
3066
|
+
const value = source[key];
|
|
3067
|
+
if (value === null || value === void 0) return null;
|
|
3068
|
+
if (typeof value !== "string") {
|
|
3069
|
+
throw new Error(`${where.table}.${where.column}.${key} of ${where.id} is not text.`);
|
|
3070
|
+
}
|
|
3071
|
+
return value;
|
|
3072
|
+
}
|
|
3073
|
+
function partyOf(value, where) {
|
|
3074
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
3075
|
+
throw new Error(`${where.table}.${where.column} of ${where.id} is not a party.`);
|
|
3076
|
+
}
|
|
3077
|
+
const source = value;
|
|
3078
|
+
const legalName = textOrNull2(source, "legalName", where);
|
|
3079
|
+
if (legalName === null) {
|
|
3080
|
+
throw new Error(`${where.table}.${where.column} of ${where.id} names no legal name.`);
|
|
3081
|
+
}
|
|
3082
|
+
return {
|
|
3083
|
+
legalName,
|
|
3084
|
+
vatId: textOrNull2(source, "vatId", where),
|
|
3085
|
+
taxNumber: textOrNull2(source, "taxNumber", where),
|
|
3086
|
+
addressLine1: textOrNull2(source, "addressLine1", where),
|
|
3087
|
+
addressLine2: textOrNull2(source, "addressLine2", where),
|
|
3088
|
+
postalCode: textOrNull2(source, "postalCode", where),
|
|
3089
|
+
city: textOrNull2(source, "city", where),
|
|
3090
|
+
country: textOrNull2(source, "country", where)
|
|
3091
|
+
};
|
|
3092
|
+
}
|
|
3093
|
+
function issuerOf(value, where) {
|
|
3094
|
+
return partyOf(value, where);
|
|
3095
|
+
}
|
|
3096
|
+
function subscriberOf(value, where) {
|
|
3097
|
+
const party = partyOf(value, where);
|
|
3098
|
+
const customerNumber = textOrNull2(value, "customerNumber", where);
|
|
3099
|
+
if (customerNumber === null) {
|
|
3100
|
+
throw new Error(`${where.table}.${where.column} of ${where.id} names no customer number.`);
|
|
3101
|
+
}
|
|
3102
|
+
return { ...party, customerNumber };
|
|
3103
|
+
}
|
|
3104
|
+
function taxesOf(value, where) {
|
|
3105
|
+
if (!Array.isArray(value)) {
|
|
3106
|
+
throw new Error(`${where.table}.${where.column} of ${where.id} is not a list of rates.`);
|
|
3107
|
+
}
|
|
3108
|
+
return value.map((entry) => {
|
|
3109
|
+
const item = entry ?? {};
|
|
3110
|
+
return {
|
|
3111
|
+
rate: amountOf2(item.rate, where),
|
|
3112
|
+
net: amountOf2(item.net, where),
|
|
3113
|
+
tax: amountOf2(item.tax, where)
|
|
3114
|
+
};
|
|
3115
|
+
});
|
|
3116
|
+
}
|
|
3117
|
+
|
|
3118
|
+
// src/subscription-invoice-refusals.ts
|
|
3119
|
+
function subscriptionInvoiceChargeInvoiced(chargeId) {
|
|
3120
|
+
return new PersistenceRefusal(
|
|
3121
|
+
INVOICE_ERROR_CODES.SUBSCRIPTION_INVOICE_CHARGE_INVOICED,
|
|
3122
|
+
"moved",
|
|
3123
|
+
`Charge '${chargeId}' already stands on an invoice.`,
|
|
3124
|
+
{ chargeId }
|
|
3125
|
+
);
|
|
3126
|
+
}
|
|
3127
|
+
function subscriptionInvoiceDocumentChanged(invoiceId, recorded, rendered) {
|
|
3128
|
+
return new PersistenceRefusal(
|
|
3129
|
+
INVOICE_ERROR_CODES.SUBSCRIPTION_INVOICE_DOCUMENT_CHANGED,
|
|
3130
|
+
"moved",
|
|
3131
|
+
`The document rendered for invoice '${invoiceId}' differs from the one recorded for it.`,
|
|
3132
|
+
{ invoiceId, recorded, rendered }
|
|
3133
|
+
);
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
// src/subscription-invoice-draft.ts
|
|
3137
|
+
function invoiceGroupsOf(charges) {
|
|
3138
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3139
|
+
for (const charge of charges) {
|
|
3140
|
+
const key = `${charge.contractId}|${charge.bookedAt.toISOString()}`;
|
|
3141
|
+
const group = groups.get(key);
|
|
3142
|
+
if (group) group.charges.push(charge);
|
|
3143
|
+
else
|
|
3144
|
+
groups.set(key, {
|
|
3145
|
+
contractId: charge.contractId,
|
|
3146
|
+
bookedAt: charge.bookedAt,
|
|
3147
|
+
charges: [charge]
|
|
3148
|
+
});
|
|
3149
|
+
}
|
|
3150
|
+
return [...groups.values()].filter((group) => group.charges.some((charge) => charge.amountNet !== 0)).sort(
|
|
3151
|
+
(a, b) => a.bookedAt.getTime() - b.bookedAt.getTime() || a.contractId.localeCompare(b.contractId)
|
|
3152
|
+
);
|
|
3153
|
+
}
|
|
3154
|
+
function draftSubscriptionInvoice(input) {
|
|
3155
|
+
const { group, treatment, timeZone } = input;
|
|
3156
|
+
const lines = linesOf(input);
|
|
3157
|
+
const issueDate = dayInZone(input.issuedAt, timeZone);
|
|
3158
|
+
const tax = input.tax(lines.map((line) => ({ net: line.amountNet, rate: line.taxRate })));
|
|
3159
|
+
return {
|
|
3160
|
+
numberPrefix: input.numberPrefix,
|
|
3161
|
+
numberYear: yearOfDay(issueDate),
|
|
3162
|
+
tenantId: input.tenantId,
|
|
3163
|
+
subscriberId: input.subscriberId,
|
|
3164
|
+
subscriptionId: group.charges[0].subscriptionId,
|
|
3165
|
+
contractId: group.contractId,
|
|
3166
|
+
issuedAt: input.issuedAt,
|
|
3167
|
+
issueDate,
|
|
3168
|
+
dueDate: addDaysToDay(issueDate, input.paymentTermDays),
|
|
3169
|
+
servicePeriodFrom: lines.map((line) => line.periodFrom).sort()[0],
|
|
3170
|
+
servicePeriodUntil: lines.map((line) => line.periodUntil).sort().at(-1),
|
|
3171
|
+
currency: currencyOf(group),
|
|
3172
|
+
issuer: input.issuer,
|
|
3173
|
+
subscriber: input.subscriber,
|
|
3174
|
+
footer: [...input.footer],
|
|
3175
|
+
taxTreatment: treatment,
|
|
3176
|
+
taxes: tax.rates,
|
|
3177
|
+
totalNet: tax.net,
|
|
3178
|
+
totalTax: tax.tax,
|
|
3179
|
+
totalGross: tax.gross,
|
|
3180
|
+
lines
|
|
3181
|
+
};
|
|
3182
|
+
}
|
|
3183
|
+
function invoiceContentDraftOf(invoice) {
|
|
3184
|
+
return {
|
|
3185
|
+
issuer: invoice.issuer,
|
|
3186
|
+
subscriber: invoice.subscriber,
|
|
3187
|
+
treatment: invoice.taxTreatment,
|
|
3188
|
+
issueDate: invoice.issueDate,
|
|
3189
|
+
dueDate: invoice.dueDate,
|
|
3190
|
+
servicePeriod: { from: invoice.servicePeriodFrom, until: invoice.servicePeriodUntil },
|
|
3191
|
+
lines: invoice.lines.map((line) => ({
|
|
3192
|
+
title: line.title,
|
|
3193
|
+
net: line.amountNet,
|
|
3194
|
+
rate: line.taxRate
|
|
3195
|
+
}))
|
|
3196
|
+
};
|
|
3197
|
+
}
|
|
3198
|
+
function linesOf(input) {
|
|
3199
|
+
const placeOf = new Map(input.contractLines.map((line, index) => [line.id, index]));
|
|
3200
|
+
const place = (charge) => {
|
|
3201
|
+
const index = placeOf.get(charge.contractLineItemId);
|
|
3202
|
+
if (index === void 0) {
|
|
3203
|
+
throw new Error(
|
|
3204
|
+
`Charge ${charge.id} names contract line ${charge.contractLineItemId}, which contract ${input.group.contractId} does not have.`
|
|
3205
|
+
);
|
|
3206
|
+
}
|
|
3207
|
+
return index;
|
|
3208
|
+
};
|
|
3209
|
+
return [...input.group.charges].sort(
|
|
3210
|
+
(a, b) => place(a) - place(b) || a.periodStart.getTime() - b.periodStart.getTime() || a.origin.localeCompare(b.origin)
|
|
3211
|
+
).map((charge, index) => ({
|
|
3212
|
+
position: index + 1,
|
|
3213
|
+
chargeId: charge.id,
|
|
3214
|
+
contractLineItemId: charge.contractLineItemId,
|
|
3215
|
+
title: input.contractLines[place(charge)].titleSnapshot,
|
|
3216
|
+
origin: charge.origin,
|
|
3217
|
+
source: charge.source,
|
|
3218
|
+
periodFrom: dayInZone(charge.periodStart, input.timeZone),
|
|
3219
|
+
periodUntil: lastDayInZone(
|
|
3220
|
+
{ from: charge.periodStart, until: charge.periodEnd },
|
|
3221
|
+
input.timeZone
|
|
3222
|
+
),
|
|
3223
|
+
amountNet: charge.amountNet,
|
|
3224
|
+
taxRate: input.treatment.rate
|
|
3225
|
+
}));
|
|
3226
|
+
}
|
|
3227
|
+
function currencyOf(group) {
|
|
3228
|
+
const currencies = new Set(group.charges.map((charge) => charge.currency));
|
|
3229
|
+
if (currencies.size !== 1) {
|
|
3230
|
+
throw new Error(
|
|
3231
|
+
`The charges of contract ${group.contractId} booked at ${group.bookedAt.toISOString()} are in ${[...currencies].join(" and ")}; an invoice is in one currency.`
|
|
3232
|
+
);
|
|
3233
|
+
}
|
|
3234
|
+
return [...currencies][0];
|
|
3235
|
+
}
|
|
3236
|
+
|
|
3237
|
+
// src/invoice-issuer.ts
|
|
3238
|
+
function invoiceIssuerOf(copy, configured, history) {
|
|
3239
|
+
const target = configured && identityOf2(configured);
|
|
3240
|
+
let reached = identityOf2(copy);
|
|
3241
|
+
if (!target || !reached) return { ...copy };
|
|
3242
|
+
for (const step of history) {
|
|
3243
|
+
if (sameLegalIdentity(reached, target)) break;
|
|
3244
|
+
const change = classifyIssuerChange(
|
|
3245
|
+
recordedIssuerIdentity(step.previous),
|
|
3246
|
+
issuerBlockOf(step.current)
|
|
3247
|
+
);
|
|
3248
|
+
if (change.kind === "corrected" && sameLegalIdentity(change.recorded, reached)) {
|
|
3249
|
+
reached = change.current;
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
return sameLegalIdentity(reached, target) ? { ...configured } : { ...copy };
|
|
3253
|
+
}
|
|
3254
|
+
function invoiceFooterOf(issuer, configured, footer) {
|
|
3255
|
+
const named = identityOf2(issuer);
|
|
3256
|
+
const target = configured && identityOf2(configured);
|
|
3257
|
+
return named && target && sameLegalIdentity(named, target) ? [...footer] : [];
|
|
3258
|
+
}
|
|
3259
|
+
function identityOf2(party) {
|
|
3260
|
+
return recordedIssuerIdentity({ issuer: party });
|
|
3261
|
+
}
|
|
3262
|
+
function issuerBlockOf(values) {
|
|
3263
|
+
const issuer = values.issuer;
|
|
3264
|
+
if (issuer === null || typeof issuer !== "object" || Array.isArray(issuer)) return void 0;
|
|
3265
|
+
return issuer;
|
|
3266
|
+
}
|
|
3267
|
+
|
|
3268
|
+
// src/invoice-document.types.ts
|
|
3269
|
+
var INVOICE_DOCUMENT_CAPABILITY = "invoices.read";
|
|
3270
|
+
|
|
3271
|
+
// src/invoice-document-mapping.ts
|
|
3272
|
+
var DOCUMENTS = "subscription_invoice_documents";
|
|
3273
|
+
var ARCHIVE = "subscription_invoice_archive";
|
|
3274
|
+
var CHECKSUM = /^[0-9a-f]{64}$/;
|
|
3275
|
+
function isInvoiceDocumentChecksum(value) {
|
|
3276
|
+
return typeof value === "string" && CHECKSUM.test(value);
|
|
3277
|
+
}
|
|
3278
|
+
function toSubscriptionInvoiceDocumentRecord(row) {
|
|
3279
|
+
if (!isInvoiceDocumentChecksum(row.checksum)) {
|
|
3280
|
+
throw new Error(`${DOCUMENTS}.checksum of ${row.invoiceId} is not a SHA-256 digest.`);
|
|
3281
|
+
}
|
|
3282
|
+
const size = Number(row.size);
|
|
3283
|
+
if (!Number.isSafeInteger(size) || size < 0) {
|
|
3284
|
+
throw new Error(`${DOCUMENTS}.size of ${row.invoiceId} is not a size in bytes.`);
|
|
3285
|
+
}
|
|
3286
|
+
return {
|
|
3287
|
+
invoiceId: row.invoiceId,
|
|
3288
|
+
checksum: row.checksum,
|
|
3289
|
+
mediaType: row.mediaType,
|
|
3290
|
+
fileName: row.fileName,
|
|
3291
|
+
size,
|
|
3292
|
+
renderedAt: row.renderedAt,
|
|
3293
|
+
archivedAt: row.archivedAt,
|
|
3294
|
+
deliveryClaimedAt: row.deliveryClaimedAt,
|
|
3295
|
+
deliveredAt: row.deliveredAt,
|
|
3296
|
+
deliveredTo: row.deliveredTo
|
|
3297
|
+
};
|
|
3298
|
+
}
|
|
3299
|
+
function toArchivedInvoiceDocument(row) {
|
|
3300
|
+
if (!isInvoiceDocumentChecksum(row.checksum)) {
|
|
3301
|
+
throw new Error(`${ARCHIVE}.checksum of ${row.invoiceId} is not a SHA-256 digest.`);
|
|
3302
|
+
}
|
|
3303
|
+
if (!(row.content instanceof Uint8Array)) {
|
|
3304
|
+
throw new Error(`${ARCHIVE}.content of ${row.invoiceId} is not a file.`);
|
|
3305
|
+
}
|
|
3306
|
+
return {
|
|
3307
|
+
invoiceId: row.invoiceId,
|
|
3308
|
+
checksum: row.checksum,
|
|
3309
|
+
mediaType: row.mediaType,
|
|
3310
|
+
fileName: row.fileName,
|
|
3311
|
+
// A copy that owns its bytes: a driver's `Buffer` may be a view into a
|
|
3312
|
+
// pooled allocation, and a caller handing it on must not see that pool.
|
|
3313
|
+
content: new Uint8Array(row.content),
|
|
3314
|
+
archivedAt: row.archivedAt
|
|
3315
|
+
};
|
|
3316
|
+
}
|
|
3317
|
+
var INVOICE_ARCHIVE_TRIGGERS = [
|
|
3318
|
+
"subscription_invoice_archive_is_kept",
|
|
3319
|
+
"subscription_invoice_archive_is_not_emptied"
|
|
3320
|
+
];
|
|
3321
|
+
function invoiceArchiveProtectionProblem(enabledTriggers) {
|
|
3322
|
+
const missing = INVOICE_ARCHIVE_TRIGGERS.filter((name) => !enabledTriggers.includes(name));
|
|
3323
|
+
if (missing.length === 0) return null;
|
|
3324
|
+
return `${ARCHIVE} lacks ${missing.join(" and ")}, which keep an archived invoice document as it was issued: run @saasicat/spec/sql/1.0-an-invoice-document-is-archived.postgres.sql after db push, and enable the triggers where they were disabled.`;
|
|
3325
|
+
}
|
|
3326
|
+
|
|
3327
|
+
// src/e-invoice-format.ts
|
|
3328
|
+
var CATEGORY = {
|
|
3329
|
+
standard: "S",
|
|
3330
|
+
reduced: "S",
|
|
3331
|
+
exempt: "E",
|
|
3332
|
+
"small-business": "E",
|
|
3333
|
+
"reverse-charge": "AE",
|
|
3334
|
+
"not-taxable": "O"
|
|
3335
|
+
};
|
|
3336
|
+
function vatCategoryOf(kind) {
|
|
3337
|
+
return CATEGORY[kind];
|
|
3338
|
+
}
|
|
3339
|
+
var NOT_XML = /[^\t\n\r\u0020-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/gu;
|
|
3340
|
+
function holdsOnlyXmlCharacters(text) {
|
|
3341
|
+
return text.search(NOT_XML) === -1;
|
|
3342
|
+
}
|
|
3343
|
+
var CARRIAGE_RETURN = /\r\n?/g;
|
|
3344
|
+
function asXmlReadsIt(text) {
|
|
3345
|
+
return text.replace(NOT_XML, "?").replace(CARRIAGE_RETURN, "\n");
|
|
3346
|
+
}
|
|
3347
|
+
|
|
2211
3348
|
// src/subscriber-mapping.ts
|
|
2212
3349
|
function formatCustomerNumber(prefix, sequence) {
|
|
2213
3350
|
return `${prefix}${sequence}`;
|
|
@@ -2225,6 +3362,7 @@ function toSubscriberRecord(row, tenantId) {
|
|
|
2225
3362
|
vatId: row.vatId,
|
|
2226
3363
|
taxNumber: row.taxNumber,
|
|
2227
3364
|
invoiceEmail: row.invoiceEmail,
|
|
3365
|
+
business: row.business,
|
|
2228
3366
|
tenantId,
|
|
2229
3367
|
migrated: row.migrated,
|
|
2230
3368
|
createdAt: row.createdAt,
|
|
@@ -2242,6 +3380,17 @@ function toSubscriberCorrectionRecord(row) {
|
|
|
2242
3380
|
correctedAt: row.correctedAt
|
|
2243
3381
|
};
|
|
2244
3382
|
}
|
|
3383
|
+
function toSubscriberTaxOriginChangeRecord(row) {
|
|
3384
|
+
return {
|
|
3385
|
+
id: row.id,
|
|
3386
|
+
subscriberId: row.subscriberId,
|
|
3387
|
+
previous: toTaxOriginValues(row.previous),
|
|
3388
|
+
changed: toTaxOriginValues(row.changed),
|
|
3389
|
+
changedBy: row.changedBy,
|
|
3390
|
+
changedAt: row.changedAt,
|
|
3391
|
+
reason: row.reason
|
|
3392
|
+
};
|
|
3393
|
+
}
|
|
2245
3394
|
function identityCorrectionDelta(current, corrected) {
|
|
2246
3395
|
const previous = {};
|
|
2247
3396
|
const next = {};
|
|
@@ -2305,7 +3454,9 @@ function subscriberFromRegistration(pending) {
|
|
|
2305
3454
|
city: pending.city,
|
|
2306
3455
|
country: pending.country,
|
|
2307
3456
|
vatId: pending.vatId,
|
|
2308
|
-
taxNumber: pending.taxNumber
|
|
3457
|
+
taxNumber: pending.taxNumber,
|
|
3458
|
+
business: pending.business,
|
|
3459
|
+
vatIdCheck: vatIdCheckFromStore(pending.vatIdCheck)
|
|
2309
3460
|
};
|
|
2310
3461
|
}
|
|
2311
3462
|
function toIdentityValues(value) {
|
|
@@ -2323,7 +3474,7 @@ function toIdentityValues(value) {
|
|
|
2323
3474
|
// src/subscriber-payment-method-mapping.ts
|
|
2324
3475
|
var PAYMENT_METHOD_TYPES = ["card", "sepa_debit"];
|
|
2325
3476
|
var STATUSES = ["ACTIVE", "REPLACED"];
|
|
2326
|
-
var
|
|
3477
|
+
var TABLE4 = "subscriber_payment_methods";
|
|
2327
3478
|
function toSubscriberPaymentMethodRecord(row) {
|
|
2328
3479
|
return {
|
|
2329
3480
|
id: row.id,
|
|
@@ -2332,7 +3483,7 @@ function toSubscriberPaymentMethodRecord(row) {
|
|
|
2332
3483
|
provider: row.provider,
|
|
2333
3484
|
customerRef: row.customerRef,
|
|
2334
3485
|
paymentMethodRef: row.paymentMethodRef,
|
|
2335
|
-
type: oneOf(PAYMENT_METHOD_TYPES, row.type, { table:
|
|
3486
|
+
type: oneOf(PAYMENT_METHOD_TYPES, row.type, { table: TABLE4, column: "type", id: row.id }),
|
|
2336
3487
|
brand: row.brand,
|
|
2337
3488
|
last4: row.last4,
|
|
2338
3489
|
expiryMonth: row.expiryMonth,
|
|
@@ -2340,7 +3491,7 @@ function toSubscriberPaymentMethodRecord(row) {
|
|
|
2340
3491
|
country: row.country,
|
|
2341
3492
|
bankCode: row.bankCode,
|
|
2342
3493
|
mandateReference: row.mandateReference,
|
|
2343
|
-
status: oneOf(STATUSES, row.status, { table:
|
|
3494
|
+
status: oneOf(STATUSES, row.status, { table: TABLE4, column: "status", id: row.id }),
|
|
2344
3495
|
confirmedAt: row.confirmedAt,
|
|
2345
3496
|
replacedAt: row.replacedAt,
|
|
2346
3497
|
createdAt: row.createdAt
|
|
@@ -2406,6 +3557,8 @@ function toSubscriptionBundleRecord(row) {
|
|
|
2406
3557
|
}),
|
|
2407
3558
|
currentPeriodStart: row.currentPeriodStart ?? null,
|
|
2408
3559
|
currentPeriodEnd: row.currentPeriodEnd ?? null,
|
|
3560
|
+
pendingBundleVersionId: row.pendingBundleVersionId ?? null,
|
|
3561
|
+
pendingVersionEffectiveAt: row.pendingVersionEffectiveAt ?? null,
|
|
2409
3562
|
canceledAt: row.canceledAt,
|
|
2410
3563
|
canceledEffectiveAt: row.canceledEffectiveAt,
|
|
2411
3564
|
createdAt: row.createdAt,
|
|
@@ -2422,6 +3575,7 @@ function toSubscriptionContractRecord(row, lineItems) {
|
|
|
2422
3575
|
subscriber: toSubscriberParty(row.subscriberSnapshot),
|
|
2423
3576
|
issuer: isPlainObject2(row.issuerSnapshot) ? toIssuerParty(row.issuerSnapshot) : null,
|
|
2424
3577
|
partiesMigrated: row.partiesMigrated,
|
|
3578
|
+
taxTreatment: toTaxTreatment(row.taxTreatment),
|
|
2425
3579
|
status: row.status,
|
|
2426
3580
|
effectiveFrom: row.effectiveFrom,
|
|
2427
3581
|
effectiveUntil: row.effectiveUntil,
|
|
@@ -2669,6 +3823,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
2669
3823
|
PLAN_NOT_FOUND: "Plan '{planId}' nicht gefunden",
|
|
2670
3824
|
PLAN_VERSION_NOT_FOUND: "PlanVersion '{versionId}' nicht gefunden",
|
|
2671
3825
|
BUNDLE_NOT_FOUND: "Bundle '{bundleId}' nicht gefunden",
|
|
3826
|
+
BUNDLE_DELETE_WHILE_RETIREMENT_MOVES_PENDING: "{count} Buchungen ziehen noch auf eine Version von {bundleKey} um, wie eine Stilllegung es ihnen mitgeteilt hat. Das Add-on l\xE4sst sich l\xF6schen, sobald sie umgezogen sind.",
|
|
2672
3827
|
BUNDLE_VERSION_NOT_FOUND: "BundleVersion '{bundleVersionId}' nicht gefunden",
|
|
2673
3828
|
FEATURE_NOT_FOUND: "Feature '{featureKey}' nicht gefunden",
|
|
2674
3829
|
QUOTA_NOT_FOUND: "Quota '{quotaKey}' nicht gefunden",
|
|
@@ -2724,9 +3879,37 @@ var ERROR_MESSAGES_DE = {
|
|
|
2724
3879
|
RETIREMENT_NOTHING_AFFECTED: "Kein laufendes Abonnement nutzt Version {version} von {planKey}. Es gibt niemanden zu benachrichtigen.",
|
|
2725
3880
|
RETIREMENT_WITHIN_TWELVE_MONTHS: "{count} dieser Abonnements waren in den letzten zw\xF6lf Monaten schon von einer Stilllegung betroffen. Ein Abonnement ist h\xF6chstens einmal im Jahr betroffen.",
|
|
2726
3881
|
RETIREMENT_PREVIEW_CHANGED: "Die Abonnements, die diese Stilllegung betrifft, haben sich seit der Anzeige ge\xE4ndert. Sieh sie dir noch einmal an, bevor du sie ank\xFCndigst.",
|
|
3882
|
+
BUNDLE_RETIREMENT_VERSION_ON_SALE: "Version {version} von {bundleKey} wird noch verkauft. Ver\xF6ffentliche die Version, die sie ersetzt, und lege diese still, sobald ihr Verkauf geendet hat, damit sie nach der Ank\xFCndigung niemand mehr bucht.",
|
|
3883
|
+
BUNDLE_RETIREMENT_REPLACEMENT_NOT_ON_SALE: "Version {version} von {bundleKey} wird nicht verkauft. Buchungen k\xF6nnen nicht auf ihr weiterlaufen.",
|
|
3884
|
+
BUNDLE_RETIREMENT_REPLACEMENT_OF_ANOTHER_BUNDLE: "Der Ersatz ist eine Version von {replacementBundleKey}, nicht von {bundleKey}. Eine Buchung l\xE4uft auf einer Version ihres eigenen Add-ons weiter.",
|
|
3885
|
+
BUNDLE_RETIREMENT_REPLACEMENT_CANNOT_RUN: "{count} dieser Buchungen laufen neben einem Plan, neben dem Version {version} von {bundleKey} nicht laufen kann. Sie k\xF6nnen nicht auf ihr weiterlaufen.",
|
|
3886
|
+
BUNDLE_RETIREMENT_NOTHING_AFFECTED: "Keine laufende Buchung nutzt Version {version} von {bundleKey}. Es gibt niemanden zu benachrichtigen.",
|
|
3887
|
+
BUNDLE_RETIREMENT_REINSTATE_REFUSED: "Version {version} von {bundleKey} wird stillgelegt, und diese Buchung endet, bevor sie umziehen w\xFCrde. Buchen Sie Version {replacementVersion} ab dem {bookableFrom}, wenn diese Buchung beendet ist.",
|
|
3888
|
+
BUNDLE_RETIREMENT_REINSTATE_REPLACEMENT_CANNOT_RUN: "Version {version} von {bundleKey} wird stillgelegt, und diese Buchung endet, bevor sie umziehen w\xFCrde. Version {replacementVersion}, die sie ersetzt, kann neben Ihrem Paket oder einem Paket, zu dem Ihr Abonnement wechselt, nicht laufen.",
|
|
3889
|
+
BUNDLE_RETIREMENT_REINSTATE_SUBSCRIPTION_ENDS: "Version {version} von {bundleKey} wird stillgelegt, und diese Buchung endet, bevor sie umziehen w\xFCrde. Ihr Abonnement endet bis dahin ebenfalls.",
|
|
3890
|
+
BUNDLE_RETIREMENT_SWITCH_PLAN_CHANGES: "{bundleName} zieht am {date} auf seine neue Version um, und Ihr Paket \xE4ndert sich vorher. Der Preis, den ein Wechsel halten w\xFCrde, steht deshalb noch nicht fest. Wechseln Sie, sobald Ihr Paket gewechselt hat, oder lassen Sie es an diesem Tag umziehen.",
|
|
3891
|
+
BUNDLE_VERSION_OFFER_CHANGED: "Das Angebot hat sich seit der Anzeige ge\xE4ndert. Bitte sieh dir das aktuelle an, bevor du wechselst.",
|
|
3892
|
+
FEATURE_WITHDRAWAL_UNAVAILABLE: "Ein Feature zur\xFCckzuziehen ist hier nicht m\xF6glich: Die Speicher k\xF6nnen nicht alle auflisten, die ein R\xFCckzug erreicht.",
|
|
3893
|
+
FEATURE_WITHDRAWAL_FEATURE_UNKNOWN: "Der Katalog kennt kein Feature {featureKey}.",
|
|
3894
|
+
FEATURE_WITHDRAWAL_DATE_IN_PAST: "Ein Feature wird ab jetzt oder ab einem sp\xE4teren Datum zur\xFCckgezogen, nie ab einem vergangenen.",
|
|
3895
|
+
FEATURE_WITHDRAWAL_OPEN: "{featureKey} ist bereits zur\xFCckgezogen, und dieser R\xFCckzug ist nicht aufgehoben. Heben Sie ihn auf, bevor Sie einen weiteren ank\xFCndigen.",
|
|
3896
|
+
FEATURE_WITHDRAWAL_OVERLAPS: "{featureKey} ist bis zum {date} zur\xFCckgezogen. Ein weiterer R\xFCckzug kann fr\xFChestens an diesem Tag beginnen.",
|
|
3897
|
+
FEATURE_WITHDRAWAL_REDUCTION_NOT_REACHED: "Die Minderung f\xFCr {key} bei Abrechnung {billingCycle} betrifft nichts, was dieser R\xFCckzug erreicht.",
|
|
3898
|
+
FEATURE_WITHDRAWAL_REDUCTION_NAMED_TWICE: "Die Minderung f\xFCr {key} bei Abrechnung {billingCycle} ist doppelt angegeben.",
|
|
3899
|
+
FEATURE_WITHDRAWAL_REDUCTION_EXCEEDS_PRICE: "Die Minderung f\xFCr {key} bei Abrechnung {billingCycle} ist h\xF6her als der niedrigste Preis, den sie mindert: {price}.",
|
|
3900
|
+
FEATURE_WITHDRAWAL_PREVIEW_CHANGED: "Die Abonnements, die dieser R\xFCckzug erreicht, haben sich seit der Anzeige ge\xE4ndert. Sehen Sie sie erneut an, bevor Sie ihn ank\xFCndigen.",
|
|
3901
|
+
FEATURE_WITHDRAWAL_NOT_FOUND: "R\xFCckzug {withdrawalId} nicht gefunden.",
|
|
3902
|
+
FEATURE_WITHDRAWAL_ALREADY_LIFTED: "Dieser R\xFCckzug ist bereits aufgehoben, ab dem {date}.",
|
|
3903
|
+
FEATURE_WITHDRAWAL_NOT_TOLD_YET: "\xDCber diesen R\xFCckzug ist noch niemand informiert, und er wird nicht aufgehoben, bevor das geschehen ist. Versuchen Sie es gleich noch einmal.",
|
|
3904
|
+
FEATURE_WITHDRAWAL_LIFT_IN_PAST: "Ein R\xFCckzug wird ab jetzt oder ab einem sp\xE4teren Datum aufgehoben, nie ab einem vergangenen.",
|
|
3905
|
+
FEATURE_WITHDRAWAL_NOT_IN_EFFECT: "{featureKey} ist gerade nicht zur\xFCckgezogen. Deshalb kann nichts sofort beendet werden.",
|
|
3906
|
+
FEATURE_WITHDRAWAL_DOES_NOT_REACH: "Dieser R\xFCckzug betrifft Ihr Abonnement nicht, oder diese Buchung nicht mehr.",
|
|
3907
|
+
FEATURE_WITHDRAWAL_ALREADY_ENDED: "Das ist bereits beendet.",
|
|
3908
|
+
FEATURE_WITHDRAWAL_END_NOW_UNSUPPORTED: "Ihre K\xFCndigung zum {date} ist erfasst und kann hier nicht vorgezogen werden. Sie endet an diesem Tag, und bis dahin gilt die Minderung.",
|
|
2727
3909
|
RETIREMENT_SWITCH_NOT_PENDING: "F\xFCr Ihre Version steht keine Einstellung mehr bevor. Es gibt nichts, wohin Sie wechseln k\xF6nnten.",
|
|
2728
3910
|
RETIREMENT_SWITCH_IN_TRIAL: "Der Wechsel ist m\xF6glich, sobald Ihre Testphase endet.",
|
|
2729
3911
|
RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW: "{bundleName} kann im Paket {planName} nicht laufen und l\xE4uft fr\xFChestens bis {until}. Ist es gek\xFCndigt, ist der Wechsel ab diesem Tag m\xF6glich.",
|
|
3912
|
+
RETIREMENT_SWITCH_BUNDLE_REPLACEMENT_CANNOT_FOLLOW: "{bundleName} l\xE4uft ab dem {from} auf Version {version} weiter, die im Paket {planName} nicht laufen kann. Ist es gek\xFCndigt, ist der Wechsel m\xF6glich.",
|
|
2730
3913
|
RETIREMENT_SWITCH_NOT_OPEN: "Dieses Abonnement kann gerade nicht wechseln: Eine \xC4nderung ist geplant, es ist beendet, oder sein Paket gilt f\xFCr einen Sondervertrag.",
|
|
2731
3914
|
RETIREMENT_SWITCH_CHANGED: "Die Einstellung hat sich seit der Anzeige ge\xE4ndert. Sehen Sie sie sich noch einmal an, bevor Sie wechseln.",
|
|
2732
3915
|
SUBSCRIPTION_ENDED: "Dieses Abonnement ist beendet. Sein Paket kann nicht mehr gewechselt werden.",
|
|
@@ -2739,6 +3922,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
2739
3922
|
CYCLE_SHORTENS_AT_TERM_END: "Ein monatlich abgerechnetes {planName} kann nicht innerhalb der laufenden Jahreslaufzeit beginnen. Das Upgrade greift zum Ende dieser Laufzeit; wer es sofort m\xF6chte, beh\xE4lt den j\xE4hrlichen Rhythmus.",
|
|
2740
3923
|
BUNDLE_BOOKING_OUTLASTS_TARGET_CYCLE: "{bundleName} wird j\xE4hrlich abgerechnet und l\xE4uft fr\xFChestens bis {until}; ein monatlich abgerechnetes Paket kann es nicht tragen. Ist es gek\xFCndigt, geht ein Wechsel durch, der an diesem Tag oder sp\xE4ter wirksam wird \u2014 oder behalten Sie den j\xE4hrlichen Rhythmus.",
|
|
2741
3924
|
BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN: "{bundleName} kann im Paket {planName} nicht laufen und l\xE4uft fr\xFChestens bis {until}. Ist es gek\xFCndigt, geht ein Wechsel durch, der an diesem Tag oder sp\xE4ter wirksam wird \u2014 oder w\xE4hlen Sie ein anderes Paket.",
|
|
3925
|
+
BUNDLE_REPLACEMENT_DOES_NOT_FIT_TARGET_PLAN: "{bundleName} l\xE4uft ab dem {from} auf Version {version} weiter, die im Paket {planName} nicht laufen kann. K\xFCndigen Sie es, dann geht der Wechsel durch \u2014 oder w\xE4hlen Sie ein anderes Paket.",
|
|
2742
3926
|
REDUNDANT_FEATURES: "Der Plan oder ein anderes gebuchtes Bundle enth\xE4lt bereits {count} der Funktionen aus diesem Bundle \u2014 mit der Buchung werden sie doppelt bezahlt.",
|
|
2743
3927
|
MINIMUM_TERM_BINDS: "Die Mindestlaufzeit reicht \xFCber das Ende der Periode hinaus \u2014 die K\xFCndigung wird erst zum Ende der Mindestlaufzeit wirksam.",
|
|
2744
3928
|
BUNDLE_FEATURE_DEPENDENCY_UNSATISFIED: "Das Bundle setzt [{features}] voraus \u2014 weder im Plan noch in den aktiven Bundles vorhanden.",
|
|
@@ -2763,6 +3947,16 @@ var ERROR_MESSAGES_DE = {
|
|
|
2763
3947
|
PROMO_WOULD_PRODUCE_ZERO_INVOICE: "Bei absoluten Betr\xE4gen muss der Rabatt unter dem niedrigsten anwendbaren Planpreis bleiben, oder allowZeroInvoice muss aktiviert sein.",
|
|
2764
3948
|
PROMO_MAX_REDEMPTIONS_LOWERED: "maxRedemptions l\xE4sst sich nicht senken.",
|
|
2765
3949
|
// ── contract ──
|
|
3950
|
+
SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_DECIDED: "Der Vertrag nennt in {field} {stated} %, der Steueradapter entscheidet {decided} %.",
|
|
3951
|
+
SUBSCRIPTION_INVOICE_CHARGE_INVOICED: "Die Forderung '{chargeId}' steht bereits auf einer Rechnung.",
|
|
3952
|
+
SUBSCRIPTION_INVOICE_CONTENT_INCOMPLETE: "Der Rechnung fehlt, was der Steueradapter {adapter} verlangt: {missing}. Sie wird ausgestellt, sobald es erg\xE4nzt ist.",
|
|
3953
|
+
SUBSCRIPTION_INVOICE_PARTIES_UNCONFIRMED: "Der Vertrag {contractId} nennt keinen best\xE4tigten Aussteller und Abonnenten \u2013 eine Migration hat seine Parteien \xFCbernommen, oder er nennt keinen Aussteller \u2013, deshalb werden seine Forderungen nicht in Rechnung gestellt.",
|
|
3954
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_CHANGED: "Das Dokument der Rechnung {invoiceId} weicht vom festgehaltenen oder archivierten ab ({rendered} statt {recorded}); das erste bleibt, und der n\xE4chste Lauf kl\xE4rt, welches die Rechnung beh\xE4lt.",
|
|
3955
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_REFUSED: "Der Steueradapter {adapter} weist die gerenderte Rechnung zur\xFCck: {missing}. Die Rechnung beh\xE4lt ihre Nummer und wartet auf ein Dokument, das die Pr\xFCfung besteht.",
|
|
3956
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_MISMATCH: "Das archivierte Dokument der Rechnung {invoiceId} passt nicht zur beim Rendern festgehaltenen Pr\xFCfsumme und wird nicht herausgegeben.",
|
|
3957
|
+
SUBSCRIPTION_INVOICE_DOCUMENT_NOT_ARCHIVED: "Das Dokument der Rechnung {invoiceId} ist noch nicht archiviert.",
|
|
3958
|
+
SUBSCRIPTION_INVOICE_NOT_FOUND: "Keine Rechnung '{invoiceId}'.",
|
|
3959
|
+
SUBSCRIPTION_INVOICE_NO_INVOICE_EMAIL: "Der Abonnent {subscriberId} hat keine Rechnungs-E-Mail; seine Rechnung wird versendet, sobald eine eingetragen ist.",
|
|
2766
3960
|
CHECKOUT_OFFER_LINE_ITEMS_REQUIRED: "Aus einem Checkout-Angebot entsteht nur ein einziger Vertrag, und das erst, wenn seine Positionen eingefroren sind.",
|
|
2767
3961
|
CHECKOUT_OFFER_PLAN_LINE_ITEM_REQUIRED: "Ein Checkout-Angebot braucht eine eingefrorene Plan-Position.",
|
|
2768
3962
|
CHECKOUT_OFFER_BUNDLE_LINE_ITEMS_REQUIRED: "Jede gew\xE4hlte Bundle-Version braucht eine eingefrorene Bundle-Position.",
|
|
@@ -2787,6 +3981,8 @@ var ERROR_MESSAGES_DE = {
|
|
|
2787
3981
|
CHECKOUT_OFFER_ALREADY_CONSUMED: "Checkout-Angebot '{offerId}' wurde bereits eingel\xF6st \u2014 '{action}' ist nicht mehr m\xF6glich",
|
|
2788
3982
|
CHECKOUT_OFFER_NOT_CONSUMED: "CheckoutOffer '{offerId}' muss eingel\xF6st sein, bevor der Vertrag entsteht",
|
|
2789
3983
|
CHECKOUT_OFFER_CHANGED: "Checkout-Angebot '{offerId}' hat sich w\xE4hrend des Abschlusses ge\xE4ndert. Bitte neu laden.",
|
|
3984
|
+
CHECKOUT_OFFER_CONTRACT_IN_FORCE: "Checkout-Angebot '{offerId}' schlie\xDFt einen ersten Vertrag ab, und dieser Mandant hat bereits einen. Ein laufendes Abo \xE4ndert sich \xFCber seinen Plan und seine Add-ons.",
|
|
3985
|
+
CHECKOUT_OFFER_ADD_ON_BOOKED_IN_ANOTHER_VERSION: "Checkout-Angebot '{offerId}' nennt Version {offeredVersion} des Add-ons '{bundleKey}', das dieser Mandant in Version {bookedVersion} gebucht hat (Buchung {subscriptionBundleId}). Die Version wechselt \xFCber das Angebot neben dem Add-on.",
|
|
2790
3986
|
SUBSCRIPTION_CONTRACT_NOT_FOUND: "SubscriptionContract '{contractId}' nicht gefunden",
|
|
2791
3987
|
NO_ACTIVE_SUBSCRIPTION_CONTRACT: "Kein aktiver Abo-Vertrag f\xFCr Mandant {tenantId}",
|
|
2792
3988
|
SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SubscriptionContract '{contractId}' ist bereits geschlossen",
|
|
@@ -2797,11 +3993,16 @@ var ERROR_MESSAGES_DE = {
|
|
|
2797
3993
|
SUBSCRIBER_NOT_FOUND: "Vertragspartner '{subscriberId}' nicht gefunden",
|
|
2798
3994
|
SUBSCRIBER_LEGAL_NAME_REQUIRED: "Ein Vertragspartner braucht seinen rechtlichen Namen.",
|
|
2799
3995
|
SUBSCRIBER_DETAIL_INVALID: "Das Feld {field} des Vertragspartners ist ung\xFCltig.",
|
|
3996
|
+
SUBSCRIBER_IDENTITY_INCOMPLETE: "Die Rechnungsadresse des Vertragspartners ist noch nicht vollst\xE4ndig: Ein Vertrag nennt ihn nur mit Stra\xDFe und Hausnummer, PLZ, Ort und Land.",
|
|
3997
|
+
SUBSCRIBER_BUSINESS_STATUS_REASON_REQUIRED: "Eine \xC4nderung, ob der Vertragspartner ein Unternehmen ist, braucht eine Begr\xFCndung.",
|
|
3998
|
+
SUBSCRIBER_VAT_ID_MISSING: "Der Vertragspartner hat keine Umsatzsteuer-Identifikationsnummer, die sich pr\xFCfen lie\xDFe.",
|
|
2800
3999
|
SUBSCRIBER_IDENTITY_NOT_A_CONTACT: "{field} geh\xF6rt zur rechtlichen Identit\xE4t des Vertragspartners und \xE4ndert sich nur als Korrektur mit Begr\xFCndung.",
|
|
2801
4000
|
SUBSCRIBER_CORRECTION_REASON_REQUIRED: "Eine Korrektur der rechtlichen Identit\xE4t braucht eine Begr\xFCndung.",
|
|
2802
4001
|
SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "Eine Korrektur der rechtlichen Identit\xE4t muss nennen, wer sie vornimmt.",
|
|
2803
4002
|
SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "Die Korrektur \xE4ndert nichts: Jeder genannte Wert ist bereits erfasst.",
|
|
2804
4003
|
SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "\xDCbernimmt eine andere Rechtsperson, ist das eine \xDCbertragung und keine Korrektur; sie l\xE4sst sich nicht als \xC4nderung erfassen.",
|
|
4004
|
+
SUBSCRIBER_BUSINESS_STATUS_NOT_A_CONTACT: "Ob der Vertragspartner ein Unternehmen ist, geh\xF6rt zu seiner steuerlichen Herkunft und \xE4ndert sich nur als erfasste \xC4nderung, die nennt, wer sie vornimmt.",
|
|
4005
|
+
SUBSCRIBER_CHANGE_ACTOR_REQUIRED: "Eine \xC4nderung der Angaben des Vertragspartners muss nennen, wer sie vornimmt.",
|
|
2805
4006
|
// ── registration ──
|
|
2806
4007
|
PENDING_REGISTRATION_NOT_FOUND: "Diese Registrierung konnten wir nicht finden. Vielleicht ist sie bereits abgeschlossen oder verworfen.",
|
|
2807
4008
|
PENDING_REGISTRATION_EXPIRED: "Diese Registrierung ist abgelaufen. Bitte fange noch einmal von vorn an.",
|
|
@@ -2835,7 +4036,11 @@ var ERROR_MESSAGES_DE = {
|
|
|
2835
4036
|
MAINTENANCE_WINDOW_END_NOT_AFTER_START: "Das Ende eines Wartungsfensters muss nach seinem Beginn liegen.",
|
|
2836
4037
|
MAINTENANCE_WINDOW_END_IN_PAST: "Das Ende eines Wartungsfensters darf nicht in der Vergangenheit liegen.",
|
|
2837
4038
|
MAINTENANCE_TIME_INVALID: "{field} muss Datum und Uhrzeit mit Zeitzone sein, etwa 2026-10-02T22:00+02:00.",
|
|
2838
|
-
MAINTENANCE_MESSAGE_TOO_LONG: "Die Nachricht darf h\xF6chstens {max} Zeichen lang sein."
|
|
4039
|
+
MAINTENANCE_MESSAGE_TOO_LONG: "Die Nachricht darf h\xF6chstens {max} Zeichen lang sein.",
|
|
4040
|
+
// ── tax ──
|
|
4041
|
+
TAX_TREATMENT_NOT_SUPPORTED: "Der Steueradapter {adapter} unterst\xFCtzt diesen Fall nicht: {reason}",
|
|
4042
|
+
TAX_VAT_ID_CHECK_NOT_COMPLETED: "Die Umsatzsteuer-Identifikationsnummer lie\xDF sich gerade nicht pr\xFCfen ({reason}). Bitte sp\xE4ter erneut versuchen.",
|
|
4043
|
+
TAX_VAT_ID_CHECK_NOT_AVAILABLE: "Diese Installation nennt keinen Steueradapter, darum wird keine Umsatzsteuer-Identifikationsnummer gepr\xFCft."
|
|
2839
4044
|
};
|
|
2840
4045
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2841
4046
|
0 && (module.exports = {
|
|
@@ -2843,6 +4048,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
2843
4048
|
AUTH_ERROR_CODES,
|
|
2844
4049
|
BILLING_ERROR_CODES,
|
|
2845
4050
|
BUNDLE_PRICE_LOOKUP_LIMIT,
|
|
4051
|
+
BUNDLE_VERSION_RETIREMENT_CAPABILITY,
|
|
2846
4052
|
CATALOGUE_KEYS,
|
|
2847
4053
|
CATALOG_ERROR_CODES,
|
|
2848
4054
|
CONTRACT_ERROR_CODES,
|
|
@@ -2850,7 +4056,13 @@ var ERROR_MESSAGES_DE = {
|
|
|
2850
4056
|
ERROR_MESSAGES_DE,
|
|
2851
4057
|
ERROR_MESSAGES_EN,
|
|
2852
4058
|
FEATURE_NOT_LICENSED,
|
|
4059
|
+
FEATURE_WITHDRAWAL_CAPABILITY,
|
|
4060
|
+
FEATURE_WITHDRAWAL_REASON_MAX_LENGTH,
|
|
2853
4061
|
ForeignPaymentMethodReferenceError,
|
|
4062
|
+
INVOICE_ARCHIVE_TRIGGERS,
|
|
4063
|
+
INVOICE_DOCUMENT_CAPABILITY,
|
|
4064
|
+
INVOICE_ERROR_CODES,
|
|
4065
|
+
INVOICE_SEQUENCE_DIGITS,
|
|
2854
4066
|
LEGAL_IDENTITY_FIELDS,
|
|
2855
4067
|
MAINTENANCE_CAPABILITY,
|
|
2856
4068
|
MAINTENANCE_ERROR_CODES,
|
|
@@ -2883,9 +4095,21 @@ var ERROR_MESSAGES_DE = {
|
|
|
2883
4095
|
SETTINGS_ERROR_CODES,
|
|
2884
4096
|
SETUP_ERROR_CODES,
|
|
2885
4097
|
SUBSCRIBER_ACCOUNT_CAPABILITY,
|
|
4098
|
+
SUBSCRIBER_ATTENTION_CAPABILITY,
|
|
4099
|
+
SUBSCRIBER_ATTENTION_PAGE_SIZE,
|
|
4100
|
+
SUBSCRIBER_CHARGE_ORIGINS,
|
|
4101
|
+
SUBSCRIBER_CHARGE_SOURCES,
|
|
4102
|
+
SUBSCRIBER_CORRECTION_CAPABILITY,
|
|
2886
4103
|
SUBSCRIBER_ERROR_CODES,
|
|
4104
|
+
SUBSCRIBER_INVOICE_ADDRESS_FIELDS,
|
|
4105
|
+
SUBSCRIBER_STANDING_CAPABILITY,
|
|
4106
|
+
SUBSCRIBER_TAX_ORIGIN_FIELDS,
|
|
4107
|
+
TAX_ERROR_CODES,
|
|
4108
|
+
TAX_TREATMENT_KINDS,
|
|
2887
4109
|
VERSION_RETIREMENT_CAPABILITY,
|
|
4110
|
+
addDaysToDay,
|
|
2888
4111
|
applyPromo,
|
|
4112
|
+
asXmlReadsIt,
|
|
2889
4113
|
assertPersistenceCapabilities,
|
|
2890
4114
|
buildActivePlanVersionWhere,
|
|
2891
4115
|
buildActiveVersionWhere,
|
|
@@ -2894,6 +4118,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
2894
4118
|
bundleKeyTaken,
|
|
2895
4119
|
bundleStemDefaults,
|
|
2896
4120
|
canonicalJson,
|
|
4121
|
+
canonicalVatId,
|
|
2897
4122
|
catalogDraftExists,
|
|
2898
4123
|
catalogVersionAlreadyPublished,
|
|
2899
4124
|
catalogVersionGone,
|
|
@@ -2908,14 +4133,28 @@ var ERROR_MESSAGES_DE = {
|
|
|
2908
4133
|
contractPartiesOf,
|
|
2909
4134
|
coverageExcludingSelf,
|
|
2910
4135
|
customLimitsReader,
|
|
4136
|
+
dayInZone,
|
|
2911
4137
|
definedFields,
|
|
2912
4138
|
diffSettings,
|
|
4139
|
+
draftSubscriptionInvoice,
|
|
4140
|
+
endedAtOnceSubjectOf,
|
|
4141
|
+
featureWithdrawalRowOf,
|
|
4142
|
+
featuresWithdrawnAt,
|
|
2913
4143
|
formatCustomerNumber,
|
|
2914
4144
|
formatErrorMessage,
|
|
4145
|
+
formatInvoiceNumber,
|
|
2915
4146
|
grossFromNet,
|
|
4147
|
+
holdsOnlyXmlCharacters,
|
|
2916
4148
|
identityCorrectionDelta,
|
|
4149
|
+
invoiceArchiveProtectionProblem,
|
|
4150
|
+
invoiceContentDraftOf,
|
|
4151
|
+
invoiceFooterOf,
|
|
4152
|
+
invoiceGroupsOf,
|
|
4153
|
+
invoiceIssuerOf,
|
|
2917
4154
|
isBundleRedundant,
|
|
4155
|
+
isFeatureWithdrawnAt,
|
|
2918
4156
|
isForeignPaymentMethodReferenceError,
|
|
4157
|
+
isInvoiceDocumentChecksum,
|
|
2919
4158
|
isMaintenanceAnnouncementLapsed,
|
|
2920
4159
|
isMaintenanceOverrun,
|
|
2921
4160
|
isPaymentCallbackRejectedError,
|
|
@@ -2925,6 +4164,8 @@ var ERROR_MESSAGES_DE = {
|
|
|
2925
4164
|
isVersionEditable,
|
|
2926
4165
|
issuerIdentityOf,
|
|
2927
4166
|
keepOneRecommended,
|
|
4167
|
+
keepsVatIdCheck,
|
|
4168
|
+
lastDayInZone,
|
|
2928
4169
|
maintenanceRetryAfterSeconds,
|
|
2929
4170
|
maintenanceStatusOf,
|
|
2930
4171
|
maintenanceWindowStatusOf,
|
|
@@ -2934,6 +4175,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
2934
4175
|
missingRequiresFor,
|
|
2935
4176
|
movedIdentityFields,
|
|
2936
4177
|
netFromGross,
|
|
4178
|
+
nextWithdrawalChange,
|
|
2937
4179
|
noActivePlanVersion,
|
|
2938
4180
|
parseZonedInstant,
|
|
2939
4181
|
percentOf,
|
|
@@ -2970,11 +4212,22 @@ var ERROR_MESSAGES_DE = {
|
|
|
2970
4212
|
subscriptionBundleGone,
|
|
2971
4213
|
subscriptionContractGone,
|
|
2972
4214
|
subscriptionGone,
|
|
4215
|
+
subscriptionInvoiceChargeInvoiced,
|
|
4216
|
+
subscriptionInvoiceColumns,
|
|
4217
|
+
subscriptionInvoiceDocumentChanged,
|
|
4218
|
+
subscriptionInvoiceLineColumns,
|
|
2973
4219
|
sumToCents,
|
|
4220
|
+
taxOriginOf,
|
|
4221
|
+
taxOriginWrite,
|
|
4222
|
+
taxPerRate,
|
|
4223
|
+
taxTreatmentToJson,
|
|
4224
|
+
toArchivedInvoiceDocument,
|
|
2974
4225
|
toBundleStemRow,
|
|
4226
|
+
toBundleVersionRetirementRecord,
|
|
2975
4227
|
toCents,
|
|
2976
4228
|
toContractLineItemRecord,
|
|
2977
4229
|
toDecimalString,
|
|
4230
|
+
toFeatureWithdrawalRecord,
|
|
2978
4231
|
toMaintenanceWindowRecord,
|
|
2979
4232
|
toPlanRow,
|
|
2980
4233
|
toPlanVersionRow,
|
|
@@ -2983,11 +4236,22 @@ var ERROR_MESSAGES_DE = {
|
|
|
2983
4236
|
toSubscriberCorrectionRecord,
|
|
2984
4237
|
toSubscriberPaymentMethodRecord,
|
|
2985
4238
|
toSubscriberRecord,
|
|
4239
|
+
toSubscriberTaxOriginChangeRecord,
|
|
4240
|
+
toSubscriberVatIdCheckRecord,
|
|
2986
4241
|
toSubscriptionBundleRecord,
|
|
2987
4242
|
toSubscriptionContractRecord,
|
|
4243
|
+
toSubscriptionInvoiceDocumentRecord,
|
|
4244
|
+
toSubscriptionInvoiceRecord,
|
|
2988
4245
|
toSubscriptionNoticeRecord,
|
|
4246
|
+
toTaxOriginValues,
|
|
4247
|
+
toTaxTreatment,
|
|
2989
4248
|
toVersionRetirementRecord,
|
|
4249
|
+
utcMidnightOf,
|
|
4250
|
+
vatCategoryOf,
|
|
4251
|
+
vatIdCheckFromStore,
|
|
2990
4252
|
versionOnSale,
|
|
2991
4253
|
versionOnSaleOrNext,
|
|
2992
|
-
versionSale
|
|
4254
|
+
versionSale,
|
|
4255
|
+
withdrawnFeaturesOf,
|
|
4256
|
+
yearOfDay
|
|
2993
4257
|
});
|