@saasicat/core 1.0.0-rc.20 → 1.0.0-rc.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-stamp +1 -1
- package/dist/index.cjs +192 -17
- package/dist/index.d.cts +581 -16
- package/dist/index.d.ts +581 -16
- package/dist/index.js +184 -17
- package/package.json +1 -1
package/dist/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
91754758b2193699e34b267e3d43034f1ffa6d651baee667fbdf3456d23db8b2
|
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ __export(index_exports, {
|
|
|
30
30
|
ERROR_MESSAGES_DE: () => ERROR_MESSAGES_DE,
|
|
31
31
|
ERROR_MESSAGES_EN: () => ERROR_MESSAGES_EN,
|
|
32
32
|
FEATURE_NOT_LICENSED: () => FEATURE_NOT_LICENSED,
|
|
33
|
+
ForeignPaymentMethodReferenceError: () => ForeignPaymentMethodReferenceError,
|
|
33
34
|
LEGAL_IDENTITY_FIELDS: () => LEGAL_IDENTITY_FIELDS,
|
|
34
35
|
MARKETING_PRIORITY_MAX: () => MARKETING_PRIORITY_MAX,
|
|
35
36
|
MARKETING_PRIORITY_MIN: () => MARKETING_PRIORITY_MIN,
|
|
@@ -53,6 +54,7 @@ __export(index_exports, {
|
|
|
53
54
|
REGISTRATION_STEP_BY_STATUS: () => REGISTRATION_STEP_BY_STATUS,
|
|
54
55
|
SETTINGS_ERROR_CODES: () => SETTINGS_ERROR_CODES,
|
|
55
56
|
SETUP_ERROR_CODES: () => SETUP_ERROR_CODES,
|
|
57
|
+
SUBSCRIBER_ACCOUNT_CAPABILITY: () => SUBSCRIBER_ACCOUNT_CAPABILITY,
|
|
56
58
|
SUBSCRIBER_ERROR_CODES: () => SUBSCRIBER_ERROR_CODES,
|
|
57
59
|
applyPromo: () => applyPromo,
|
|
58
60
|
assertPersistenceCapabilities: () => assertPersistenceCapabilities,
|
|
@@ -74,6 +76,7 @@ __export(index_exports, {
|
|
|
74
76
|
formatErrorMessage: () => formatErrorMessage,
|
|
75
77
|
identityCorrectionDelta: () => identityCorrectionDelta,
|
|
76
78
|
isBundleRedundant: () => isBundleRedundant,
|
|
79
|
+
isForeignPaymentMethodReferenceError: () => isForeignPaymentMethodReferenceError,
|
|
77
80
|
isPaymentCallbackRejectedError: () => isPaymentCallbackRejectedError,
|
|
78
81
|
isPlatformUserExistsError: () => isPlatformUserExistsError,
|
|
79
82
|
isVersionEditable: () => isVersionEditable,
|
|
@@ -85,15 +88,18 @@ __export(index_exports, {
|
|
|
85
88
|
planCatalogSettingsOf: () => planCatalogSettingsOf,
|
|
86
89
|
previousUtcDay: () => previousUtcDay,
|
|
87
90
|
promoStatus: () => promoStatus,
|
|
91
|
+
promotionOnPrice: () => promotionOnPrice,
|
|
88
92
|
readQuotaRecord: () => readQuotaRecord,
|
|
89
93
|
readQuotaValue: () => readQuotaValue,
|
|
90
94
|
recordedIssuerIdentity: () => recordedIssuerIdentity,
|
|
95
|
+
refuseForeignPaymentMethodReference: () => refuseForeignPaymentMethodReference,
|
|
91
96
|
resolveBundleAvailability: () => resolveBundleAvailability,
|
|
92
97
|
resolveErrorMessage: () => resolveErrorMessage,
|
|
93
98
|
sameLegalIdentity: () => sameLegalIdentity,
|
|
94
99
|
selectChargeableBundles: () => selectChargeableBundles,
|
|
95
100
|
settingsSubtreeOf: () => settingsSubtreeOf,
|
|
96
101
|
startOfUtcDay: () => startOfUtcDay,
|
|
102
|
+
subscriberChargeColumns: () => subscriberChargeColumns,
|
|
97
103
|
subscriberFromRegistration: () => subscriberFromRegistration,
|
|
98
104
|
subscriberPaymentMethodColumns: () => subscriberPaymentMethodColumns,
|
|
99
105
|
toBundleStemRow: () => toBundleStemRow,
|
|
@@ -101,9 +107,11 @@ __export(index_exports, {
|
|
|
101
107
|
toPlanRow: () => toPlanRow,
|
|
102
108
|
toPlanVersionRow: () => toPlanVersionRow,
|
|
103
109
|
toRunningContractIssuer: () => toRunningContractIssuer,
|
|
110
|
+
toSubscriberChargeRecord: () => toSubscriberChargeRecord,
|
|
104
111
|
toSubscriberCorrectionRecord: () => toSubscriberCorrectionRecord,
|
|
105
112
|
toSubscriberPaymentMethodRecord: () => toSubscriberPaymentMethodRecord,
|
|
106
113
|
toSubscriberRecord: () => toSubscriberRecord,
|
|
114
|
+
toSubscriptionBundleRecord: () => toSubscriptionBundleRecord,
|
|
107
115
|
toSubscriptionContractRecord: () => toSubscriptionContractRecord
|
|
108
116
|
});
|
|
109
117
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -197,27 +205,33 @@ function pickActivePromo(promotions, targetKey, locale, cycle, today = /* @__PUR
|
|
|
197
205
|
return matches[0] ?? null;
|
|
198
206
|
}
|
|
199
207
|
function applyPromo(promo, basePrice) {
|
|
208
|
+
const result = boundedPromo(promo, basePrice);
|
|
209
|
+
return result && result.discounted < result.original ? result : null;
|
|
210
|
+
}
|
|
211
|
+
function boundedPromo(promo, basePrice) {
|
|
200
212
|
if (!promo || basePrice === null || basePrice === void 0) return null;
|
|
201
213
|
if (promo.type === "percent" && typeof promo.value === "number") {
|
|
214
|
+
const pct = withinBounds(promo.value, 100);
|
|
202
215
|
return {
|
|
203
216
|
kind: "percent",
|
|
204
|
-
discounted: Math.round(basePrice * (100 -
|
|
217
|
+
discounted: Math.round(basePrice * (100 - pct)) / 100,
|
|
205
218
|
original: basePrice,
|
|
206
|
-
pct
|
|
219
|
+
pct
|
|
207
220
|
};
|
|
208
221
|
}
|
|
209
222
|
if (promo.type === "amount" && typeof promo.value === "number") {
|
|
223
|
+
const saved = withinBounds(promo.value, basePrice);
|
|
210
224
|
return {
|
|
211
225
|
kind: "amount",
|
|
212
|
-
discounted: Math.
|
|
226
|
+
discounted: Math.round((basePrice - saved) * 100) / 100,
|
|
213
227
|
original: basePrice,
|
|
214
|
-
saved
|
|
228
|
+
saved
|
|
215
229
|
};
|
|
216
230
|
}
|
|
217
|
-
if (promo.type === "intro" && typeof promo.value === "object") {
|
|
231
|
+
if (promo.type === "intro" && typeof promo.value === "object" && promo.value !== null) {
|
|
218
232
|
return {
|
|
219
233
|
kind: "intro",
|
|
220
|
-
discounted: promo.value.price,
|
|
234
|
+
discounted: withinBounds(promo.value.price, basePrice),
|
|
221
235
|
original: basePrice,
|
|
222
236
|
months: promo.value.months
|
|
223
237
|
};
|
|
@@ -227,6 +241,14 @@ function applyPromo(promo, basePrice) {
|
|
|
227
241
|
}
|
|
228
242
|
return null;
|
|
229
243
|
}
|
|
244
|
+
function withinBounds(value, upper) {
|
|
245
|
+
return Math.min(Math.max(value, 0), Math.max(upper, 0));
|
|
246
|
+
}
|
|
247
|
+
function promotionOnPrice(promotions, targetKey, locale, cycle, basePrice, today = /* @__PURE__ */ new Date(), targetType = "PLAN") {
|
|
248
|
+
const promotion = pickActivePromo(promotions, targetKey, locale, cycle, today, targetType);
|
|
249
|
+
const result = applyPromo(promotion, basePrice);
|
|
250
|
+
return promotion && result ? { promotion, result } : null;
|
|
251
|
+
}
|
|
230
252
|
|
|
231
253
|
// src/quota-value.ts
|
|
232
254
|
function readQuotaValue(value) {
|
|
@@ -523,6 +545,12 @@ var CATALOG_ERROR_CODES = {
|
|
|
523
545
|
FEATURE_NOT_FOUND: "FEATURE_NOT_FOUND",
|
|
524
546
|
QUOTA_NOT_FOUND: "QUOTA_NOT_FOUND",
|
|
525
547
|
PROMOTION_NOT_FOUND: "PROMOTION_NOT_FOUND",
|
|
548
|
+
/**
|
|
549
|
+
* A promotion's value is not one its type takes: a percentage above 0 and
|
|
550
|
+
* at most 100, an amount above 0, an intro price of at least 0 for a whole
|
|
551
|
+
* number of months, or a whole number of free months.
|
|
552
|
+
*/
|
|
553
|
+
PROMOTION_VALUE_INVALID: "PROMOTION_VALUE_INVALID",
|
|
526
554
|
MARKETING_PROJECTION_NOT_FOUND: "MARKETING_PROJECTION_NOT_FOUND",
|
|
527
555
|
// ── already exists ──
|
|
528
556
|
PLAN_ALREADY_EXISTS: "PLAN_ALREADY_EXISTS",
|
|
@@ -682,6 +710,13 @@ var CONTRACT_ERROR_CODES = {
|
|
|
682
710
|
SUBSCRIPTION_CONTRACT_LINE_ITEM_TAX_MISMATCH: "SUBSCRIPTION_CONTRACT_LINE_ITEM_TAX_MISMATCH",
|
|
683
711
|
SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_PERCENT: "SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_PERCENT",
|
|
684
712
|
SUBSCRIPTION_CONTRACT_LINE_ITEM_CURRENCY_MISMATCH: "SUBSCRIPTION_CONTRACT_LINE_ITEM_CURRENCY_MISMATCH",
|
|
713
|
+
/**
|
|
714
|
+
* The lines do not add up to a total the contract states, counted as often
|
|
715
|
+
* as each falls due in one period. `field` names the total.
|
|
716
|
+
*/
|
|
717
|
+
SUBSCRIPTION_CONTRACT_LINES_DO_NOT_ADD_UP: "SUBSCRIPTION_CONTRACT_LINES_DO_NOT_ADD_UP",
|
|
718
|
+
/** Something that takes money off states a negative amount. */
|
|
719
|
+
SUBSCRIPTION_CONTRACT_DISCOUNT_NEGATIVE: "SUBSCRIPTION_CONTRACT_DISCOUNT_NEGATIVE",
|
|
685
720
|
SUBSCRIPTION_CONTRACT_TERMINATION_BEFORE_START: "SUBSCRIPTION_CONTRACT_TERMINATION_BEFORE_START",
|
|
686
721
|
// ── stage 3 ──
|
|
687
722
|
CHECKOUT_OFFER_NOT_FOUND: "CHECKOUT_OFFER_NOT_FOUND",
|
|
@@ -794,7 +829,14 @@ var PAYMENT_ERROR_CODES = {
|
|
|
794
829
|
* A success or cancel URL at an origin `config/saas.yaml#payments.returnUrlOrigins`
|
|
795
830
|
* does not name. Carries `field`.
|
|
796
831
|
*/
|
|
797
|
-
PAYMENT_RETURN_URL_NOT_ALLOWED: "PAYMENT_RETURN_URL_NOT_ALLOWED"
|
|
832
|
+
PAYMENT_RETURN_URL_NOT_ALLOWED: "PAYMENT_RETURN_URL_NOT_ALLOWED",
|
|
833
|
+
/**
|
|
834
|
+
* The gateway failed — unreachable, refusing the account's keys, or
|
|
835
|
+
* answering with an error — while opening its form or reading a callback
|
|
836
|
+
* back. Answered with 502; what the gateway answered stays in the server
|
|
837
|
+
* log.
|
|
838
|
+
*/
|
|
839
|
+
PAYMENT_GATEWAY_FAILED: "PAYMENT_GATEWAY_FAILED"
|
|
798
840
|
};
|
|
799
841
|
var SETTINGS_ERROR_CODES = {
|
|
800
842
|
/** No recorded change has this id, or the installation keeps no record at all. */
|
|
@@ -1060,6 +1102,83 @@ function textOrNull(value) {
|
|
|
1060
1102
|
return trimmed === "" ? null : trimmed;
|
|
1061
1103
|
}
|
|
1062
1104
|
|
|
1105
|
+
// src/closed-value.ts
|
|
1106
|
+
function oneOf(allowed, value, source) {
|
|
1107
|
+
const match = allowed.find((entry) => entry === value);
|
|
1108
|
+
if (match === void 0) {
|
|
1109
|
+
throw new Error(
|
|
1110
|
+
`${source.table} row '${source.id}' holds ${source.column} '${value}', which is none of ${allowed.join(", ")}.`
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
return match;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// src/subscriber-ledger-mapping.ts
|
|
1117
|
+
var ORIGINS = {
|
|
1118
|
+
activation: true,
|
|
1119
|
+
renewal: true,
|
|
1120
|
+
planChange: true,
|
|
1121
|
+
bundleBooking: true,
|
|
1122
|
+
credit: true,
|
|
1123
|
+
correction: true
|
|
1124
|
+
};
|
|
1125
|
+
var SOURCES = {
|
|
1126
|
+
plan: true,
|
|
1127
|
+
bundle: true,
|
|
1128
|
+
discount: true
|
|
1129
|
+
};
|
|
1130
|
+
var TABLE = "subscriber_ledger_entries";
|
|
1131
|
+
var CENT_TOLERANCE = 1e-6;
|
|
1132
|
+
function toSubscriberChargeRecord(row) {
|
|
1133
|
+
const where = (column) => ({ table: TABLE, column, id: row.id });
|
|
1134
|
+
return {
|
|
1135
|
+
id: row.id,
|
|
1136
|
+
subscriberId: row.subscriberId,
|
|
1137
|
+
tenantId: row.tenantId,
|
|
1138
|
+
subscriptionId: row.subscriptionId,
|
|
1139
|
+
contractId: row.contractId,
|
|
1140
|
+
contractLineItemId: row.contractLineItemId,
|
|
1141
|
+
origin: oneOf(keysOf(ORIGINS), row.origin, where("origin")),
|
|
1142
|
+
source: oneOf(keysOf(SOURCES), row.source, where("source")),
|
|
1143
|
+
sourceRef: row.sourceRef,
|
|
1144
|
+
periodStart: row.periodStart,
|
|
1145
|
+
periodEnd: row.periodEnd,
|
|
1146
|
+
currency: row.currency,
|
|
1147
|
+
amountNet: Number(row.amountNet),
|
|
1148
|
+
bookedAt: row.bookedAt,
|
|
1149
|
+
createdAt: row.createdAt
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
function subscriberChargeColumns(charge) {
|
|
1153
|
+
const cents = charge.amountNet * 100;
|
|
1154
|
+
if (!Number.isFinite(cents) || Math.abs(cents - Math.round(cents)) > CENT_TOLERANCE) {
|
|
1155
|
+
throw new Error(
|
|
1156
|
+
`A charge of ${charge.amountNet} is not a whole number of cents; round it once where it is derived, before it is written.`
|
|
1157
|
+
);
|
|
1158
|
+
}
|
|
1159
|
+
return {
|
|
1160
|
+
subscriberId: charge.subscriberId,
|
|
1161
|
+
tenantId: charge.tenantId,
|
|
1162
|
+
subscriptionId: charge.subscriptionId,
|
|
1163
|
+
contractId: charge.contractId,
|
|
1164
|
+
contractLineItemId: charge.contractLineItemId,
|
|
1165
|
+
origin: charge.origin,
|
|
1166
|
+
source: charge.source,
|
|
1167
|
+
sourceRef: charge.sourceRef,
|
|
1168
|
+
periodStart: charge.periodStart,
|
|
1169
|
+
periodEnd: charge.periodEnd,
|
|
1170
|
+
currency: charge.currency,
|
|
1171
|
+
amountNet: charge.amountNet.toFixed(2),
|
|
1172
|
+
bookedAt: charge.bookedAt
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
function keysOf(record) {
|
|
1176
|
+
return Object.keys(record);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
// src/subscriber-ledger.types.ts
|
|
1180
|
+
var SUBSCRIBER_ACCOUNT_CAPABILITY = "charges.read";
|
|
1181
|
+
|
|
1063
1182
|
// src/subscriber-mapping.ts
|
|
1064
1183
|
function formatCustomerNumber(prefix, sequence) {
|
|
1065
1184
|
return `${prefix}${sequence}`;
|
|
@@ -1175,6 +1294,7 @@ function toIdentityValues(value) {
|
|
|
1175
1294
|
// src/subscriber-payment-method-mapping.ts
|
|
1176
1295
|
var PAYMENT_METHOD_TYPES = ["card", "sepa_debit"];
|
|
1177
1296
|
var STATUSES = ["ACTIVE", "REPLACED"];
|
|
1297
|
+
var TABLE2 = "subscriber_payment_methods";
|
|
1178
1298
|
function toSubscriberPaymentMethodRecord(row) {
|
|
1179
1299
|
return {
|
|
1180
1300
|
id: row.id,
|
|
@@ -1183,7 +1303,7 @@ function toSubscriberPaymentMethodRecord(row) {
|
|
|
1183
1303
|
provider: row.provider,
|
|
1184
1304
|
customerRef: row.customerRef,
|
|
1185
1305
|
paymentMethodRef: row.paymentMethodRef,
|
|
1186
|
-
type: oneOf(PAYMENT_METHOD_TYPES, row.type, "type", row.id),
|
|
1306
|
+
type: oneOf(PAYMENT_METHOD_TYPES, row.type, { table: TABLE2, column: "type", id: row.id }),
|
|
1187
1307
|
brand: row.brand,
|
|
1188
1308
|
last4: row.last4,
|
|
1189
1309
|
expiryMonth: row.expiryMonth,
|
|
@@ -1191,7 +1311,7 @@ function toSubscriberPaymentMethodRecord(row) {
|
|
|
1191
1311
|
country: row.country,
|
|
1192
1312
|
bankCode: row.bankCode,
|
|
1193
1313
|
mandateReference: row.mandateReference,
|
|
1194
|
-
status: oneOf(STATUSES, row.status, "status", row.id),
|
|
1314
|
+
status: oneOf(STATUSES, row.status, { table: TABLE2, column: "status", id: row.id }),
|
|
1195
1315
|
confirmedAt: row.confirmedAt,
|
|
1196
1316
|
replacedAt: row.replacedAt,
|
|
1197
1317
|
createdAt: row.createdAt
|
|
@@ -1215,14 +1335,53 @@ function subscriberPaymentMethodColumns(data) {
|
|
|
1215
1335
|
confirmedAt: data.confirmedAt
|
|
1216
1336
|
};
|
|
1217
1337
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
`
|
|
1338
|
+
var FOREIGN_PAYMENT_METHOD_REFERENCE = "FOREIGN_PAYMENT_METHOD_REFERENCE";
|
|
1339
|
+
var ForeignPaymentMethodReferenceError = class extends Error {
|
|
1340
|
+
constructor(gatewayAccount, paymentMethodRef) {
|
|
1341
|
+
super(
|
|
1342
|
+
`Payment method '${paymentMethodRef}' of account '${gatewayAccount}' belongs to another subscriber. A reference belongs to exactly one, so it is not handed out.`
|
|
1223
1343
|
);
|
|
1344
|
+
this.gatewayAccount = gatewayAccount;
|
|
1345
|
+
this.paymentMethodRef = paymentMethodRef;
|
|
1346
|
+
this.name = "ForeignPaymentMethodReferenceError";
|
|
1224
1347
|
}
|
|
1225
|
-
|
|
1348
|
+
gatewayAccount;
|
|
1349
|
+
paymentMethodRef;
|
|
1350
|
+
code = FOREIGN_PAYMENT_METHOD_REFERENCE;
|
|
1351
|
+
};
|
|
1352
|
+
function isForeignPaymentMethodReferenceError(error) {
|
|
1353
|
+
return error instanceof Error && error.code === FOREIGN_PAYMENT_METHOD_REFERENCE;
|
|
1354
|
+
}
|
|
1355
|
+
function refuseForeignPaymentMethodReference(recorded, subscriberId) {
|
|
1356
|
+
if (recorded.subscriberId === subscriberId) return;
|
|
1357
|
+
throw new ForeignPaymentMethodReferenceError(
|
|
1358
|
+
recorded.gatewayAccount,
|
|
1359
|
+
recorded.paymentMethodRef
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
// src/subscription-bundle-mapping.ts
|
|
1364
|
+
var BILLING_CYCLES = ["MONTHLY", "YEARLY"];
|
|
1365
|
+
function toSubscriptionBundleRecord(row) {
|
|
1366
|
+
const billingCycle = row.billingCycle ?? null;
|
|
1367
|
+
return {
|
|
1368
|
+
id: row.id,
|
|
1369
|
+
subscriptionId: row.subscriptionId,
|
|
1370
|
+
bundleVersionId: row.bundleVersionId,
|
|
1371
|
+
startedAt: row.startedAt,
|
|
1372
|
+
minimumTermEndsAt: row.minimumTermEndsAt,
|
|
1373
|
+
billingCycle: billingCycle === null ? null : oneOf(BILLING_CYCLES, billingCycle, {
|
|
1374
|
+
table: "subscription_bundles",
|
|
1375
|
+
column: "billingCycle",
|
|
1376
|
+
id: row.id
|
|
1377
|
+
}),
|
|
1378
|
+
currentPeriodStart: row.currentPeriodStart ?? null,
|
|
1379
|
+
currentPeriodEnd: row.currentPeriodEnd ?? null,
|
|
1380
|
+
canceledAt: row.canceledAt,
|
|
1381
|
+
canceledEffectiveAt: row.canceledEffectiveAt,
|
|
1382
|
+
createdAt: row.createdAt,
|
|
1383
|
+
updatedAt: row.updatedAt
|
|
1384
|
+
};
|
|
1226
1385
|
}
|
|
1227
1386
|
|
|
1228
1387
|
// src/subscription-contract-mapping.ts
|
|
@@ -1434,6 +1593,7 @@ var ERROR_MESSAGES_EN = {
|
|
|
1434
1593
|
FEATURE_NOT_FOUND: "Feature '{featureKey}' not found",
|
|
1435
1594
|
QUOTA_NOT_FOUND: "Quota '{quotaKey}' not found",
|
|
1436
1595
|
PROMOTION_NOT_FOUND: "Promotion '{promotionId}' not found",
|
|
1596
|
+
PROMOTION_VALUE_INVALID: "The value of a '{type}' promotion is not one its type takes: a percentage above 0 and at most 100, an amount above 0, an intro price of at least 0 for a whole number of months, or a whole number of free months.",
|
|
1437
1597
|
MARKETING_PROJECTION_NOT_FOUND: "MarketingProjection '{projectionId}' not found",
|
|
1438
1598
|
PLAN_ALREADY_EXISTS: "Plan '{planKey}' already exists",
|
|
1439
1599
|
BUNDLE_ALREADY_EXISTS: "Bundle '{bundleKey}' already exists",
|
|
@@ -1488,7 +1648,7 @@ var ERROR_MESSAGES_EN = {
|
|
|
1488
1648
|
// ── promo ──
|
|
1489
1649
|
PROMO_CODE_NOT_FOUND: "Code not found",
|
|
1490
1650
|
PROMO_CODE_ALREADY_EXISTS: "The code already exists.",
|
|
1491
|
-
PROMO_CODE_HAS_REDEMPTIONS: "The code already has redemptions \u2014 it cannot be soft-deleted. Pause it instead.",
|
|
1651
|
+
PROMO_CODE_HAS_REDEMPTIONS: "The code already has redemptions, or checkouts holding one \u2014 it cannot be soft-deleted. Pause it instead.",
|
|
1492
1652
|
PROMO_CODE_NOT_REDEEMABLE: "Code cannot be redeemed: {reason}",
|
|
1493
1653
|
PROMO_CODE_FORMAT_INVALID: 'The code may only contain upper-case letters, digits, "-" and "_" (4\u201332 characters).',
|
|
1494
1654
|
PROMO_PERCENT_OUT_OF_RANGE: "The percentage must be between 0 and 100.",
|
|
@@ -1518,6 +1678,8 @@ var ERROR_MESSAGES_EN = {
|
|
|
1518
1678
|
SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_PERCENT: "A subscription contract states a tax rate of {taxRate} at {field}, which is not a percentage: a rate lies from 0 to 100, and a value between 0 and 1 is refused as a fraction.",
|
|
1519
1679
|
SUBSCRIPTION_CONTRACT_TERMINATION_BEFORE_START: "effectiveUntil must be after the effectiveFrom of the contract.",
|
|
1520
1680
|
SUBSCRIPTION_CONTRACT_LINE_ITEM_CURRENCY_MISMATCH: "A line item must be booked in the currency its contract was priced in.",
|
|
1681
|
+
SUBSCRIPTION_CONTRACT_LINES_DO_NOT_ADD_UP: "The line items of a subscription contract add up to {lines} for {field}, but the contract states {stated}.",
|
|
1682
|
+
SUBSCRIPTION_CONTRACT_DISCOUNT_NEGATIVE: "A subscription contract states a discount of {amount} at {field}; a discount takes money off and is never negative.",
|
|
1521
1683
|
CHECKOUT_OFFER_NOT_FOUND: "CheckoutOffer '{offerId}' not found",
|
|
1522
1684
|
CHECKOUT_OFFER_EXPIRED: "Checkout offer '{offerId}' has expired and cannot be {action}",
|
|
1523
1685
|
CHECKOUT_OFFER_ALREADY_CONSUMED: "Checkout offer '{offerId}' has already been consumed and cannot be {action}",
|
|
@@ -1557,6 +1719,7 @@ var ERROR_MESSAGES_EN = {
|
|
|
1557
1719
|
PAYMENT_GATEWAY_ACCOUNT_UNKNOWN: "No payment gateway account is configured under '{account}'.",
|
|
1558
1720
|
PAYMENT_CALLBACK_REJECTED: "The payment callback could not be verified.",
|
|
1559
1721
|
PAYMENT_RETURN_URL_NOT_ALLOWED: "The {field} leads to a site this installation does not return to.",
|
|
1722
|
+
PAYMENT_GATEWAY_FAILED: "The payment provider did not answer as expected. Please try again in a few minutes.",
|
|
1560
1723
|
// ── entitlement (code lives in upsell.types.ts) ──
|
|
1561
1724
|
[FEATURE_NOT_LICENSED]: "Feature {featureKeys} is not included in the current plan.",
|
|
1562
1725
|
// ── settings ──
|
|
@@ -1641,6 +1804,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
1641
1804
|
FEATURE_NOT_FOUND: "Feature '{featureKey}' nicht gefunden",
|
|
1642
1805
|
QUOTA_NOT_FOUND: "Quota '{quotaKey}' nicht gefunden",
|
|
1643
1806
|
PROMOTION_NOT_FOUND: "Promotion '{promotionId}' nicht gefunden",
|
|
1807
|
+
PROMOTION_VALUE_INVALID: "Der Wert einer Aktion vom Typ '{type}' passt nicht zu ihrem Typ: ein Prozentsatz \xFCber 0 und h\xF6chstens 100, ein Betrag \xFCber 0, ein Einf\xFChrungspreis ab 0 f\xFCr eine ganze Zahl von Monaten oder eine ganze Zahl von Gratismonaten.",
|
|
1644
1808
|
MARKETING_PROJECTION_NOT_FOUND: "MarketingProjection '{projectionId}' nicht gefunden",
|
|
1645
1809
|
PLAN_ALREADY_EXISTS: "Plan '{planKey}' gibt es bereits",
|
|
1646
1810
|
BUNDLE_ALREADY_EXISTS: "Bundle '{bundleKey}' gibt es bereits",
|
|
@@ -1695,7 +1859,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
1695
1859
|
// ── promo ──
|
|
1696
1860
|
PROMO_CODE_NOT_FOUND: "Code nicht gefunden",
|
|
1697
1861
|
PROMO_CODE_ALREADY_EXISTS: "Diesen Code gibt es bereits.",
|
|
1698
|
-
PROMO_CODE_HAS_REDEMPTIONS: "Der Code wurde bereits eingel\xF6st \u2014 er l\xE4sst sich nicht per Soft-Delete entfernen. Pausiere ihn stattdessen.",
|
|
1862
|
+
PROMO_CODE_HAS_REDEMPTIONS: "Der Code wurde bereits eingel\xF6st oder ist f\xFCr einen laufenden Checkout reserviert \u2014 er l\xE4sst sich nicht per Soft-Delete entfernen. Pausiere ihn stattdessen.",
|
|
1699
1863
|
PROMO_CODE_NOT_REDEEMABLE: "Der Code l\xE4sst sich nicht einl\xF6sen: {reason}",
|
|
1700
1864
|
PROMO_CODE_FORMAT_INVALID: 'Der Code darf nur Gro\xDFbuchstaben, Ziffern, "-" und "_" enthalten (4\u201332 Zeichen).',
|
|
1701
1865
|
PROMO_PERCENT_OUT_OF_RANGE: "Der Prozentwert muss zwischen 0 und 100 liegen.",
|
|
@@ -1724,6 +1888,8 @@ var ERROR_MESSAGES_DE = {
|
|
|
1724
1888
|
SUBSCRIPTION_CONTRACT_LINE_ITEM_TAX_MISMATCH: "taxAmount einer Position muss exakt priceGross minus priceNet sein.",
|
|
1725
1889
|
SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_PERCENT: "Ein Abo-Vertrag nennt bei {field} einen Steuersatz von {taxRate}, der kein Prozentsatz ist: Ein Satz liegt zwischen 0 und 100, und ein Wert zwischen 0 und 1 wird als Bruch abgelehnt.",
|
|
1726
1890
|
SUBSCRIPTION_CONTRACT_LINE_ITEM_CURRENCY_MISMATCH: "Eine Position muss in der W\xE4hrung gebucht sein, in der ihr Vertrag bepreist ist.",
|
|
1891
|
+
SUBSCRIPTION_CONTRACT_LINES_DO_NOT_ADD_UP: "Die Positionen eines Abo-Vertrags ergeben {lines} f\xFCr {field}, der Vertrag nennt aber {stated}.",
|
|
1892
|
+
SUBSCRIPTION_CONTRACT_DISCOUNT_NEGATIVE: "Ein Abo-Vertrag nennt bei {field} einen Rabatt von {amount}; ein Rabatt zieht Geld ab und ist nie negativ.",
|
|
1727
1893
|
SUBSCRIPTION_CONTRACT_TERMINATION_BEFORE_START: "effectiveUntil muss nach dem effectiveFrom des Vertrags liegen.",
|
|
1728
1894
|
CHECKOUT_OFFER_NOT_FOUND: "CheckoutOffer '{offerId}' nicht gefunden",
|
|
1729
1895
|
CHECKOUT_OFFER_EXPIRED: "Checkout-Angebot '{offerId}' ist abgelaufen \u2014 '{action}' ist nicht mehr m\xF6glich",
|
|
@@ -1764,6 +1930,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
1764
1930
|
PAYMENT_GATEWAY_ACCOUNT_UNKNOWN: "Unter '{account}' ist kein Konto eines Zahlungsanbieters eingerichtet.",
|
|
1765
1931
|
PAYMENT_CALLBACK_REJECTED: "Die R\xFCckmeldung des Zahlungsanbieters lie\xDF sich nicht pr\xFCfen.",
|
|
1766
1932
|
PAYMENT_RETURN_URL_NOT_ALLOWED: "Die {field} f\xFChrt auf eine Seite, zu der diese Installation nicht zur\xFCckleitet.",
|
|
1933
|
+
PAYMENT_GATEWAY_FAILED: "Der Zahlungsanbieter hat nicht wie erwartet geantwortet. Bitte versuche es in ein paar Minuten noch einmal.",
|
|
1767
1934
|
// ── entitlement (code lives in upsell.types.ts) ──
|
|
1768
1935
|
[FEATURE_NOT_LICENSED]: "Das Feature {featureKeys} ist im aktuellen Plan nicht enthalten.",
|
|
1769
1936
|
// ── settings ──
|
|
@@ -1781,6 +1948,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
1781
1948
|
ERROR_MESSAGES_DE,
|
|
1782
1949
|
ERROR_MESSAGES_EN,
|
|
1783
1950
|
FEATURE_NOT_LICENSED,
|
|
1951
|
+
ForeignPaymentMethodReferenceError,
|
|
1784
1952
|
LEGAL_IDENTITY_FIELDS,
|
|
1785
1953
|
MARKETING_PRIORITY_MAX,
|
|
1786
1954
|
MARKETING_PRIORITY_MIN,
|
|
@@ -1804,6 +1972,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
1804
1972
|
REGISTRATION_STEP_BY_STATUS,
|
|
1805
1973
|
SETTINGS_ERROR_CODES,
|
|
1806
1974
|
SETUP_ERROR_CODES,
|
|
1975
|
+
SUBSCRIBER_ACCOUNT_CAPABILITY,
|
|
1807
1976
|
SUBSCRIBER_ERROR_CODES,
|
|
1808
1977
|
applyPromo,
|
|
1809
1978
|
assertPersistenceCapabilities,
|
|
@@ -1825,6 +1994,7 @@ var ERROR_MESSAGES_DE = {
|
|
|
1825
1994
|
formatErrorMessage,
|
|
1826
1995
|
identityCorrectionDelta,
|
|
1827
1996
|
isBundleRedundant,
|
|
1997
|
+
isForeignPaymentMethodReferenceError,
|
|
1828
1998
|
isPaymentCallbackRejectedError,
|
|
1829
1999
|
isPlatformUserExistsError,
|
|
1830
2000
|
isVersionEditable,
|
|
@@ -1836,15 +2006,18 @@ var ERROR_MESSAGES_DE = {
|
|
|
1836
2006
|
planCatalogSettingsOf,
|
|
1837
2007
|
previousUtcDay,
|
|
1838
2008
|
promoStatus,
|
|
2009
|
+
promotionOnPrice,
|
|
1839
2010
|
readQuotaRecord,
|
|
1840
2011
|
readQuotaValue,
|
|
1841
2012
|
recordedIssuerIdentity,
|
|
2013
|
+
refuseForeignPaymentMethodReference,
|
|
1842
2014
|
resolveBundleAvailability,
|
|
1843
2015
|
resolveErrorMessage,
|
|
1844
2016
|
sameLegalIdentity,
|
|
1845
2017
|
selectChargeableBundles,
|
|
1846
2018
|
settingsSubtreeOf,
|
|
1847
2019
|
startOfUtcDay,
|
|
2020
|
+
subscriberChargeColumns,
|
|
1848
2021
|
subscriberFromRegistration,
|
|
1849
2022
|
subscriberPaymentMethodColumns,
|
|
1850
2023
|
toBundleStemRow,
|
|
@@ -1852,8 +2025,10 @@ var ERROR_MESSAGES_DE = {
|
|
|
1852
2025
|
toPlanRow,
|
|
1853
2026
|
toPlanVersionRow,
|
|
1854
2027
|
toRunningContractIssuer,
|
|
2028
|
+
toSubscriberChargeRecord,
|
|
1855
2029
|
toSubscriberCorrectionRecord,
|
|
1856
2030
|
toSubscriberPaymentMethodRecord,
|
|
1857
2031
|
toSubscriberRecord,
|
|
2032
|
+
toSubscriptionBundleRecord,
|
|
1858
2033
|
toSubscriptionContractRecord
|
|
1859
2034
|
});
|