@saasicat/nest 0.2.0
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/LICENSE +202 -0
- package/README.md +53 -0
- package/dist/admin/index.cjs +1283 -0
- package/dist/admin/index.d.cts +225 -0
- package/dist/admin/index.d.ts +225 -0
- package/dist/admin/index.js +58 -0
- package/dist/admin-audit.service-9IqXMlZm.d.cts +30 -0
- package/dist/admin-audit.service-9IqXMlZm.d.ts +30 -0
- package/dist/admin-manifest.config-DyrQNT7M.d.cts +10 -0
- package/dist/admin-manifest.config-DyrQNT7M.d.ts +10 -0
- package/dist/aggregation-CJ3qQf92.d.cts +288 -0
- package/dist/aggregation-Dvz9e8X2.d.ts +288 -0
- package/dist/billing/index.cjs +5205 -0
- package/dist/billing/index.d.cts +1326 -0
- package/dist/billing/index.d.ts +1326 -0
- package/dist/billing/index.js +197 -0
- package/dist/catalog/index.cjs +6449 -0
- package/dist/catalog/index.d.cts +1073 -0
- package/dist/catalog/index.d.ts +1073 -0
- package/dist/catalog/index.js +158 -0
- package/dist/checkout-offer/index.cjs +807 -0
- package/dist/checkout-offer/index.d.cts +120 -0
- package/dist/checkout-offer/index.d.ts +120 -0
- package/dist/checkout-offer/index.js +20 -0
- package/dist/chunk-2FR6ZL7R.js +0 -0
- package/dist/chunk-2PNX2QL2.js +347 -0
- package/dist/chunk-2VNZYRDV.js +326 -0
- package/dist/chunk-7MLGHWKO.js +12 -0
- package/dist/chunk-ABB2CRAS.js +31 -0
- package/dist/chunk-AJ3EPELS.js +157 -0
- package/dist/chunk-E56W4U2P.js +90 -0
- package/dist/chunk-HRU3CP57.js +71 -0
- package/dist/chunk-L4SUWH5B.js +14 -0
- package/dist/chunk-M6CZQYPY.js +314 -0
- package/dist/chunk-MDIZUVIK.js +87 -0
- package/dist/chunk-MV6LW5UB.js +217 -0
- package/dist/chunk-NYLON2VC.js +6 -0
- package/dist/chunk-P6MYZMXQ.js +951 -0
- package/dist/chunk-Q53N43LQ.js +13 -0
- package/dist/chunk-QJVPRD3R.js +573 -0
- package/dist/chunk-RIGLQ4BV.js +3367 -0
- package/dist/chunk-SABTXESR.js +24 -0
- package/dist/chunk-SHUYVCID.js +6 -0
- package/dist/chunk-SYEVGPFC.js +686 -0
- package/dist/chunk-V7HUZ6UQ.js +5923 -0
- package/dist/chunk-WPUVJRIN.js +29 -0
- package/dist/chunk-XCZ3TTFK.js +22 -0
- package/dist/chunk-XSGU2Y2O.js +1611 -0
- package/dist/chunk-YNEW3L63.js +190 -0
- package/dist/chunk-YXGHPILG.js +614 -0
- package/dist/chunk-ZL4LLE2Z.js +465 -0
- package/dist/di-CcNeq9v-.d.cts +16 -0
- package/dist/di-CcNeq9v-.d.ts +16 -0
- package/dist/discovery/index.cjs +588 -0
- package/dist/discovery/index.d.cts +299 -0
- package/dist/discovery/index.d.ts +299 -0
- package/dist/discovery/index.js +49 -0
- package/dist/discovery.scanner-CUYLKlYT.d.cts +59 -0
- package/dist/discovery.scanner-CUYLKlYT.d.ts +59 -0
- package/dist/entitlement/index.cjs +805 -0
- package/dist/entitlement/index.d.cts +60 -0
- package/dist/entitlement/index.d.ts +60 -0
- package/dist/entitlement/index.js +57 -0
- package/dist/index.cjs +15918 -0
- package/dist/index.d.cts +85 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +956 -0
- package/dist/plan-resolution-CFCoUkrE.d.cts +41 -0
- package/dist/plan-resolution-CFCoUkrE.d.ts +41 -0
- package/dist/platform/index.cjs +2772 -0
- package/dist/platform/index.d.cts +118 -0
- package/dist/platform/index.d.ts +118 -0
- package/dist/platform/index.js +37 -0
- package/dist/promo/index.cjs +995 -0
- package/dist/promo/index.d.cts +121 -0
- package/dist/promo/index.d.ts +121 -0
- package/dist/promo/index.js +58 -0
- package/dist/registration/index.cjs +1687 -0
- package/dist/registration/index.d.cts +444 -0
- package/dist/registration/index.d.ts +444 -0
- package/dist/registration/index.js +82 -0
- package/dist/saas-platform.module-CgZ2omgg.d.cts +180 -0
- package/dist/saas-platform.module-DT9TnCzk.d.ts +180 -0
- package/dist/service-DX8KbGXl.d.cts +109 -0
- package/dist/service-DX8KbGXl.d.ts +109 -0
- package/dist/subscription-contract/index.cjs +471 -0
- package/dist/subscription-contract/index.d.cts +17 -0
- package/dist/subscription-contract/index.d.ts +17 -0
- package/dist/subscription-contract/index.js +21 -0
- package/dist/subscription-contract.service--cm47ZJJ.d.cts +39 -0
- package/dist/subscription-contract.service--cm47ZJJ.d.ts +39 -0
- package/dist/testing/index.cjs +3942 -0
- package/dist/testing/index.d.cts +279 -0
- package/dist/testing/index.d.ts +279 -0
- package/dist/testing/index.js +1195 -0
- package/package.json +185 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/subscription-contract/index.ts
|
|
22
|
+
var subscription_contract_exports = {};
|
|
23
|
+
__export(subscription_contract_exports, {
|
|
24
|
+
SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN: () => SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN,
|
|
25
|
+
SubscriptionContractModule: () => SubscriptionContractModule,
|
|
26
|
+
SubscriptionContractService: () => SubscriptionContractService,
|
|
27
|
+
contractLineItemToInvoiceLineItem: () => contractLineItemToInvoiceLineItem,
|
|
28
|
+
sortContractLineItemsForInvoice: () => sortContractLineItemsForInvoice,
|
|
29
|
+
subscriptionContractToInvoiceSnapshot: () => subscriptionContractToInvoiceSnapshot
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(subscription_contract_exports);
|
|
32
|
+
|
|
33
|
+
// src/subscription-contract/subscription-contract.service.ts
|
|
34
|
+
var import_common = require("@nestjs/common");
|
|
35
|
+
|
|
36
|
+
// src/checkout-offer/discount-line-items.ts
|
|
37
|
+
function appendImplicitDiscountLineItem(input) {
|
|
38
|
+
const lineItems = input.lineItems.map((item) => cloneCheckoutOfferLineItem(item));
|
|
39
|
+
const discountNet = roundMoney(input.priceBreakdown.regularNet - input.priceBreakdown.effectiveNet);
|
|
40
|
+
if (lineItems.some((item) => item.kind === "discount" && !isGeneratedDiscount(item))) {
|
|
41
|
+
return lineItems;
|
|
42
|
+
}
|
|
43
|
+
const lineItemsWithoutGeneratedDiscount = lineItems.filter((item) => !isGeneratedDiscount(item));
|
|
44
|
+
if (discountNet <= 0) {
|
|
45
|
+
return lineItemsWithoutGeneratedDiscount;
|
|
46
|
+
}
|
|
47
|
+
return [
|
|
48
|
+
...lineItemsWithoutGeneratedDiscount,
|
|
49
|
+
createDiscountLineItem(input, discountNet)
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
__name(appendImplicitDiscountLineItem, "appendImplicitDiscountLineItem");
|
|
53
|
+
function cloneCheckoutOfferLineItem(item) {
|
|
54
|
+
return {
|
|
55
|
+
...item,
|
|
56
|
+
featuresSnapshot: [
|
|
57
|
+
...item.featuresSnapshot ?? []
|
|
58
|
+
],
|
|
59
|
+
quotaEffectsSnapshot: {
|
|
60
|
+
...item.quotaEffectsSnapshot ?? {}
|
|
61
|
+
},
|
|
62
|
+
metadata: cloneRecord(item.metadata)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
__name(cloneCheckoutOfferLineItem, "cloneCheckoutOfferLineItem");
|
|
66
|
+
function createDiscountLineItem(input, discountNet) {
|
|
67
|
+
const promoCode = input.promoCodeSnapshot ?? null;
|
|
68
|
+
const firstPromotion = input.promotionSnapshots?.[0] ?? null;
|
|
69
|
+
const discountGross = roundMoney(discountNet * (1 + input.priceBreakdown.vatRate));
|
|
70
|
+
return {
|
|
71
|
+
kind: "discount",
|
|
72
|
+
sourceKey: promoCode?.code ?? firstPromotion?.id ?? "price-discount",
|
|
73
|
+
sourceVersionId: null,
|
|
74
|
+
titleSnapshot: promoCode?.label ?? firstPromotion?.label ?? "Rabatt",
|
|
75
|
+
descriptionSnapshot: promoCode ? `Promo-Code ${promoCode.code}` : null,
|
|
76
|
+
quantity: 1,
|
|
77
|
+
unit: null,
|
|
78
|
+
priceNet: -discountNet,
|
|
79
|
+
priceGross: -discountGross,
|
|
80
|
+
billingCycle: input.billingCycle,
|
|
81
|
+
featuresSnapshot: [],
|
|
82
|
+
quotaEffectsSnapshot: {},
|
|
83
|
+
metadata: {
|
|
84
|
+
generated: true,
|
|
85
|
+
source: promoCode ? "promo_code" : firstPromotion ? "promotion" : "price_breakdown",
|
|
86
|
+
discountNet,
|
|
87
|
+
discountGross,
|
|
88
|
+
promotionSnapshots: cloneArray(input.promotionSnapshots ?? []),
|
|
89
|
+
promoCodeSnapshot: cloneJsonValue(promoCode)
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
__name(createDiscountLineItem, "createDiscountLineItem");
|
|
94
|
+
function roundMoney(value) {
|
|
95
|
+
return Math.round((value + Number.EPSILON) * 100) / 100;
|
|
96
|
+
}
|
|
97
|
+
__name(roundMoney, "roundMoney");
|
|
98
|
+
function isGeneratedDiscount(item) {
|
|
99
|
+
return item.kind === "discount" && item.metadata?.generated === true;
|
|
100
|
+
}
|
|
101
|
+
__name(isGeneratedDiscount, "isGeneratedDiscount");
|
|
102
|
+
function cloneRecord(value) {
|
|
103
|
+
if (!value) return null;
|
|
104
|
+
return cloneJsonValue(value);
|
|
105
|
+
}
|
|
106
|
+
__name(cloneRecord, "cloneRecord");
|
|
107
|
+
function cloneArray(value) {
|
|
108
|
+
return cloneJsonValue(value);
|
|
109
|
+
}
|
|
110
|
+
__name(cloneArray, "cloneArray");
|
|
111
|
+
function cloneJsonValue(value) {
|
|
112
|
+
return value == null ? value : JSON.parse(JSON.stringify(value));
|
|
113
|
+
}
|
|
114
|
+
__name(cloneJsonValue, "cloneJsonValue");
|
|
115
|
+
|
|
116
|
+
// src/subscription-contract/tokens.ts
|
|
117
|
+
var SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/SubscriptionContractRepository");
|
|
118
|
+
|
|
119
|
+
// src/subscription-contract/subscription-contract.service.ts
|
|
120
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
121
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
122
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
123
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
124
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
125
|
+
}
|
|
126
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
127
|
+
function _ts_metadata(k, v) {
|
|
128
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
129
|
+
}
|
|
130
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
131
|
+
function _ts_param(paramIndex, decorator) {
|
|
132
|
+
return function(target, key) {
|
|
133
|
+
decorator(target, key, paramIndex);
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
__name(_ts_param, "_ts_param");
|
|
137
|
+
var SubscriptionContractService = class {
|
|
138
|
+
static {
|
|
139
|
+
__name(this, "SubscriptionContractService");
|
|
140
|
+
}
|
|
141
|
+
repo;
|
|
142
|
+
constructor(repo) {
|
|
143
|
+
this.repo = repo;
|
|
144
|
+
}
|
|
145
|
+
list(filter) {
|
|
146
|
+
return this.repo.list(filter);
|
|
147
|
+
}
|
|
148
|
+
async getById(contractId) {
|
|
149
|
+
const row = await this.repo.findById(contractId);
|
|
150
|
+
if (!row) {
|
|
151
|
+
throw new import_common.NotFoundException(`SubscriptionContract '${contractId}' nicht gefunden`);
|
|
152
|
+
}
|
|
153
|
+
return row;
|
|
154
|
+
}
|
|
155
|
+
async findActiveByTenantId(tenantId, asOf = /* @__PURE__ */ new Date()) {
|
|
156
|
+
return this.repo.findActiveByTenantId(tenantId, asOf);
|
|
157
|
+
}
|
|
158
|
+
async getActiveInvoiceSnapshotForTenant(tenantId, asOf = /* @__PURE__ */ new Date()) {
|
|
159
|
+
const contract = await this.repo.findActiveByTenantId(tenantId, asOf);
|
|
160
|
+
if (!contract) {
|
|
161
|
+
throw new import_common.NotFoundException(`Kein aktiver SubscriptionContract f\xFCr Tenant ${tenantId}`);
|
|
162
|
+
}
|
|
163
|
+
return subscriptionContractToInvoiceSnapshot(contract);
|
|
164
|
+
}
|
|
165
|
+
async create(data) {
|
|
166
|
+
this.assertCreateData(data);
|
|
167
|
+
return this.repo.create(this.cloneCreateData(data));
|
|
168
|
+
}
|
|
169
|
+
async terminate(contractId, data) {
|
|
170
|
+
const existing = await this.getById(contractId);
|
|
171
|
+
this.assertTerminable(existing, data);
|
|
172
|
+
return this.repo.terminate(contractId, data);
|
|
173
|
+
}
|
|
174
|
+
async replaceActiveContract(tenantId, data, terminateAt) {
|
|
175
|
+
const previous = await this.repo.findActiveByTenantId(tenantId, terminateAt);
|
|
176
|
+
if (previous) {
|
|
177
|
+
await this.terminate(previous.id, {
|
|
178
|
+
effectiveUntil: terminateAt,
|
|
179
|
+
status: "superseded"
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const next = await this.create({
|
|
183
|
+
...data,
|
|
184
|
+
tenantId,
|
|
185
|
+
effectiveFrom: data.effectiveFrom ?? terminateAt
|
|
186
|
+
});
|
|
187
|
+
return {
|
|
188
|
+
previous,
|
|
189
|
+
next
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
createDataFromOffer(offer, options) {
|
|
193
|
+
if (offer.status !== "consumed") {
|
|
194
|
+
throw new import_common.ConflictException(`CheckoutOffer '${offer.id}' muss vor Contract-Erstellung consumed sein`);
|
|
195
|
+
}
|
|
196
|
+
const lineItems = this.lineItemsFromOffer(offer);
|
|
197
|
+
return {
|
|
198
|
+
projectKey: offer.projectKey,
|
|
199
|
+
tenantId: options.tenantId,
|
|
200
|
+
status: options.status ?? "active",
|
|
201
|
+
effectiveFrom: options.effectiveFrom,
|
|
202
|
+
effectiveUntil: options.effectiveUntil ?? null,
|
|
203
|
+
originalOfferId: offer.id,
|
|
204
|
+
originalPlanVersionId: offer.planVersionId,
|
|
205
|
+
originalBundleVersionIds: [
|
|
206
|
+
...offer.bundleVersionIds ?? []
|
|
207
|
+
],
|
|
208
|
+
entitlementSnapshot: options.entitlementSnapshot ?? null,
|
|
209
|
+
priceSnapshot: this.priceSnapshotFromOffer(offer),
|
|
210
|
+
promotionSnapshots: [
|
|
211
|
+
...offer.promotionSnapshots ?? []
|
|
212
|
+
],
|
|
213
|
+
promoCodeSnapshots: offer.promoCodeSnapshot ? [
|
|
214
|
+
offer.promoCodeSnapshot
|
|
215
|
+
] : [],
|
|
216
|
+
termsSnapshot: options.termsSnapshot ?? null,
|
|
217
|
+
lineItems
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
async createFromOffer(offer, options) {
|
|
221
|
+
return this.create(this.createDataFromOffer(offer, options));
|
|
222
|
+
}
|
|
223
|
+
lineItemsFromOffer(offer) {
|
|
224
|
+
const source = offer.lineItems ?? [];
|
|
225
|
+
if (source.length === 0) {
|
|
226
|
+
throw new import_common.UnprocessableEntityException({
|
|
227
|
+
code: "CHECKOUT_OFFER_LINE_ITEMS_REQUIRED",
|
|
228
|
+
message: "Aus einem CheckoutOffer kann nur ein Contract entstehen, wenn LineItems eingefroren sind."
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return appendImplicitDiscountLineItem({
|
|
232
|
+
billingCycle: offer.billingCycle,
|
|
233
|
+
priceBreakdown: offer.priceBreakdown,
|
|
234
|
+
lineItems: source,
|
|
235
|
+
promotionSnapshots: offer.promotionSnapshots ?? [],
|
|
236
|
+
promoCodeSnapshot: offer.promoCodeSnapshot ?? null
|
|
237
|
+
}).map((item) => this.offerLineItemToContractLineItem(item));
|
|
238
|
+
}
|
|
239
|
+
offerLineItemToContractLineItem(item) {
|
|
240
|
+
return {
|
|
241
|
+
kind: item.kind,
|
|
242
|
+
sourceKey: item.sourceKey,
|
|
243
|
+
sourceVersionId: item.sourceVersionId ?? null,
|
|
244
|
+
titleSnapshot: item.titleSnapshot,
|
|
245
|
+
descriptionSnapshot: item.descriptionSnapshot ?? null,
|
|
246
|
+
quantity: item.quantity,
|
|
247
|
+
unit: item.unit ?? null,
|
|
248
|
+
priceNet: item.priceNet,
|
|
249
|
+
priceGross: item.priceGross,
|
|
250
|
+
billingCycle: item.billingCycle,
|
|
251
|
+
minimumTermUntil: this.parseOptionalDate(item.minimumTermUntil, "lineItems.minimumTermUntil"),
|
|
252
|
+
featuresSnapshot: [
|
|
253
|
+
...item.featuresSnapshot ?? []
|
|
254
|
+
],
|
|
255
|
+
quotaEffectsSnapshot: {
|
|
256
|
+
...item.quotaEffectsSnapshot ?? {}
|
|
257
|
+
},
|
|
258
|
+
metadata: item.metadata ?? null
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
parseOptionalDate(value, field) {
|
|
262
|
+
if (value === null || value === void 0) return null;
|
|
263
|
+
const date = value instanceof Date ? new Date(value) : new Date(value);
|
|
264
|
+
if (Number.isNaN(date.getTime())) {
|
|
265
|
+
throw new import_common.UnprocessableEntityException({
|
|
266
|
+
code: "SUBSCRIPTION_CONTRACT_INVALID_DATE",
|
|
267
|
+
message: `${field} muss ein g\xFCltiges Datum sein.`
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
return date;
|
|
271
|
+
}
|
|
272
|
+
priceSnapshotFromOffer(offer) {
|
|
273
|
+
const breakdown = offer.priceBreakdown;
|
|
274
|
+
return {
|
|
275
|
+
currency: breakdown.currency,
|
|
276
|
+
billingCycle: breakdown.billingCycle,
|
|
277
|
+
subtotalNet: breakdown.regularNet,
|
|
278
|
+
discountNet: Math.max(0, breakdown.regularNet - breakdown.effectiveNet),
|
|
279
|
+
totalNet: breakdown.effectiveNet,
|
|
280
|
+
vatRate: breakdown.vatRate,
|
|
281
|
+
totalGross: breakdown.effectiveGross
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
assertCreateData(data) {
|
|
285
|
+
if (data.lineItems.length === 0) {
|
|
286
|
+
throw new import_common.UnprocessableEntityException({
|
|
287
|
+
code: "SUBSCRIPTION_CONTRACT_LINE_ITEMS_REQUIRED",
|
|
288
|
+
message: "SubscriptionContract ben\xF6tigt mindestens eine LineItem."
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
if (data.effectiveUntil && data.effectiveUntil <= data.effectiveFrom) {
|
|
292
|
+
throw new import_common.UnprocessableEntityException({
|
|
293
|
+
code: "SUBSCRIPTION_CONTRACT_INVALID_WINDOW",
|
|
294
|
+
message: "effectiveUntil muss nach effectiveFrom liegen."
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
const planLineItems = data.lineItems.filter((item) => item.kind === "plan");
|
|
298
|
+
if (planLineItems.length !== 1) {
|
|
299
|
+
throw new import_common.UnprocessableEntityException({
|
|
300
|
+
code: "SUBSCRIPTION_CONTRACT_PLAN_LINE_ITEM_REQUIRED",
|
|
301
|
+
message: "SubscriptionContract ben\xF6tigt genau eine Plan-Grundposition."
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
assertTerminable(existing, data) {
|
|
306
|
+
if (existing.status === "terminated" || existing.status === "superseded") {
|
|
307
|
+
throw new import_common.ConflictException(`SubscriptionContract '${existing.id}' ist bereits geschlossen`);
|
|
308
|
+
}
|
|
309
|
+
if (data.effectiveUntil <= existing.effectiveFrom) {
|
|
310
|
+
throw new import_common.UnprocessableEntityException({
|
|
311
|
+
code: "SUBSCRIPTION_CONTRACT_TERMINATION_BEFORE_START",
|
|
312
|
+
message: "effectiveUntil muss nach effectiveFrom des Contracts liegen."
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
cloneCreateData(data) {
|
|
317
|
+
return {
|
|
318
|
+
...data,
|
|
319
|
+
originalBundleVersionIds: [
|
|
320
|
+
...data.originalBundleVersionIds ?? []
|
|
321
|
+
],
|
|
322
|
+
promotionSnapshots: [
|
|
323
|
+
...data.promotionSnapshots ?? []
|
|
324
|
+
],
|
|
325
|
+
promoCodeSnapshots: [
|
|
326
|
+
...data.promoCodeSnapshots ?? []
|
|
327
|
+
],
|
|
328
|
+
termsSnapshot: data.termsSnapshot ? {
|
|
329
|
+
...data.termsSnapshot
|
|
330
|
+
} : null,
|
|
331
|
+
lineItems: data.lineItems.map((item) => this.cloneLineItemData(item))
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
cloneLineItemData(item) {
|
|
335
|
+
return {
|
|
336
|
+
...item,
|
|
337
|
+
featuresSnapshot: [
|
|
338
|
+
...item.featuresSnapshot
|
|
339
|
+
],
|
|
340
|
+
quotaEffectsSnapshot: {
|
|
341
|
+
...item.quotaEffectsSnapshot
|
|
342
|
+
},
|
|
343
|
+
metadata: item.metadata ? {
|
|
344
|
+
...item.metadata
|
|
345
|
+
} : null
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
SubscriptionContractService = _ts_decorate([
|
|
350
|
+
(0, import_common.Injectable)(),
|
|
351
|
+
_ts_param(0, (0, import_common.Inject)(SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN)),
|
|
352
|
+
_ts_metadata("design:type", Function),
|
|
353
|
+
_ts_metadata("design:paramtypes", [
|
|
354
|
+
typeof SubscriptionContractRepository === "undefined" ? Object : SubscriptionContractRepository
|
|
355
|
+
])
|
|
356
|
+
], SubscriptionContractService);
|
|
357
|
+
function contractLineItemToInvoiceLineItem(item) {
|
|
358
|
+
return {
|
|
359
|
+
sourceContractLineItemId: item.id,
|
|
360
|
+
sourceKey: item.sourceKey,
|
|
361
|
+
sourceVersionId: item.sourceVersionId,
|
|
362
|
+
kind: item.kind,
|
|
363
|
+
title: item.titleSnapshot,
|
|
364
|
+
description: item.descriptionSnapshot,
|
|
365
|
+
quantity: item.quantity,
|
|
366
|
+
unit: item.unit,
|
|
367
|
+
priceNet: item.priceNet,
|
|
368
|
+
priceGross: item.priceGross,
|
|
369
|
+
billingCycle: item.billingCycle,
|
|
370
|
+
minimumTermUntil: item.minimumTermUntil,
|
|
371
|
+
metadata: item.metadata
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
__name(contractLineItemToInvoiceLineItem, "contractLineItemToInvoiceLineItem");
|
|
375
|
+
function subscriptionContractToInvoiceSnapshot(contract) {
|
|
376
|
+
return {
|
|
377
|
+
contractId: contract.id,
|
|
378
|
+
projectKey: contract.projectKey,
|
|
379
|
+
tenantId: contract.tenantId,
|
|
380
|
+
originalOfferId: contract.originalOfferId,
|
|
381
|
+
currency: contract.priceSnapshot.currency,
|
|
382
|
+
billingCycle: contract.priceSnapshot.billingCycle,
|
|
383
|
+
effectiveFrom: contract.effectiveFrom,
|
|
384
|
+
effectiveUntil: contract.effectiveUntil,
|
|
385
|
+
subtotalNet: contract.priceSnapshot.subtotalNet,
|
|
386
|
+
discountNet: contract.priceSnapshot.discountNet,
|
|
387
|
+
totalNet: contract.priceSnapshot.totalNet,
|
|
388
|
+
vatRate: contract.priceSnapshot.vatRate,
|
|
389
|
+
totalGross: contract.priceSnapshot.totalGross,
|
|
390
|
+
lineItems: sortContractLineItemsForInvoice(contract.lineItems).map(contractLineItemToInvoiceLineItem)
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
__name(subscriptionContractToInvoiceSnapshot, "subscriptionContractToInvoiceSnapshot");
|
|
394
|
+
function sortContractLineItemsForInvoice(lineItems) {
|
|
395
|
+
return [
|
|
396
|
+
...lineItems
|
|
397
|
+
].sort((a, b) => lineItemKindPriority(a.kind) - lineItemKindPriority(b.kind) || a.createdAt.getTime() - b.createdAt.getTime() || a.id.localeCompare(b.id));
|
|
398
|
+
}
|
|
399
|
+
__name(sortContractLineItemsForInvoice, "sortContractLineItemsForInvoice");
|
|
400
|
+
function lineItemKindPriority(kind) {
|
|
401
|
+
switch (kind) {
|
|
402
|
+
case "plan":
|
|
403
|
+
return 10;
|
|
404
|
+
case "bundle":
|
|
405
|
+
return 20;
|
|
406
|
+
case "discount":
|
|
407
|
+
return 90;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
__name(lineItemKindPriority, "lineItemKindPriority");
|
|
411
|
+
|
|
412
|
+
// src/subscription-contract/subscription-contract.module.ts
|
|
413
|
+
var import_common2 = require("@nestjs/common");
|
|
414
|
+
|
|
415
|
+
// src/core/di.ts
|
|
416
|
+
function asProvider(token, impl) {
|
|
417
|
+
if (typeof impl === "object" && impl !== null && "useFactory" in impl && typeof impl.useFactory === "function") {
|
|
418
|
+
const factory = impl;
|
|
419
|
+
return {
|
|
420
|
+
provide: token,
|
|
421
|
+
useFactory: factory.useFactory,
|
|
422
|
+
inject: factory.inject
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
provide: token,
|
|
427
|
+
useValue: impl
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
__name(asProvider, "asProvider");
|
|
431
|
+
|
|
432
|
+
// src/subscription-contract/subscription-contract.module.ts
|
|
433
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
434
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
435
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
436
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
437
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
438
|
+
}
|
|
439
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
440
|
+
var SubscriptionContractModule = class _SubscriptionContractModule {
|
|
441
|
+
static {
|
|
442
|
+
__name(this, "SubscriptionContractModule");
|
|
443
|
+
}
|
|
444
|
+
static forRoot(options) {
|
|
445
|
+
return {
|
|
446
|
+
module: _SubscriptionContractModule,
|
|
447
|
+
global: options.global ?? false,
|
|
448
|
+
providers: [
|
|
449
|
+
asProvider(SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN, options.subscriptionContractRepository),
|
|
450
|
+
SubscriptionContractService,
|
|
451
|
+
...options.extraProviders ?? []
|
|
452
|
+
],
|
|
453
|
+
exports: [
|
|
454
|
+
SubscriptionContractService,
|
|
455
|
+
SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN
|
|
456
|
+
]
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
SubscriptionContractModule = _ts_decorate2([
|
|
461
|
+
(0, import_common2.Module)({})
|
|
462
|
+
], SubscriptionContractModule);
|
|
463
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
464
|
+
0 && (module.exports = {
|
|
465
|
+
SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN,
|
|
466
|
+
SubscriptionContractModule,
|
|
467
|
+
SubscriptionContractService,
|
|
468
|
+
contractLineItemToInvoiceLineItem,
|
|
469
|
+
sortContractLineItemsForInvoice,
|
|
470
|
+
subscriptionContractToInvoiceSnapshot
|
|
471
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { C as CreateContractFromOfferOptions, S as SubscriptionContractService, c as contractLineItemToInvoiceLineItem, s as sortContractLineItemsForInvoice, a as subscriptionContractToInvoiceSnapshot } from '../subscription-contract.service--cm47ZJJ.cjs';
|
|
2
|
+
import { Provider, DynamicModule } from '@nestjs/common';
|
|
3
|
+
import { SubscriptionContractRepository } from '@saasicat/types';
|
|
4
|
+
import { P as ProviderSpec } from '../di-CcNeq9v-.cjs';
|
|
5
|
+
|
|
6
|
+
interface SubscriptionContractModuleOptions {
|
|
7
|
+
subscriptionContractRepository: ProviderSpec<SubscriptionContractRepository>;
|
|
8
|
+
extraProviders?: Provider[];
|
|
9
|
+
global?: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare class SubscriptionContractModule {
|
|
12
|
+
static forRoot(options: SubscriptionContractModuleOptions): DynamicModule;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare const SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN: unique symbol;
|
|
16
|
+
|
|
17
|
+
export { SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN, SubscriptionContractModule, type SubscriptionContractModuleOptions };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { C as CreateContractFromOfferOptions, S as SubscriptionContractService, c as contractLineItemToInvoiceLineItem, s as sortContractLineItemsForInvoice, a as subscriptionContractToInvoiceSnapshot } from '../subscription-contract.service--cm47ZJJ.js';
|
|
2
|
+
import { Provider, DynamicModule } from '@nestjs/common';
|
|
3
|
+
import { SubscriptionContractRepository } from '@saasicat/types';
|
|
4
|
+
import { P as ProviderSpec } from '../di-CcNeq9v-.js';
|
|
5
|
+
|
|
6
|
+
interface SubscriptionContractModuleOptions {
|
|
7
|
+
subscriptionContractRepository: ProviderSpec<SubscriptionContractRepository>;
|
|
8
|
+
extraProviders?: Provider[];
|
|
9
|
+
global?: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare class SubscriptionContractModule {
|
|
12
|
+
static forRoot(options: SubscriptionContractModuleOptions): DynamicModule;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare const SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN: unique symbol;
|
|
16
|
+
|
|
17
|
+
export { SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN, SubscriptionContractModule, type SubscriptionContractModuleOptions };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SubscriptionContractModule,
|
|
3
|
+
SubscriptionContractService,
|
|
4
|
+
contractLineItemToInvoiceLineItem,
|
|
5
|
+
sortContractLineItemsForInvoice,
|
|
6
|
+
subscriptionContractToInvoiceSnapshot
|
|
7
|
+
} from "../chunk-2PNX2QL2.js";
|
|
8
|
+
import "../chunk-MDIZUVIK.js";
|
|
9
|
+
import {
|
|
10
|
+
SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN
|
|
11
|
+
} from "../chunk-NYLON2VC.js";
|
|
12
|
+
import "../chunk-SABTXESR.js";
|
|
13
|
+
import "../chunk-SHUYVCID.js";
|
|
14
|
+
export {
|
|
15
|
+
SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN,
|
|
16
|
+
SubscriptionContractModule,
|
|
17
|
+
SubscriptionContractService,
|
|
18
|
+
contractLineItemToInvoiceLineItem,
|
|
19
|
+
sortContractLineItemsForInvoice,
|
|
20
|
+
subscriptionContractToInvoiceSnapshot
|
|
21
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { SubscriptionContractRepository, SubscriptionContractRecord, SubscriptionContractInvoiceSnapshot, CreateSubscriptionContractData, TerminateSubscriptionContractData, CheckoutOfferRow, ContractLineItemRecord, InvoiceLineItemSnapshot } from '@saasicat/types';
|
|
2
|
+
|
|
3
|
+
interface CreateContractFromOfferOptions {
|
|
4
|
+
tenantId: string;
|
|
5
|
+
effectiveFrom: Date;
|
|
6
|
+
effectiveUntil?: Date | null;
|
|
7
|
+
status?: CreateSubscriptionContractData['status'];
|
|
8
|
+
entitlementSnapshot?: CreateSubscriptionContractData['entitlementSnapshot'];
|
|
9
|
+
termsSnapshot?: Record<string, unknown> | null;
|
|
10
|
+
}
|
|
11
|
+
declare class SubscriptionContractService {
|
|
12
|
+
private readonly repo;
|
|
13
|
+
constructor(repo: SubscriptionContractRepository);
|
|
14
|
+
list(filter: Parameters<SubscriptionContractRepository['list']>[0]): Promise<SubscriptionContractRecord[]>;
|
|
15
|
+
getById(contractId: string): Promise<SubscriptionContractRecord>;
|
|
16
|
+
findActiveByTenantId(tenantId: string, asOf?: Date): Promise<SubscriptionContractRecord | null>;
|
|
17
|
+
getActiveInvoiceSnapshotForTenant(tenantId: string, asOf?: Date): Promise<SubscriptionContractInvoiceSnapshot>;
|
|
18
|
+
create(data: CreateSubscriptionContractData): Promise<SubscriptionContractRecord>;
|
|
19
|
+
terminate(contractId: string, data: TerminateSubscriptionContractData): Promise<SubscriptionContractRecord>;
|
|
20
|
+
replaceActiveContract(tenantId: string, data: CreateSubscriptionContractData, terminateAt: Date): Promise<{
|
|
21
|
+
previous: SubscriptionContractRecord | null;
|
|
22
|
+
next: SubscriptionContractRecord;
|
|
23
|
+
}>;
|
|
24
|
+
createDataFromOffer(offer: CheckoutOfferRow, options: CreateContractFromOfferOptions): CreateSubscriptionContractData;
|
|
25
|
+
createFromOffer(offer: CheckoutOfferRow, options: CreateContractFromOfferOptions): Promise<SubscriptionContractRecord>;
|
|
26
|
+
private lineItemsFromOffer;
|
|
27
|
+
private offerLineItemToContractLineItem;
|
|
28
|
+
private parseOptionalDate;
|
|
29
|
+
private priceSnapshotFromOffer;
|
|
30
|
+
private assertCreateData;
|
|
31
|
+
private assertTerminable;
|
|
32
|
+
private cloneCreateData;
|
|
33
|
+
private cloneLineItemData;
|
|
34
|
+
}
|
|
35
|
+
declare function contractLineItemToInvoiceLineItem(item: ContractLineItemRecord): InvoiceLineItemSnapshot;
|
|
36
|
+
declare function subscriptionContractToInvoiceSnapshot(contract: SubscriptionContractRecord): SubscriptionContractInvoiceSnapshot;
|
|
37
|
+
declare function sortContractLineItemsForInvoice(lineItems: readonly ContractLineItemRecord[]): ContractLineItemRecord[];
|
|
38
|
+
|
|
39
|
+
export { type CreateContractFromOfferOptions as C, SubscriptionContractService as S, subscriptionContractToInvoiceSnapshot as a, contractLineItemToInvoiceLineItem as c, sortContractLineItemsForInvoice as s };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { SubscriptionContractRepository, SubscriptionContractRecord, SubscriptionContractInvoiceSnapshot, CreateSubscriptionContractData, TerminateSubscriptionContractData, CheckoutOfferRow, ContractLineItemRecord, InvoiceLineItemSnapshot } from '@saasicat/types';
|
|
2
|
+
|
|
3
|
+
interface CreateContractFromOfferOptions {
|
|
4
|
+
tenantId: string;
|
|
5
|
+
effectiveFrom: Date;
|
|
6
|
+
effectiveUntil?: Date | null;
|
|
7
|
+
status?: CreateSubscriptionContractData['status'];
|
|
8
|
+
entitlementSnapshot?: CreateSubscriptionContractData['entitlementSnapshot'];
|
|
9
|
+
termsSnapshot?: Record<string, unknown> | null;
|
|
10
|
+
}
|
|
11
|
+
declare class SubscriptionContractService {
|
|
12
|
+
private readonly repo;
|
|
13
|
+
constructor(repo: SubscriptionContractRepository);
|
|
14
|
+
list(filter: Parameters<SubscriptionContractRepository['list']>[0]): Promise<SubscriptionContractRecord[]>;
|
|
15
|
+
getById(contractId: string): Promise<SubscriptionContractRecord>;
|
|
16
|
+
findActiveByTenantId(tenantId: string, asOf?: Date): Promise<SubscriptionContractRecord | null>;
|
|
17
|
+
getActiveInvoiceSnapshotForTenant(tenantId: string, asOf?: Date): Promise<SubscriptionContractInvoiceSnapshot>;
|
|
18
|
+
create(data: CreateSubscriptionContractData): Promise<SubscriptionContractRecord>;
|
|
19
|
+
terminate(contractId: string, data: TerminateSubscriptionContractData): Promise<SubscriptionContractRecord>;
|
|
20
|
+
replaceActiveContract(tenantId: string, data: CreateSubscriptionContractData, terminateAt: Date): Promise<{
|
|
21
|
+
previous: SubscriptionContractRecord | null;
|
|
22
|
+
next: SubscriptionContractRecord;
|
|
23
|
+
}>;
|
|
24
|
+
createDataFromOffer(offer: CheckoutOfferRow, options: CreateContractFromOfferOptions): CreateSubscriptionContractData;
|
|
25
|
+
createFromOffer(offer: CheckoutOfferRow, options: CreateContractFromOfferOptions): Promise<SubscriptionContractRecord>;
|
|
26
|
+
private lineItemsFromOffer;
|
|
27
|
+
private offerLineItemToContractLineItem;
|
|
28
|
+
private parseOptionalDate;
|
|
29
|
+
private priceSnapshotFromOffer;
|
|
30
|
+
private assertCreateData;
|
|
31
|
+
private assertTerminable;
|
|
32
|
+
private cloneCreateData;
|
|
33
|
+
private cloneLineItemData;
|
|
34
|
+
}
|
|
35
|
+
declare function contractLineItemToInvoiceLineItem(item: ContractLineItemRecord): InvoiceLineItemSnapshot;
|
|
36
|
+
declare function subscriptionContractToInvoiceSnapshot(contract: SubscriptionContractRecord): SubscriptionContractInvoiceSnapshot;
|
|
37
|
+
declare function sortContractLineItemsForInvoice(lineItems: readonly ContractLineItemRecord[]): ContractLineItemRecord[];
|
|
38
|
+
|
|
39
|
+
export { type CreateContractFromOfferOptions as C, SubscriptionContractService as S, subscriptionContractToInvoiceSnapshot as a, contractLineItemToInvoiceLineItem as c, sortContractLineItemsForInvoice as s };
|