@saasicat/core 1.0.0-rc.24 → 1.0.0-rc.25

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/index.js CHANGED
@@ -404,7 +404,10 @@ var TABLE = "subscription_notices";
404
404
  var KINDS = {
405
405
  "version-offered": true,
406
406
  "version-retired": true,
407
- "version-retirement-reminder": true
407
+ "version-retirement-reminder": true,
408
+ "bundle-version-retired": true,
409
+ "bundle-version-retirement-reminder": true,
410
+ "bundle-version-offered": true
408
411
  };
409
412
  function toSubscriptionNoticeRecord(row) {
410
413
  return {
@@ -513,6 +516,28 @@ function toVersionRetirementRecord(row) {
513
516
  };
514
517
  }
515
518
 
519
+ // src/bundle-version-retirement.types.ts
520
+ var BUNDLE_VERSION_RETIREMENT_CAPABILITY = "bundleVersions.retire";
521
+
522
+ // src/bundle-version-retirement-mapping.ts
523
+ function toBundleVersionRetirementRecord(row) {
524
+ return {
525
+ id: row.id,
526
+ retired: {
527
+ bundleVersionId: row.retiredBundleVersionId,
528
+ bundleKey: row.retiredBundleKey,
529
+ version: row.retiredVersion
530
+ },
531
+ replacement: {
532
+ bundleVersionId: row.replacementBundleVersionId,
533
+ bundleKey: row.replacementBundleKey,
534
+ version: row.replacementVersion
535
+ },
536
+ announcedAt: row.announcedAt,
537
+ announcedBy: row.announcedBy
538
+ };
539
+ }
540
+
516
541
  // src/scheduled-change-after-write.ts
517
542
  var NO_SCHEDULED_CHANGE = {
518
543
  pendingPlan: null,
@@ -820,6 +845,13 @@ var CATALOG_ERROR_CODES = {
820
845
  PLAN_NOT_FOUND: "PLAN_NOT_FOUND",
821
846
  PLAN_VERSION_NOT_FOUND: "PLAN_VERSION_NOT_FOUND",
822
847
  BUNDLE_NOT_FOUND: "BUNDLE_NOT_FOUND",
848
+ /**
849
+ * Bookings told that their add-on version is being retired have still to
850
+ * move onto a version of this add-on — waiting for their notice, for their
851
+ * date, or past it — and a deleted add-on is booked by nothing, the move
852
+ * included. Carries how many, and the add-on's key.
853
+ */
854
+ BUNDLE_DELETE_WHILE_RETIREMENT_MOVES_PENDING: "BUNDLE_DELETE_WHILE_RETIREMENT_MOVES_PENDING",
823
855
  BUNDLE_VERSION_NOT_FOUND: "BUNDLE_VERSION_NOT_FOUND",
824
856
  FEATURE_NOT_FOUND: "FEATURE_NOT_FOUND",
825
857
  QUOTA_NOT_FOUND: "QUOTA_NOT_FOUND",
@@ -1010,6 +1042,16 @@ var BILLING_ERROR_CODES = {
1010
1042
  * to pick, so the way past it is the add-on ending.
1011
1043
  */
1012
1044
  RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW: "RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW",
1045
+ /**
1046
+ * As `RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW`, where only the version the
1047
+ * add-on continues on from a retirement's date cannot run beside the
1048
+ * replacement's plan. The version it is on can, so cancelling it — it then
1049
+ * ends before that date — lets the switch through. Given while that date
1050
+ * is ahead and the add-on is not cancelled yet; otherwise the earlier code
1051
+ * names the day it can end. Carries the add-on, that version, its date and
1052
+ * the plan.
1053
+ */
1054
+ RETIREMENT_SWITCH_BUNDLE_REPLACEMENT_CANNOT_FOLLOW: "RETIREMENT_SWITCH_BUNDLE_REPLACEMENT_CANNOT_FOLLOW",
1013
1055
  /**
1014
1056
  * The subscription takes no switch now: a change is scheduled, it has
1015
1057
  * ended, or its plan is held for a special contract.
@@ -1020,6 +1062,75 @@ var BILLING_ERROR_CODES = {
1020
1062
  * the retirement as it now stands.
1021
1063
  */
1022
1064
  RETIREMENT_SWITCH_CHANGED: "RETIREMENT_SWITCH_CHANGED",
1065
+ // ── retiring an add-on version for running bookings ──
1066
+ //
1067
+ // An add-on retirement answers with the plan retirement's codes where the
1068
+ // sentence is the same — terms not confirmed, a version named as its own
1069
+ // replacement, twelve months, a preview that changed — and with these
1070
+ // where it names an add-on rather than a plan.
1071
+ /**
1072
+ * The add-on version is still on sale: a booking made after the
1073
+ * announcement would be on it without having been told. Carries the
1074
+ * add-on key and the version.
1075
+ */
1076
+ BUNDLE_RETIREMENT_VERSION_ON_SALE: "BUNDLE_RETIREMENT_VERSION_ON_SALE",
1077
+ /** The replacement is not on sale, so no booking can continue on it. Carries add-on key and version. */
1078
+ BUNDLE_RETIREMENT_REPLACEMENT_NOT_ON_SALE: "BUNDLE_RETIREMENT_REPLACEMENT_NOT_ON_SALE",
1079
+ /**
1080
+ * The replacement is a version of another add-on. A booking continues on
1081
+ * a version of its own add-on, so it stays the same booking with its term.
1082
+ * Carries both add-on keys.
1083
+ */
1084
+ BUNDLE_RETIREMENT_REPLACEMENT_OF_ANOTHER_BUNDLE: "BUNDLE_RETIREMENT_REPLACEMENT_OF_ANOTHER_BUNDLE",
1085
+ /**
1086
+ * Some of the bookings it reaches run, at their date, beside a plan the
1087
+ * replacement cannot run beside: not allowed there, without a price there
1088
+ * in the booking's rhythm, or in a longer rhythm than the plan's. Carries
1089
+ * how many, and the replacement's add-on key and version.
1090
+ */
1091
+ BUNDLE_RETIREMENT_REPLACEMENT_CANNOT_RUN: "BUNDLE_RETIREMENT_REPLACEMENT_CANNOT_RUN",
1092
+ /** No running booking is on the version: there is nobody to tell. Carries add-on key and version. */
1093
+ BUNDLE_RETIREMENT_NOTHING_AFFECTED: "BUNDLE_RETIREMENT_NOTHING_AFFECTED",
1094
+ /**
1095
+ * The booking is on an add-on version being retired, and was cancelled to
1096
+ * end before it would move, so it was never told and nothing moves it.
1097
+ * Reinstated, it would run on past the date on a version nobody sells;
1098
+ * booking the replacement once it has ended is the way. Carries the add-on
1099
+ * key, the version, the replacement's version and the day it can be booked
1100
+ * from.
1101
+ */
1102
+ BUNDLE_RETIREMENT_REINSTATE_REFUSED: "BUNDLE_RETIREMENT_REINSTATE_REFUSED",
1103
+ /**
1104
+ * As `BUNDLE_RETIREMENT_REINSTATE_REFUSED`, where the replacement cannot
1105
+ * run beside the plan the subscription is on when the booking ends, or
1106
+ * beside one it is already set to move to after that, in any rhythm it
1107
+ * could be booked in, so there is no version of the add-on to book.
1108
+ * Carries the add-on key, the version and the replacement's version.
1109
+ */
1110
+ BUNDLE_RETIREMENT_REINSTATE_REPLACEMENT_CANNOT_RUN: "BUNDLE_RETIREMENT_REINSTATE_REPLACEMENT_CANNOT_RUN",
1111
+ /**
1112
+ * As `BUNDLE_RETIREMENT_REINSTATE_REFUSED`, where the subscription ends by
1113
+ * the day the replacement could be booked from, so there is no day to
1114
+ * name. Carries the add-on key, the version and the replacement's version.
1115
+ */
1116
+ BUNDLE_RETIREMENT_REINSTATE_SUBSCRIPTION_ENDS: "BUNDLE_RETIREMENT_REINSTATE_SUBSCRIPTION_ENDS",
1117
+ /**
1118
+ * The plan the add-on runs beside, or the rhythm it is billed in, changes
1119
+ * before the date the booking was told — by a change scheduled, or by a
1120
+ * retirement told that moves the subscription to another plan — so the
1121
+ * price a switch now would hold is not the one the booking pays until
1122
+ * then. Switching once the plan has changed, or waiting for the
1123
+ * date, is the way. Carries the add-on and the date.
1124
+ */
1125
+ BUNDLE_RETIREMENT_SWITCH_PLAN_CHANGES: "BUNDLE_RETIREMENT_SWITCH_PLAN_CHANGES",
1126
+ /**
1127
+ * The add-on version the caller asked to switch a booking to is no longer
1128
+ * the one offered beside it — another is on sale, the booking moved, or
1129
+ * there is no offer. Nothing was switched. Carries the version named
1130
+ * (`bundleVersionId`) and the current `offer`, or `null`, so the page can
1131
+ * show it instead of guessing.
1132
+ */
1133
+ BUNDLE_VERSION_OFFER_CHANGED: "BUNDLE_VERSION_OFFER_CHANGED",
1023
1134
  // ── the preview routes' own blockers and warnings ──
1024
1135
  //
1025
1136
  // These travel inside a 200 response, in `blockers[]` and `warnings[]`, not
@@ -1066,6 +1177,16 @@ var BILLING_ERROR_CODES = {
1066
1177
  * day the booking can end.
1067
1178
  */
1068
1179
  BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN: "BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN",
1180
+ /**
1181
+ * A bundle the tenant already holds can run on the plan they are moving
1182
+ * to, but the version it continues on from a retirement's date cannot.
1183
+ * Cancelling it lets the change through at once: the booking then ends
1184
+ * before that date and never reaches the version. Given while that date is
1185
+ * ahead and the booking is not cancelled yet; otherwise
1186
+ * `BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN` names the day it can end.
1187
+ * Carries the bundle, that version, its date and the plan.
1188
+ */
1189
+ BUNDLE_REPLACEMENT_DOES_NOT_FIT_TARGET_PLAN: "BUNDLE_REPLACEMENT_DOES_NOT_FIT_TARGET_PLAN",
1069
1190
  /**
1070
1191
  * Features of the previewed bundle are already covered by the plan or by
1071
1192
  * another booked bundle. A warning rather than a blocker: paying twice is
@@ -1135,6 +1256,21 @@ var CONTRACT_ERROR_CODES = {
1135
1256
  * describes. Nothing was written; load the offer and conclude it again.
1136
1257
  */
1137
1258
  CHECKOUT_OFFER_CHANGED: "CHECKOUT_OFFER_CHANGED",
1259
+ /**
1260
+ * An offer concludes a tenant's first contract, and this tenant has a
1261
+ * contract in force at the moment the offer's would take effect, or one
1262
+ * beginning after it. Concluded, the two would run side by side. Nothing
1263
+ * was written; a running subscription changes through its plan and its
1264
+ * add-ons. Carries the offer and the contract that runs.
1265
+ */
1266
+ CHECKOUT_OFFER_CONTRACT_IN_FORCE: "CHECKOUT_OFFER_CONTRACT_IN_FORCE",
1267
+ /**
1268
+ * The offer names a version of an add-on the tenant has booked in another
1269
+ * version. Concluded, the contract would name a version the booking is not
1270
+ * on. Nothing was written; a booking changes its version through the offer
1271
+ * beside it. Carries the offer, the add-on, the booking and both versions.
1272
+ */
1273
+ CHECKOUT_OFFER_ADD_ON_BOOKED_IN_ANOTHER_VERSION: "CHECKOUT_OFFER_ADD_ON_BOOKED_IN_ANOTHER_VERSION",
1138
1274
  SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND",
1139
1275
  NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT",
1140
1276
  SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED",
@@ -1145,7 +1281,12 @@ var CONTRACT_ERROR_CODES = {
1145
1281
  * second attempt, or a contract begins after the moment the successor
1146
1282
  * would take effect. Nothing was written.
1147
1283
  */
1148
- SUBSCRIPTION_CONTRACT_CHANGED: "SUBSCRIPTION_CONTRACT_CHANGED"
1284
+ SUBSCRIPTION_CONTRACT_CHANGED: "SUBSCRIPTION_CONTRACT_CHANGED",
1285
+ /**
1286
+ * A contract states a tax rate — `field` names where — other than the one
1287
+ * the installation's tax adapter decides for its subscriber.
1288
+ */
1289
+ SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_DECIDED: "SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_DECIDED"
1149
1290
  };
1150
1291
  var SUBSCRIBER_ERROR_CODES = {
1151
1292
  /**
@@ -1169,7 +1310,30 @@ var SUBSCRIBER_ERROR_CODES = {
1169
1310
  SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "SUBSCRIBER_CORRECTION_ACTOR_REQUIRED",
1170
1311
  SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "SUBSCRIBER_CORRECTION_CHANGES_NOTHING",
1171
1312
  /** The operator declared another legal entity: that is a transfer, not an edit. */
1172
- SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "SUBSCRIBER_TAKEOVER_IS_A_TRANSFER"
1313
+ SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "SUBSCRIBER_TAKEOVER_IS_A_TRANSFER",
1314
+ /**
1315
+ * A contact change named whether the subscriber is a business. That is part
1316
+ * of its tax origin and changes as a recorded change naming who made it.
1317
+ */
1318
+ SUBSCRIBER_BUSINESS_STATUS_NOT_A_CONTACT: "SUBSCRIBER_BUSINESS_STATUS_NOT_A_CONTACT",
1319
+ /** A change of the subscriber's contact details or business status did not say who makes it. */
1320
+ SUBSCRIBER_CHANGE_ACTOR_REQUIRED: "SUBSCRIBER_CHANGE_ACTOR_REQUIRED",
1321
+ /**
1322
+ * Where a tax adapter decides, a contract names its subscriber only once
1323
+ * the address an invoice names is complete (`SC-PRIC-032`): a party copied
1324
+ * onto a contract incomplete cannot be completed afterwards. Carries
1325
+ * `missing`, the empty fields, for a screen to name by their labels; the
1326
+ * shipped sentence names all four rather than the keys.
1327
+ */
1328
+ SUBSCRIBER_IDENTITY_INCOMPLETE: "SUBSCRIBER_IDENTITY_INCOMPLETE",
1329
+ /**
1330
+ * A change of whether the subscriber is a business states no reason. It
1331
+ * decides the tax treatment of the next invoice, so the change log keeps
1332
+ * why it moved (`SC-PRIC-043`).
1333
+ */
1334
+ SUBSCRIBER_BUSINESS_STATUS_REASON_REQUIRED: "SUBSCRIBER_BUSINESS_STATUS_REASON_REQUIRED",
1335
+ /** A check of the subscriber's VAT identification number was asked for, and it holds none. */
1336
+ SUBSCRIBER_VAT_ID_MISSING: "SUBSCRIBER_VAT_ID_MISSING"
1173
1337
  };
1174
1338
  var REGISTRATION_ERROR_CODES = {
1175
1339
  PENDING_REGISTRATION_NOT_FOUND: "PENDING_REGISTRATION_NOT_FOUND",
@@ -1274,6 +1438,29 @@ var MAINTENANCE_ERROR_CODES = {
1274
1438
  /** The message is longer than `MAINTENANCE_MESSAGE_MAX_LENGTH`. */
1275
1439
  MAINTENANCE_MESSAGE_TOO_LONG: "MAINTENANCE_MESSAGE_TOO_LONG"
1276
1440
  };
1441
+ var TAX_ERROR_CODES = {
1442
+ /**
1443
+ * The tax adapter answers that it does not support the subscriber's case;
1444
+ * `adapter` names it and `reason` is its sentence. Nothing is concluded with
1445
+ * a guessed tax (`SC-PRIC-039`).
1446
+ */
1447
+ TAX_TREATMENT_NOT_SUPPORTED: "TAX_TREATMENT_NOT_SUPPORTED",
1448
+ /**
1449
+ * The tax adapter needs the VAT identification number checked to treat the
1450
+ * case, and the check did not complete — the service is unavailable, timed
1451
+ * out, or answered in a way the adapter cannot read (`503`). Nothing is
1452
+ * decided in the subscriber's favour on a number not checked
1453
+ * (`SC-PRIC-040`): try again later. `adapter` names the adapter and
1454
+ * `reason` says why.
1455
+ */
1456
+ TAX_VAT_ID_CHECK_NOT_COMPLETED: "TAX_VAT_ID_CHECK_NOT_COMPLETED",
1457
+ /**
1458
+ * A VAT identification number was to be checked, and `config/saas.yaml`
1459
+ * names no tax adapter, which is what names the service to check with
1460
+ * (`409`).
1461
+ */
1462
+ TAX_VAT_ID_CHECK_NOT_AVAILABLE: "TAX_VAT_ID_CHECK_NOT_AVAILABLE"
1463
+ };
1277
1464
  var PLATFORM_ERROR_CODES = {
1278
1465
  ...SETUP_ERROR_CODES,
1279
1466
  ...AUTH_ERROR_CODES,
@@ -1285,7 +1472,8 @@ var PLATFORM_ERROR_CODES = {
1285
1472
  ...REGISTRATION_ERROR_CODES,
1286
1473
  ...PAYMENT_ERROR_CODES,
1287
1474
  ...SETTINGS_ERROR_CODES,
1288
- ...MAINTENANCE_ERROR_CODES
1475
+ ...MAINTENANCE_ERROR_CODES,
1476
+ ...TAX_ERROR_CODES
1289
1477
  };
1290
1478
 
1291
1479
  // src/errors.ts
@@ -1332,6 +1520,7 @@ var OPTIONAL_CANONICAL_MODELS = {
1332
1520
  MaintenanceWindow: ["core.maintenanceWindows"],
1333
1521
  SubscriptionNotice: ["tenantBilling.subscriptionNotices"],
1334
1522
  VersionRetirement: ["tenantBilling.versionRetirements"],
1523
+ BundleVersionRetirement: ["tenantBilling.bundleVersionRetirements"],
1335
1524
  SubscriberLedgerEntry: ["entitlement.subscriberLedgerRepository"],
1336
1525
  PromoCodeHold: ["promo.holdRepository"]
1337
1526
  };
@@ -1449,6 +1638,7 @@ var ERROR_MESSAGES_EN = {
1449
1638
  PLAN_NOT_FOUND: "Plan '{planId}' not found",
1450
1639
  PLAN_VERSION_NOT_FOUND: "PlanVersion '{versionId}' not found",
1451
1640
  BUNDLE_NOT_FOUND: "Bundle '{bundleId}' not found",
1641
+ 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.",
1452
1642
  BUNDLE_VERSION_NOT_FOUND: "BundleVersion '{bundleVersionId}' not found",
1453
1643
  FEATURE_NOT_FOUND: "Feature '{featureKey}' not found",
1454
1644
  QUOTA_NOT_FOUND: "Quota '{quotaKey}' not found",
@@ -1504,9 +1694,20 @@ var ERROR_MESSAGES_EN = {
1504
1694
  RETIREMENT_NOTHING_AFFECTED: "No running subscription is on version {version} of {planKey}, so there is nobody to tell.",
1505
1695
  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.",
1506
1696
  RETIREMENT_PREVIEW_CHANGED: "The subscriptions this retirement reaches changed since they were shown. Look at them again before announcing it.",
1697
+ 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.",
1698
+ BUNDLE_RETIREMENT_REPLACEMENT_NOT_ON_SALE: "Version {version} of {bundleKey} is not on sale, so bookings cannot continue on it.",
1699
+ 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.",
1700
+ 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.",
1701
+ BUNDLE_RETIREMENT_NOTHING_AFFECTED: "No running booking is on version {version} of {bundleKey}, so there is nobody to tell.",
1702
+ 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.",
1703
+ 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.",
1704
+ 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.",
1705
+ 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.",
1706
+ BUNDLE_VERSION_OFFER_CHANGED: "The offer changed since it was shown. Look at the current one before switching.",
1507
1707
  RETIREMENT_SWITCH_NOT_PENDING: "No retirement of your version is waiting for its date, so there is nothing to switch to.",
1508
1708
  RETIREMENT_SWITCH_IN_TRIAL: "The switch opens when your trial ends.",
1509
1709
  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.",
1710
+ 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.",
1510
1711
  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.",
1511
1712
  RETIREMENT_SWITCH_CHANGED: "The retirement changed since it was shown. Look at it again before switching.",
1512
1713
  SUBSCRIPTION_ENDED: "This subscription has ended. Its plan can no longer be changed.",
@@ -1519,6 +1720,7 @@ var ERROR_MESSAGES_EN = {
1519
1720
  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.",
1520
1721
  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.",
1521
1722
  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.",
1723
+ 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.",
1522
1724
  REDUNDANT_FEATURES: "The plan or another booked bundle already includes {count} of the features in this bundle \u2014 booking it pays for them twice.",
1523
1725
  MINIMUM_TERM_BINDS: "The minimum term extends beyond the end of the period \u2014 the cancellation only takes effect when the minimum term ends.",
1524
1726
  BUNDLE_FEATURE_DEPENDENCY_UNSATISFIED: "The bundle requires [{features}] \u2014 present neither in the plan nor in the active bundles.",
@@ -1543,6 +1745,7 @@ var ERROR_MESSAGES_EN = {
1543
1745
  PROMO_WOULD_PRODUCE_ZERO_INVOICE: "For absolute amounts the discount must stay below the lowest applicable plan price, or allowZeroInvoice must be enabled.",
1544
1746
  PROMO_MAX_REDEMPTIONS_LOWERED: "maxRedemptions cannot be lowered.",
1545
1747
  // ── contract ──
1748
+ SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_DECIDED: "The contract states {stated} % in {field}, and the tax adapter decides {decided} %.",
1546
1749
  CHECKOUT_OFFER_LINE_ITEMS_REQUIRED: "A checkout offer can yield only one contract, and only once its line items are frozen.",
1547
1750
  CHECKOUT_OFFER_PLAN_LINE_ITEM_REQUIRED: "A checkout offer requires a frozen plan line item.",
1548
1751
  CHECKOUT_OFFER_BUNDLE_LINE_ITEMS_REQUIRED: "Every selected bundle version requires a frozen bundle line item.",
@@ -1567,6 +1770,8 @@ var ERROR_MESSAGES_EN = {
1567
1770
  CHECKOUT_OFFER_ALREADY_CONSUMED: "Checkout offer '{offerId}' has already been consumed and cannot be {action}",
1568
1771
  CHECKOUT_OFFER_NOT_CONSUMED: "CheckoutOffer '{offerId}' must be consumed before the contract is created",
1569
1772
  CHECKOUT_OFFER_CHANGED: "Checkout offer '{offerId}' changed while it was being concluded. Load it again.",
1773
+ 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.",
1774
+ 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.",
1570
1775
  SUBSCRIPTION_CONTRACT_NOT_FOUND: "SubscriptionContract '{contractId}' not found",
1571
1776
  NO_ACTIVE_SUBSCRIPTION_CONTRACT: "No active subscription contract for tenant {tenantId}",
1572
1777
  SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SubscriptionContract '{contractId}' is already closed",
@@ -1577,11 +1782,16 @@ var ERROR_MESSAGES_EN = {
1577
1782
  SUBSCRIBER_NOT_FOUND: "Subscriber '{subscriberId}' not found",
1578
1783
  SUBSCRIBER_LEGAL_NAME_REQUIRED: "A subscriber needs its legal name.",
1579
1784
  SUBSCRIBER_DETAIL_INVALID: "The subscriber's {field} is not valid.",
1785
+ 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.",
1580
1786
  SUBSCRIBER_IDENTITY_NOT_A_CONTACT: "{field} is part of the subscriber's legal identity and changes only as a correction, with a reason.",
1787
+ SUBSCRIBER_BUSINESS_STATUS_REASON_REQUIRED: "A change of whether the subscriber is a business needs a reason.",
1788
+ SUBSCRIBER_VAT_ID_MISSING: "The subscriber has no VAT identification number to check.",
1581
1789
  SUBSCRIBER_CORRECTION_REASON_REQUIRED: "A correction of the legal identity needs a reason.",
1582
1790
  SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "A correction of the legal identity has to say who makes it.",
1583
1791
  SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "The correction changes nothing: every value it names is already recorded.",
1584
1792
  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.",
1793
+ 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.",
1794
+ SUBSCRIBER_CHANGE_ACTOR_REQUIRED: "A change of the subscriber's details has to say who makes it.",
1585
1795
  // ── registration ──
1586
1796
  PENDING_REGISTRATION_NOT_FOUND: "This registration could not be found. It may have already been completed or discarded.",
1587
1797
  PENDING_REGISTRATION_EXPIRED: "This registration has expired. Please start again.",
@@ -1615,7 +1825,11 @@ var ERROR_MESSAGES_EN = {
1615
1825
  MAINTENANCE_WINDOW_END_NOT_AFTER_START: "The end of a maintenance window has to be after its start.",
1616
1826
  MAINTENANCE_WINDOW_END_IN_PAST: "The end of a maintenance window cannot be in the past.",
1617
1827
  MAINTENANCE_TIME_INVALID: "The {field} has to be a date and time with its zone, such as 2026-10-02T22:00+02:00.",
1618
- MAINTENANCE_MESSAGE_TOO_LONG: "The message may be at most {max} characters long."
1828
+ MAINTENANCE_MESSAGE_TOO_LONG: "The message may be at most {max} characters long.",
1829
+ // ── tax ──
1830
+ TAX_TREATMENT_NOT_SUPPORTED: "The tax adapter {adapter} does not support this case: {reason}",
1831
+ TAX_VAT_ID_CHECK_NOT_COMPLETED: "The VAT identification number could not be checked just now ({reason}). Please try again later.",
1832
+ TAX_VAT_ID_CHECK_NOT_AVAILABLE: "This installation names no tax adapter, so no VAT identification number is checked."
1619
1833
  };
1620
1834
  function formatErrorMessage(template, params = {}) {
1621
1835
  return template.replace(/\{(\w+)\}/g, (match, name) => {
@@ -1972,6 +2186,7 @@ var ORIGINS = {
1972
2186
  renewal: true,
1973
2187
  planChange: true,
1974
2188
  bundleBooking: true,
2189
+ bundleChange: true,
1975
2190
  credit: true,
1976
2191
  correction: true
1977
2192
  };
@@ -2032,6 +2247,137 @@ function keysOf(record) {
2032
2247
  // src/subscriber-ledger.types.ts
2033
2248
  var SUBSCRIBER_ACCOUNT_CAPABILITY = "charges.read";
2034
2249
 
2250
+ // src/subscriber.types.ts
2251
+ var SUBSCRIBER_INVOICE_ADDRESS_FIELDS = [
2252
+ "addressLine1",
2253
+ "postalCode",
2254
+ "city",
2255
+ "country"
2256
+ ];
2257
+ var SUBSCRIBER_STANDING_CAPABILITY = "subscribers.read";
2258
+ var SUBSCRIBER_ATTENTION_CAPABILITY = "subscribers.attention";
2259
+ var SUBSCRIBER_ATTENTION_PAGE_SIZE = 200;
2260
+ var SUBSCRIBER_CORRECTION_CAPABILITY = "subscribers.correct";
2261
+ var SUBSCRIBER_TAX_ORIGIN_FIELDS = ["country", "business", "vatId"];
2262
+
2263
+ // src/tax.types.ts
2264
+ var TAX_TREATMENT_KINDS = [
2265
+ "standard",
2266
+ "reduced",
2267
+ "exempt",
2268
+ "reverse-charge",
2269
+ "not-taxable",
2270
+ "small-business"
2271
+ ];
2272
+
2273
+ // src/tax-origin.ts
2274
+ var VAT_ID_SEPARATORS = /[\s.-]/g;
2275
+ function canonicalVatId(written) {
2276
+ const vatId = written.replace(VAT_ID_SEPARATORS, "").toUpperCase();
2277
+ return vatId === "" ? null : vatId;
2278
+ }
2279
+ function taxOriginOf(subscriber, currentCheck) {
2280
+ const validated = subscriber.vatId !== null && currentCheck?.valid === true && currentCheck.vatId === subscriber.vatId;
2281
+ return {
2282
+ country: subscriber.country,
2283
+ business: subscriber.business,
2284
+ vatId: subscriber.vatId,
2285
+ validatedVatId: validated ? subscriber.vatId : null
2286
+ };
2287
+ }
2288
+ function keepsVatIdCheck(held, counting, check) {
2289
+ if (held.vatId === null || check.vatId !== held.vatId) return false;
2290
+ if (held.vatIdSince !== null && check.checkedAt.getTime() < held.vatIdSince.getTime()) {
2291
+ return false;
2292
+ }
2293
+ if (counting === null || counting.vatId !== held.vatId) return true;
2294
+ return counting.checkedAt.getTime() <= check.checkedAt.getTime();
2295
+ }
2296
+ function toSubscriberVatIdCheckRecord(row) {
2297
+ return {
2298
+ id: row.id,
2299
+ subscriberId: row.subscriberId,
2300
+ vatId: row.vatId,
2301
+ checkedAt: row.checkedAt,
2302
+ valid: row.valid,
2303
+ service: row.service,
2304
+ confirmation: textEntries(row.confirmation),
2305
+ recordedAt: row.recordedAt
2306
+ };
2307
+ }
2308
+ function taxTreatmentToJson(treatment) {
2309
+ return {
2310
+ kind: treatment.kind,
2311
+ rate: treatment.rate,
2312
+ note: treatment.note,
2313
+ adapter: { name: treatment.adapter.name, version: treatment.adapter.version }
2314
+ };
2315
+ }
2316
+ function toTaxTreatment(value) {
2317
+ if (!isObject(value)) return null;
2318
+ const { kind, rate, note, adapter } = value;
2319
+ if (!isTreatmentKind(kind)) return null;
2320
+ if (typeof rate !== "number" || !Number.isFinite(rate)) return null;
2321
+ if (note !== null && typeof note !== "string") return null;
2322
+ if (!isObject(adapter)) return null;
2323
+ if (typeof adapter.name !== "string" || typeof adapter.version !== "string") return null;
2324
+ return { kind, rate, note, adapter: { name: adapter.name, version: adapter.version } };
2325
+ }
2326
+ function taxOriginWrite(current, next) {
2327
+ const previous = {};
2328
+ const changed = {};
2329
+ for (const field of SUBSCRIBER_TAX_ORIGIN_FIELDS) {
2330
+ const value = next[field];
2331
+ if (value === void 0 || value === current[field]) continue;
2332
+ previous[field] = current[field];
2333
+ changed[field] = value;
2334
+ }
2335
+ return {
2336
+ previous,
2337
+ changed,
2338
+ moved: Object.keys(changed).length > 0,
2339
+ endsCountingVatIdCheck: Object.prototype.hasOwnProperty.call(changed, "vatId")
2340
+ };
2341
+ }
2342
+ function toTaxOriginValues(value) {
2343
+ if (!isObject(value)) return {};
2344
+ const values = {};
2345
+ for (const field of SUBSCRIBER_TAX_ORIGIN_FIELDS) {
2346
+ if (!Object.prototype.hasOwnProperty.call(value, field)) continue;
2347
+ const entry = value[field];
2348
+ if (field === "business") {
2349
+ values[field] = typeof entry === "boolean" ? entry : null;
2350
+ } else {
2351
+ values[field] = typeof entry === "string" ? entry : null;
2352
+ }
2353
+ }
2354
+ return values;
2355
+ }
2356
+ function isTreatmentKind(value) {
2357
+ return TAX_TREATMENT_KINDS.includes(value);
2358
+ }
2359
+ function isObject(value) {
2360
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2361
+ }
2362
+ function vatIdCheckFromStore(value) {
2363
+ if (!isObject(value)) return null;
2364
+ const { vatId, checkedAt, valid, service, confirmation } = value;
2365
+ const at = checkedAt instanceof Date ? checkedAt : new Date(String(checkedAt));
2366
+ if (typeof vatId !== "string" || typeof valid !== "boolean" || typeof service !== "string") {
2367
+ return null;
2368
+ }
2369
+ if (checkedAt === void 0 || checkedAt === null || Number.isNaN(at.getTime())) return null;
2370
+ return { vatId, checkedAt: at, valid, service, confirmation: textEntries(confirmation) };
2371
+ }
2372
+ function textEntries(value) {
2373
+ if (!isObject(value)) return {};
2374
+ const entries = {};
2375
+ for (const [key, entry] of Object.entries(value)) {
2376
+ if (typeof entry === "string") entries[key] = entry;
2377
+ }
2378
+ return entries;
2379
+ }
2380
+
2035
2381
  // src/subscriber-mapping.ts
2036
2382
  function formatCustomerNumber(prefix, sequence) {
2037
2383
  return `${prefix}${sequence}`;
@@ -2049,6 +2395,7 @@ function toSubscriberRecord(row, tenantId) {
2049
2395
  vatId: row.vatId,
2050
2396
  taxNumber: row.taxNumber,
2051
2397
  invoiceEmail: row.invoiceEmail,
2398
+ business: row.business,
2052
2399
  tenantId,
2053
2400
  migrated: row.migrated,
2054
2401
  createdAt: row.createdAt,
@@ -2066,6 +2413,17 @@ function toSubscriberCorrectionRecord(row) {
2066
2413
  correctedAt: row.correctedAt
2067
2414
  };
2068
2415
  }
2416
+ function toSubscriberTaxOriginChangeRecord(row) {
2417
+ return {
2418
+ id: row.id,
2419
+ subscriberId: row.subscriberId,
2420
+ previous: toTaxOriginValues(row.previous),
2421
+ changed: toTaxOriginValues(row.changed),
2422
+ changedBy: row.changedBy,
2423
+ changedAt: row.changedAt,
2424
+ reason: row.reason
2425
+ };
2426
+ }
2069
2427
  function identityCorrectionDelta(current, corrected) {
2070
2428
  const previous = {};
2071
2429
  const next = {};
@@ -2129,7 +2487,9 @@ function subscriberFromRegistration(pending) {
2129
2487
  city: pending.city,
2130
2488
  country: pending.country,
2131
2489
  vatId: pending.vatId,
2132
- taxNumber: pending.taxNumber
2490
+ taxNumber: pending.taxNumber,
2491
+ business: pending.business,
2492
+ vatIdCheck: vatIdCheckFromStore(pending.vatIdCheck)
2133
2493
  };
2134
2494
  }
2135
2495
  function toIdentityValues(value) {
@@ -2230,6 +2590,8 @@ function toSubscriptionBundleRecord(row) {
2230
2590
  }),
2231
2591
  currentPeriodStart: row.currentPeriodStart ?? null,
2232
2592
  currentPeriodEnd: row.currentPeriodEnd ?? null,
2593
+ pendingBundleVersionId: row.pendingBundleVersionId ?? null,
2594
+ pendingVersionEffectiveAt: row.pendingVersionEffectiveAt ?? null,
2233
2595
  canceledAt: row.canceledAt,
2234
2596
  canceledEffectiveAt: row.canceledEffectiveAt,
2235
2597
  createdAt: row.createdAt,
@@ -2246,6 +2608,7 @@ function toSubscriptionContractRecord(row, lineItems) {
2246
2608
  subscriber: toSubscriberParty(row.subscriberSnapshot),
2247
2609
  issuer: isPlainObject2(row.issuerSnapshot) ? toIssuerParty(row.issuerSnapshot) : null,
2248
2610
  partiesMigrated: row.partiesMigrated,
2611
+ taxTreatment: toTaxTreatment(row.taxTreatment),
2249
2612
  status: row.status,
2250
2613
  effectiveFrom: row.effectiveFrom,
2251
2614
  effectiveUntil: row.effectiveUntil,
@@ -2493,6 +2856,7 @@ var ERROR_MESSAGES_DE = {
2493
2856
  PLAN_NOT_FOUND: "Plan '{planId}' nicht gefunden",
2494
2857
  PLAN_VERSION_NOT_FOUND: "PlanVersion '{versionId}' nicht gefunden",
2495
2858
  BUNDLE_NOT_FOUND: "Bundle '{bundleId}' nicht gefunden",
2859
+ 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.",
2496
2860
  BUNDLE_VERSION_NOT_FOUND: "BundleVersion '{bundleVersionId}' nicht gefunden",
2497
2861
  FEATURE_NOT_FOUND: "Feature '{featureKey}' nicht gefunden",
2498
2862
  QUOTA_NOT_FOUND: "Quota '{quotaKey}' nicht gefunden",
@@ -2548,9 +2912,20 @@ var ERROR_MESSAGES_DE = {
2548
2912
  RETIREMENT_NOTHING_AFFECTED: "Kein laufendes Abonnement nutzt Version {version} von {planKey}. Es gibt niemanden zu benachrichtigen.",
2549
2913
  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.",
2550
2914
  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.",
2915
+ 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.",
2916
+ BUNDLE_RETIREMENT_REPLACEMENT_NOT_ON_SALE: "Version {version} von {bundleKey} wird nicht verkauft. Buchungen k\xF6nnen nicht auf ihr weiterlaufen.",
2917
+ 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.",
2918
+ 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.",
2919
+ BUNDLE_RETIREMENT_NOTHING_AFFECTED: "Keine laufende Buchung nutzt Version {version} von {bundleKey}. Es gibt niemanden zu benachrichtigen.",
2920
+ 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.",
2921
+ 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.",
2922
+ 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.",
2923
+ 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.",
2924
+ BUNDLE_VERSION_OFFER_CHANGED: "Das Angebot hat sich seit der Anzeige ge\xE4ndert. Bitte sieh dir das aktuelle an, bevor du wechselst.",
2551
2925
  RETIREMENT_SWITCH_NOT_PENDING: "F\xFCr Ihre Version steht keine Einstellung mehr bevor. Es gibt nichts, wohin Sie wechseln k\xF6nnten.",
2552
2926
  RETIREMENT_SWITCH_IN_TRIAL: "Der Wechsel ist m\xF6glich, sobald Ihre Testphase endet.",
2553
2927
  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.",
2928
+ 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.",
2554
2929
  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.",
2555
2930
  RETIREMENT_SWITCH_CHANGED: "Die Einstellung hat sich seit der Anzeige ge\xE4ndert. Sehen Sie sie sich noch einmal an, bevor Sie wechseln.",
2556
2931
  SUBSCRIPTION_ENDED: "Dieses Abonnement ist beendet. Sein Paket kann nicht mehr gewechselt werden.",
@@ -2563,6 +2938,7 @@ var ERROR_MESSAGES_DE = {
2563
2938
  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.",
2564
2939
  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.",
2565
2940
  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.",
2941
+ 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.",
2566
2942
  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.",
2567
2943
  MINIMUM_TERM_BINDS: "Die Mindestlaufzeit reicht \xFCber das Ende der Periode hinaus \u2014 die K\xFCndigung wird erst zum Ende der Mindestlaufzeit wirksam.",
2568
2944
  BUNDLE_FEATURE_DEPENDENCY_UNSATISFIED: "Das Bundle setzt [{features}] voraus \u2014 weder im Plan noch in den aktiven Bundles vorhanden.",
@@ -2587,6 +2963,7 @@ var ERROR_MESSAGES_DE = {
2587
2963
  PROMO_WOULD_PRODUCE_ZERO_INVOICE: "Bei absoluten Betr\xE4gen muss der Rabatt unter dem niedrigsten anwendbaren Planpreis bleiben, oder allowZeroInvoice muss aktiviert sein.",
2588
2964
  PROMO_MAX_REDEMPTIONS_LOWERED: "maxRedemptions l\xE4sst sich nicht senken.",
2589
2965
  // ── contract ──
2966
+ SUBSCRIPTION_CONTRACT_TAX_RATE_NOT_DECIDED: "Der Vertrag nennt in {field} {stated} %, der Steueradapter entscheidet {decided} %.",
2590
2967
  CHECKOUT_OFFER_LINE_ITEMS_REQUIRED: "Aus einem Checkout-Angebot entsteht nur ein einziger Vertrag, und das erst, wenn seine Positionen eingefroren sind.",
2591
2968
  CHECKOUT_OFFER_PLAN_LINE_ITEM_REQUIRED: "Ein Checkout-Angebot braucht eine eingefrorene Plan-Position.",
2592
2969
  CHECKOUT_OFFER_BUNDLE_LINE_ITEMS_REQUIRED: "Jede gew\xE4hlte Bundle-Version braucht eine eingefrorene Bundle-Position.",
@@ -2611,6 +2988,8 @@ var ERROR_MESSAGES_DE = {
2611
2988
  CHECKOUT_OFFER_ALREADY_CONSUMED: "Checkout-Angebot '{offerId}' wurde bereits eingel\xF6st \u2014 '{action}' ist nicht mehr m\xF6glich",
2612
2989
  CHECKOUT_OFFER_NOT_CONSUMED: "CheckoutOffer '{offerId}' muss eingel\xF6st sein, bevor der Vertrag entsteht",
2613
2990
  CHECKOUT_OFFER_CHANGED: "Checkout-Angebot '{offerId}' hat sich w\xE4hrend des Abschlusses ge\xE4ndert. Bitte neu laden.",
2991
+ 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.",
2992
+ 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.",
2614
2993
  SUBSCRIPTION_CONTRACT_NOT_FOUND: "SubscriptionContract '{contractId}' nicht gefunden",
2615
2994
  NO_ACTIVE_SUBSCRIPTION_CONTRACT: "Kein aktiver Abo-Vertrag f\xFCr Mandant {tenantId}",
2616
2995
  SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SubscriptionContract '{contractId}' ist bereits geschlossen",
@@ -2621,11 +3000,16 @@ var ERROR_MESSAGES_DE = {
2621
3000
  SUBSCRIBER_NOT_FOUND: "Vertragspartner '{subscriberId}' nicht gefunden",
2622
3001
  SUBSCRIBER_LEGAL_NAME_REQUIRED: "Ein Vertragspartner braucht seinen rechtlichen Namen.",
2623
3002
  SUBSCRIBER_DETAIL_INVALID: "Das Feld {field} des Vertragspartners ist ung\xFCltig.",
3003
+ 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.",
3004
+ SUBSCRIBER_BUSINESS_STATUS_REASON_REQUIRED: "Eine \xC4nderung, ob der Vertragspartner ein Unternehmen ist, braucht eine Begr\xFCndung.",
3005
+ SUBSCRIBER_VAT_ID_MISSING: "Der Vertragspartner hat keine Umsatzsteuer-Identifikationsnummer, die sich pr\xFCfen lie\xDFe.",
2624
3006
  SUBSCRIBER_IDENTITY_NOT_A_CONTACT: "{field} geh\xF6rt zur rechtlichen Identit\xE4t des Vertragspartners und \xE4ndert sich nur als Korrektur mit Begr\xFCndung.",
2625
3007
  SUBSCRIBER_CORRECTION_REASON_REQUIRED: "Eine Korrektur der rechtlichen Identit\xE4t braucht eine Begr\xFCndung.",
2626
3008
  SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "Eine Korrektur der rechtlichen Identit\xE4t muss nennen, wer sie vornimmt.",
2627
3009
  SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "Die Korrektur \xE4ndert nichts: Jeder genannte Wert ist bereits erfasst.",
2628
3010
  SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "\xDCbernimmt eine andere Rechtsperson, ist das eine \xDCbertragung und keine Korrektur; sie l\xE4sst sich nicht als \xC4nderung erfassen.",
3011
+ 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.",
3012
+ SUBSCRIBER_CHANGE_ACTOR_REQUIRED: "Eine \xC4nderung der Angaben des Vertragspartners muss nennen, wer sie vornimmt.",
2629
3013
  // ── registration ──
2630
3014
  PENDING_REGISTRATION_NOT_FOUND: "Diese Registrierung konnten wir nicht finden. Vielleicht ist sie bereits abgeschlossen oder verworfen.",
2631
3015
  PENDING_REGISTRATION_EXPIRED: "Diese Registrierung ist abgelaufen. Bitte fange noch einmal von vorn an.",
@@ -2659,13 +3043,18 @@ var ERROR_MESSAGES_DE = {
2659
3043
  MAINTENANCE_WINDOW_END_NOT_AFTER_START: "Das Ende eines Wartungsfensters muss nach seinem Beginn liegen.",
2660
3044
  MAINTENANCE_WINDOW_END_IN_PAST: "Das Ende eines Wartungsfensters darf nicht in der Vergangenheit liegen.",
2661
3045
  MAINTENANCE_TIME_INVALID: "{field} muss Datum und Uhrzeit mit Zeitzone sein, etwa 2026-10-02T22:00+02:00.",
2662
- MAINTENANCE_MESSAGE_TOO_LONG: "Die Nachricht darf h\xF6chstens {max} Zeichen lang sein."
3046
+ MAINTENANCE_MESSAGE_TOO_LONG: "Die Nachricht darf h\xF6chstens {max} Zeichen lang sein.",
3047
+ // ── tax ──
3048
+ TAX_TREATMENT_NOT_SUPPORTED: "Der Steueradapter {adapter} unterst\xFCtzt diesen Fall nicht: {reason}",
3049
+ TAX_VAT_ID_CHECK_NOT_COMPLETED: "Die Umsatzsteuer-Identifikationsnummer lie\xDF sich gerade nicht pr\xFCfen ({reason}). Bitte sp\xE4ter erneut versuchen.",
3050
+ TAX_VAT_ID_CHECK_NOT_AVAILABLE: "Diese Installation nennt keinen Steueradapter, darum wird keine Umsatzsteuer-Identifikationsnummer gepr\xFCft."
2663
3051
  };
2664
3052
  export {
2665
3053
  ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES,
2666
3054
  AUTH_ERROR_CODES,
2667
3055
  BILLING_ERROR_CODES,
2668
3056
  BUNDLE_PRICE_LOOKUP_LIMIT,
3057
+ BUNDLE_VERSION_RETIREMENT_CAPABILITY,
2669
3058
  CATALOGUE_KEYS,
2670
3059
  CATALOG_ERROR_CODES,
2671
3060
  CONTRACT_ERROR_CODES,
@@ -2706,7 +3095,15 @@ export {
2706
3095
  SETTINGS_ERROR_CODES,
2707
3096
  SETUP_ERROR_CODES,
2708
3097
  SUBSCRIBER_ACCOUNT_CAPABILITY,
3098
+ SUBSCRIBER_ATTENTION_CAPABILITY,
3099
+ SUBSCRIBER_ATTENTION_PAGE_SIZE,
3100
+ SUBSCRIBER_CORRECTION_CAPABILITY,
2709
3101
  SUBSCRIBER_ERROR_CODES,
3102
+ SUBSCRIBER_INVOICE_ADDRESS_FIELDS,
3103
+ SUBSCRIBER_STANDING_CAPABILITY,
3104
+ SUBSCRIBER_TAX_ORIGIN_FIELDS,
3105
+ TAX_ERROR_CODES,
3106
+ TAX_TREATMENT_KINDS,
2710
3107
  VERSION_RETIREMENT_CAPABILITY,
2711
3108
  applyPromo,
2712
3109
  assertPersistenceCapabilities,
@@ -2717,6 +3114,7 @@ export {
2717
3114
  bundleKeyTaken,
2718
3115
  bundleStemDefaults,
2719
3116
  canonicalJson,
3117
+ canonicalVatId,
2720
3118
  catalogDraftExists,
2721
3119
  catalogVersionAlreadyPublished,
2722
3120
  catalogVersionGone,
@@ -2748,6 +3146,7 @@ export {
2748
3146
  isVersionEditable,
2749
3147
  issuerIdentityOf,
2750
3148
  keepOneRecommended,
3149
+ keepsVatIdCheck,
2751
3150
  maintenanceRetryAfterSeconds,
2752
3151
  maintenanceStatusOf,
2753
3152
  maintenanceWindowStatusOf,
@@ -2794,7 +3193,11 @@ export {
2794
3193
  subscriptionContractGone,
2795
3194
  subscriptionGone,
2796
3195
  sumToCents,
3196
+ taxOriginOf,
3197
+ taxOriginWrite,
3198
+ taxTreatmentToJson,
2797
3199
  toBundleStemRow,
3200
+ toBundleVersionRetirementRecord,
2798
3201
  toCents,
2799
3202
  toContractLineItemRecord,
2800
3203
  toDecimalString,
@@ -2806,10 +3209,15 @@ export {
2806
3209
  toSubscriberCorrectionRecord,
2807
3210
  toSubscriberPaymentMethodRecord,
2808
3211
  toSubscriberRecord,
3212
+ toSubscriberTaxOriginChangeRecord,
3213
+ toSubscriberVatIdCheckRecord,
2809
3214
  toSubscriptionBundleRecord,
2810
3215
  toSubscriptionContractRecord,
2811
3216
  toSubscriptionNoticeRecord,
3217
+ toTaxOriginValues,
3218
+ toTaxTreatment,
2812
3219
  toVersionRetirementRecord,
3220
+ vatIdCheckFromStore,
2813
3221
  versionOnSale,
2814
3222
  versionOnSaleOrNext,
2815
3223
  versionSale