@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,120 @@
|
|
|
1
|
+
import { CheckoutOfferRepository, BundleRepository, PlanRepository, CatalogEntryRepository, CheckoutOfferFilter, CheckoutOfferRow, CreateCheckoutOfferData, UpdateCheckoutOfferData, CheckoutOfferPriceBreakdown, CheckoutOfferLineItem, CheckoutOfferPromotionSnapshot, CheckoutOfferPromoCodeSnapshot } from '@saasicat/types';
|
|
2
|
+
import { Type, CanActivate, DynamicModule, ForwardReference, Provider } from '@nestjs/common';
|
|
3
|
+
import { P as ProviderSpec } from '../di-CcNeq9v-.cjs';
|
|
4
|
+
|
|
5
|
+
declare class CheckoutOfferService {
|
|
6
|
+
private readonly repo;
|
|
7
|
+
private readonly bundles;
|
|
8
|
+
private readonly plans;
|
|
9
|
+
private readonly catalogEntries;
|
|
10
|
+
constructor(repo: CheckoutOfferRepository, bundles?: BundleRepository | null, plans?: PlanRepository | null, catalogEntries?: CatalogEntryRepository | null);
|
|
11
|
+
list(filter: CheckoutOfferFilter): Promise<CheckoutOfferRow[]>;
|
|
12
|
+
getById(id: string): Promise<CheckoutOfferRow>;
|
|
13
|
+
create(data: CreateCheckoutOfferData): Promise<CheckoutOfferRow>;
|
|
14
|
+
/** Customization in onboarding — only while the offer is `open`. */
|
|
15
|
+
update(id: string, data: UpdateCheckoutOfferData): Promise<CheckoutOfferRow>;
|
|
16
|
+
/**
|
|
17
|
+
* Freezes the offer (`status = 'consumed'`). Returns the final
|
|
18
|
+
* snapshot — the caller (registration/billing) writes it
|
|
19
|
+
* as `Subscription.packageSnapshot`.
|
|
20
|
+
*/
|
|
21
|
+
consume(id: string): Promise<CheckoutOfferRow>;
|
|
22
|
+
/**
|
|
23
|
+
* #35 P6 — server-side requires validation: the dependencies of all
|
|
24
|
+
* features (plan ∪ selected bundles) must be covered within the
|
|
25
|
+
* selection, otherwise an offer would be created whose features cannot
|
|
26
|
+
* work at the tenant (an app-specific validateModuleDependencies check is
|
|
27
|
+
* thereby replaced on the platform side). The requires source are the
|
|
28
|
+
* curated FeatureCatalogEntries; without CatalogEntryRepository it is
|
|
29
|
+
* skipped (graceful — no requires data available).
|
|
30
|
+
*/
|
|
31
|
+
private assertFeatureRequiresSatisfied;
|
|
32
|
+
/**
|
|
33
|
+
* Plan features preferably from the server SSOT (PlanRepository); fallback
|
|
34
|
+
* is the frozen featuresSnapshot of the plan LineItem (adapter without
|
|
35
|
+
* PlanRepository wiring).
|
|
36
|
+
*/
|
|
37
|
+
private resolvePlanFeatures;
|
|
38
|
+
/** Bundle features from the BundleVersions; fallback featuresSnapshot. */
|
|
39
|
+
private resolveBundleFeatures;
|
|
40
|
+
private assertBundleVersionsStillBookable;
|
|
41
|
+
private normalizeCreateData;
|
|
42
|
+
private normalizeUpdateData;
|
|
43
|
+
private resolveLineItems;
|
|
44
|
+
private defaultPlanLineItem;
|
|
45
|
+
private assertOpen;
|
|
46
|
+
private isExpired;
|
|
47
|
+
private dateIsAfterNow;
|
|
48
|
+
private isValidUntilExpired;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
declare function buildCheckoutOfferController(guards: Array<Type<CanActivate>>): Type;
|
|
52
|
+
|
|
53
|
+
interface CheckoutOfferControllerConfig {
|
|
54
|
+
/** Class-level guards; `[]` for auth-free public endpoints. */
|
|
55
|
+
guards: Array<Type<CanActivate>>;
|
|
56
|
+
}
|
|
57
|
+
interface CheckoutOfferModuleOptions {
|
|
58
|
+
checkoutOfferRepository: ProviderSpec<CheckoutOfferRepository>;
|
|
59
|
+
/**
|
|
60
|
+
* Optional for V3 revalidation on consume: if set, the service checks
|
|
61
|
+
* whether referenced bundle versions are still bookable. Also provides
|
|
62
|
+
* the bundle features for the requires validation (#35 P6).
|
|
63
|
+
*/
|
|
64
|
+
bundleRepository?: ProviderSpec<BundleRepository>;
|
|
65
|
+
/**
|
|
66
|
+
* Optional for the requires validation (#35 P6): plan features of the
|
|
67
|
+
* chosen plan version. Without wiring, falls back to the featuresSnapshot
|
|
68
|
+
* of the plan line item.
|
|
69
|
+
*/
|
|
70
|
+
planRepository?: ProviderSpec<PlanRepository>;
|
|
71
|
+
/**
|
|
72
|
+
* Optional for the requires validation (#35 P6): requires source =
|
|
73
|
+
* curated FeatureCatalogEntries. Without wiring, the validation is
|
|
74
|
+
* skipped (graceful).
|
|
75
|
+
*/
|
|
76
|
+
catalogEntryRepository?: ProviderSpec<CatalogEntryRepository>;
|
|
77
|
+
/** Controller mount for `/public/checkout-offer`. Omitted = service only. */
|
|
78
|
+
controller?: CheckoutOfferControllerConfig;
|
|
79
|
+
imports?: Array<Type<unknown> | DynamicModule | Promise<DynamicModule> | ForwardReference>;
|
|
80
|
+
extraProviders?: Provider[];
|
|
81
|
+
global?: boolean;
|
|
82
|
+
}
|
|
83
|
+
declare class CheckoutOfferModule {
|
|
84
|
+
static forRoot(options: CheckoutOfferModuleOptions): DynamicModule;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Repository for `checkout_offers`. */
|
|
88
|
+
declare const CHECKOUT_OFFER_REPOSITORY_TOKEN: unique symbol;
|
|
89
|
+
|
|
90
|
+
declare class CreateCheckoutOfferDto {
|
|
91
|
+
projectKey: string;
|
|
92
|
+
planKey: string;
|
|
93
|
+
planVersionId?: string | null;
|
|
94
|
+
billingCycle: 'monthly' | 'yearly';
|
|
95
|
+
promotionId?: string | null;
|
|
96
|
+
promoCode?: string | null;
|
|
97
|
+
bundles?: string[];
|
|
98
|
+
bundleVersionIds?: string[];
|
|
99
|
+
priceBreakdown: CheckoutOfferPriceBreakdown;
|
|
100
|
+
lineItems?: CheckoutOfferLineItem[];
|
|
101
|
+
promotionSnapshots?: CheckoutOfferPromotionSnapshot[];
|
|
102
|
+
promoCodeSnapshot?: CheckoutOfferPromoCodeSnapshot | null;
|
|
103
|
+
locale?: string;
|
|
104
|
+
validUntil?: string | null;
|
|
105
|
+
}
|
|
106
|
+
declare class UpdateCheckoutOfferDto {
|
|
107
|
+
billingCycle?: 'monthly' | 'yearly';
|
|
108
|
+
promotionId?: string | null;
|
|
109
|
+
promoCode?: string | null;
|
|
110
|
+
bundles?: string[];
|
|
111
|
+
bundleVersionIds?: string[];
|
|
112
|
+
priceBreakdown?: CheckoutOfferPriceBreakdown;
|
|
113
|
+
lineItems?: CheckoutOfferLineItem[];
|
|
114
|
+
promotionSnapshots?: CheckoutOfferPromotionSnapshot[];
|
|
115
|
+
promoCodeSnapshot?: CheckoutOfferPromoCodeSnapshot | null;
|
|
116
|
+
locale?: string;
|
|
117
|
+
validUntil?: string | null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { CHECKOUT_OFFER_REPOSITORY_TOKEN, type CheckoutOfferControllerConfig, CheckoutOfferModule, type CheckoutOfferModuleOptions, CheckoutOfferService, CreateCheckoutOfferDto, UpdateCheckoutOfferDto, buildCheckoutOfferController };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { CheckoutOfferRepository, BundleRepository, PlanRepository, CatalogEntryRepository, CheckoutOfferFilter, CheckoutOfferRow, CreateCheckoutOfferData, UpdateCheckoutOfferData, CheckoutOfferPriceBreakdown, CheckoutOfferLineItem, CheckoutOfferPromotionSnapshot, CheckoutOfferPromoCodeSnapshot } from '@saasicat/types';
|
|
2
|
+
import { Type, CanActivate, DynamicModule, ForwardReference, Provider } from '@nestjs/common';
|
|
3
|
+
import { P as ProviderSpec } from '../di-CcNeq9v-.js';
|
|
4
|
+
|
|
5
|
+
declare class CheckoutOfferService {
|
|
6
|
+
private readonly repo;
|
|
7
|
+
private readonly bundles;
|
|
8
|
+
private readonly plans;
|
|
9
|
+
private readonly catalogEntries;
|
|
10
|
+
constructor(repo: CheckoutOfferRepository, bundles?: BundleRepository | null, plans?: PlanRepository | null, catalogEntries?: CatalogEntryRepository | null);
|
|
11
|
+
list(filter: CheckoutOfferFilter): Promise<CheckoutOfferRow[]>;
|
|
12
|
+
getById(id: string): Promise<CheckoutOfferRow>;
|
|
13
|
+
create(data: CreateCheckoutOfferData): Promise<CheckoutOfferRow>;
|
|
14
|
+
/** Customization in onboarding — only while the offer is `open`. */
|
|
15
|
+
update(id: string, data: UpdateCheckoutOfferData): Promise<CheckoutOfferRow>;
|
|
16
|
+
/**
|
|
17
|
+
* Freezes the offer (`status = 'consumed'`). Returns the final
|
|
18
|
+
* snapshot — the caller (registration/billing) writes it
|
|
19
|
+
* as `Subscription.packageSnapshot`.
|
|
20
|
+
*/
|
|
21
|
+
consume(id: string): Promise<CheckoutOfferRow>;
|
|
22
|
+
/**
|
|
23
|
+
* #35 P6 — server-side requires validation: the dependencies of all
|
|
24
|
+
* features (plan ∪ selected bundles) must be covered within the
|
|
25
|
+
* selection, otherwise an offer would be created whose features cannot
|
|
26
|
+
* work at the tenant (an app-specific validateModuleDependencies check is
|
|
27
|
+
* thereby replaced on the platform side). The requires source are the
|
|
28
|
+
* curated FeatureCatalogEntries; without CatalogEntryRepository it is
|
|
29
|
+
* skipped (graceful — no requires data available).
|
|
30
|
+
*/
|
|
31
|
+
private assertFeatureRequiresSatisfied;
|
|
32
|
+
/**
|
|
33
|
+
* Plan features preferably from the server SSOT (PlanRepository); fallback
|
|
34
|
+
* is the frozen featuresSnapshot of the plan LineItem (adapter without
|
|
35
|
+
* PlanRepository wiring).
|
|
36
|
+
*/
|
|
37
|
+
private resolvePlanFeatures;
|
|
38
|
+
/** Bundle features from the BundleVersions; fallback featuresSnapshot. */
|
|
39
|
+
private resolveBundleFeatures;
|
|
40
|
+
private assertBundleVersionsStillBookable;
|
|
41
|
+
private normalizeCreateData;
|
|
42
|
+
private normalizeUpdateData;
|
|
43
|
+
private resolveLineItems;
|
|
44
|
+
private defaultPlanLineItem;
|
|
45
|
+
private assertOpen;
|
|
46
|
+
private isExpired;
|
|
47
|
+
private dateIsAfterNow;
|
|
48
|
+
private isValidUntilExpired;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
declare function buildCheckoutOfferController(guards: Array<Type<CanActivate>>): Type;
|
|
52
|
+
|
|
53
|
+
interface CheckoutOfferControllerConfig {
|
|
54
|
+
/** Class-level guards; `[]` for auth-free public endpoints. */
|
|
55
|
+
guards: Array<Type<CanActivate>>;
|
|
56
|
+
}
|
|
57
|
+
interface CheckoutOfferModuleOptions {
|
|
58
|
+
checkoutOfferRepository: ProviderSpec<CheckoutOfferRepository>;
|
|
59
|
+
/**
|
|
60
|
+
* Optional for V3 revalidation on consume: if set, the service checks
|
|
61
|
+
* whether referenced bundle versions are still bookable. Also provides
|
|
62
|
+
* the bundle features for the requires validation (#35 P6).
|
|
63
|
+
*/
|
|
64
|
+
bundleRepository?: ProviderSpec<BundleRepository>;
|
|
65
|
+
/**
|
|
66
|
+
* Optional for the requires validation (#35 P6): plan features of the
|
|
67
|
+
* chosen plan version. Without wiring, falls back to the featuresSnapshot
|
|
68
|
+
* of the plan line item.
|
|
69
|
+
*/
|
|
70
|
+
planRepository?: ProviderSpec<PlanRepository>;
|
|
71
|
+
/**
|
|
72
|
+
* Optional for the requires validation (#35 P6): requires source =
|
|
73
|
+
* curated FeatureCatalogEntries. Without wiring, the validation is
|
|
74
|
+
* skipped (graceful).
|
|
75
|
+
*/
|
|
76
|
+
catalogEntryRepository?: ProviderSpec<CatalogEntryRepository>;
|
|
77
|
+
/** Controller mount for `/public/checkout-offer`. Omitted = service only. */
|
|
78
|
+
controller?: CheckoutOfferControllerConfig;
|
|
79
|
+
imports?: Array<Type<unknown> | DynamicModule | Promise<DynamicModule> | ForwardReference>;
|
|
80
|
+
extraProviders?: Provider[];
|
|
81
|
+
global?: boolean;
|
|
82
|
+
}
|
|
83
|
+
declare class CheckoutOfferModule {
|
|
84
|
+
static forRoot(options: CheckoutOfferModuleOptions): DynamicModule;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Repository for `checkout_offers`. */
|
|
88
|
+
declare const CHECKOUT_OFFER_REPOSITORY_TOKEN: unique symbol;
|
|
89
|
+
|
|
90
|
+
declare class CreateCheckoutOfferDto {
|
|
91
|
+
projectKey: string;
|
|
92
|
+
planKey: string;
|
|
93
|
+
planVersionId?: string | null;
|
|
94
|
+
billingCycle: 'monthly' | 'yearly';
|
|
95
|
+
promotionId?: string | null;
|
|
96
|
+
promoCode?: string | null;
|
|
97
|
+
bundles?: string[];
|
|
98
|
+
bundleVersionIds?: string[];
|
|
99
|
+
priceBreakdown: CheckoutOfferPriceBreakdown;
|
|
100
|
+
lineItems?: CheckoutOfferLineItem[];
|
|
101
|
+
promotionSnapshots?: CheckoutOfferPromotionSnapshot[];
|
|
102
|
+
promoCodeSnapshot?: CheckoutOfferPromoCodeSnapshot | null;
|
|
103
|
+
locale?: string;
|
|
104
|
+
validUntil?: string | null;
|
|
105
|
+
}
|
|
106
|
+
declare class UpdateCheckoutOfferDto {
|
|
107
|
+
billingCycle?: 'monthly' | 'yearly';
|
|
108
|
+
promotionId?: string | null;
|
|
109
|
+
promoCode?: string | null;
|
|
110
|
+
bundles?: string[];
|
|
111
|
+
bundleVersionIds?: string[];
|
|
112
|
+
priceBreakdown?: CheckoutOfferPriceBreakdown;
|
|
113
|
+
lineItems?: CheckoutOfferLineItem[];
|
|
114
|
+
promotionSnapshots?: CheckoutOfferPromotionSnapshot[];
|
|
115
|
+
promoCodeSnapshot?: CheckoutOfferPromoCodeSnapshot | null;
|
|
116
|
+
locale?: string;
|
|
117
|
+
validUntil?: string | null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { CHECKOUT_OFFER_REPOSITORY_TOKEN, type CheckoutOfferControllerConfig, CheckoutOfferModule, type CheckoutOfferModuleOptions, CheckoutOfferService, CreateCheckoutOfferDto, UpdateCheckoutOfferDto, buildCheckoutOfferController };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CHECKOUT_OFFER_REPOSITORY_TOKEN,
|
|
3
|
+
CheckoutOfferModule,
|
|
4
|
+
CheckoutOfferService,
|
|
5
|
+
CreateCheckoutOfferDto,
|
|
6
|
+
UpdateCheckoutOfferDto,
|
|
7
|
+
buildCheckoutOfferController
|
|
8
|
+
} from "../chunk-SYEVGPFC.js";
|
|
9
|
+
import "../chunk-MDIZUVIK.js";
|
|
10
|
+
import "../chunk-XCZ3TTFK.js";
|
|
11
|
+
import "../chunk-SABTXESR.js";
|
|
12
|
+
import "../chunk-SHUYVCID.js";
|
|
13
|
+
export {
|
|
14
|
+
CHECKOUT_OFFER_REPOSITORY_TOKEN,
|
|
15
|
+
CheckoutOfferModule,
|
|
16
|
+
CheckoutOfferService,
|
|
17
|
+
CreateCheckoutOfferDto,
|
|
18
|
+
UpdateCheckoutOfferDto,
|
|
19
|
+
buildCheckoutOfferController
|
|
20
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendImplicitDiscountLineItem
|
|
3
|
+
} from "./chunk-MDIZUVIK.js";
|
|
4
|
+
import {
|
|
5
|
+
SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN
|
|
6
|
+
} from "./chunk-NYLON2VC.js";
|
|
7
|
+
import {
|
|
8
|
+
asProvider
|
|
9
|
+
} from "./chunk-SABTXESR.js";
|
|
10
|
+
import {
|
|
11
|
+
__name
|
|
12
|
+
} from "./chunk-SHUYVCID.js";
|
|
13
|
+
|
|
14
|
+
// src/subscription-contract/subscription-contract.service.ts
|
|
15
|
+
import { ConflictException, Inject, Injectable, NotFoundException, UnprocessableEntityException } from "@nestjs/common";
|
|
16
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
17
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
18
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
19
|
+
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;
|
|
20
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
21
|
+
}
|
|
22
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
23
|
+
function _ts_metadata(k, v) {
|
|
24
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
25
|
+
}
|
|
26
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
27
|
+
function _ts_param(paramIndex, decorator) {
|
|
28
|
+
return function(target, key) {
|
|
29
|
+
decorator(target, key, paramIndex);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
__name(_ts_param, "_ts_param");
|
|
33
|
+
var SubscriptionContractService = class {
|
|
34
|
+
static {
|
|
35
|
+
__name(this, "SubscriptionContractService");
|
|
36
|
+
}
|
|
37
|
+
repo;
|
|
38
|
+
constructor(repo) {
|
|
39
|
+
this.repo = repo;
|
|
40
|
+
}
|
|
41
|
+
list(filter) {
|
|
42
|
+
return this.repo.list(filter);
|
|
43
|
+
}
|
|
44
|
+
async getById(contractId) {
|
|
45
|
+
const row = await this.repo.findById(contractId);
|
|
46
|
+
if (!row) {
|
|
47
|
+
throw new NotFoundException(`SubscriptionContract '${contractId}' nicht gefunden`);
|
|
48
|
+
}
|
|
49
|
+
return row;
|
|
50
|
+
}
|
|
51
|
+
async findActiveByTenantId(tenantId, asOf = /* @__PURE__ */ new Date()) {
|
|
52
|
+
return this.repo.findActiveByTenantId(tenantId, asOf);
|
|
53
|
+
}
|
|
54
|
+
async getActiveInvoiceSnapshotForTenant(tenantId, asOf = /* @__PURE__ */ new Date()) {
|
|
55
|
+
const contract = await this.repo.findActiveByTenantId(tenantId, asOf);
|
|
56
|
+
if (!contract) {
|
|
57
|
+
throw new NotFoundException(`Kein aktiver SubscriptionContract f\xFCr Tenant ${tenantId}`);
|
|
58
|
+
}
|
|
59
|
+
return subscriptionContractToInvoiceSnapshot(contract);
|
|
60
|
+
}
|
|
61
|
+
async create(data) {
|
|
62
|
+
this.assertCreateData(data);
|
|
63
|
+
return this.repo.create(this.cloneCreateData(data));
|
|
64
|
+
}
|
|
65
|
+
async terminate(contractId, data) {
|
|
66
|
+
const existing = await this.getById(contractId);
|
|
67
|
+
this.assertTerminable(existing, data);
|
|
68
|
+
return this.repo.terminate(contractId, data);
|
|
69
|
+
}
|
|
70
|
+
async replaceActiveContract(tenantId, data, terminateAt) {
|
|
71
|
+
const previous = await this.repo.findActiveByTenantId(tenantId, terminateAt);
|
|
72
|
+
if (previous) {
|
|
73
|
+
await this.terminate(previous.id, {
|
|
74
|
+
effectiveUntil: terminateAt,
|
|
75
|
+
status: "superseded"
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const next = await this.create({
|
|
79
|
+
...data,
|
|
80
|
+
tenantId,
|
|
81
|
+
effectiveFrom: data.effectiveFrom ?? terminateAt
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
previous,
|
|
85
|
+
next
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
createDataFromOffer(offer, options) {
|
|
89
|
+
if (offer.status !== "consumed") {
|
|
90
|
+
throw new ConflictException(`CheckoutOffer '${offer.id}' muss vor Contract-Erstellung consumed sein`);
|
|
91
|
+
}
|
|
92
|
+
const lineItems = this.lineItemsFromOffer(offer);
|
|
93
|
+
return {
|
|
94
|
+
projectKey: offer.projectKey,
|
|
95
|
+
tenantId: options.tenantId,
|
|
96
|
+
status: options.status ?? "active",
|
|
97
|
+
effectiveFrom: options.effectiveFrom,
|
|
98
|
+
effectiveUntil: options.effectiveUntil ?? null,
|
|
99
|
+
originalOfferId: offer.id,
|
|
100
|
+
originalPlanVersionId: offer.planVersionId,
|
|
101
|
+
originalBundleVersionIds: [
|
|
102
|
+
...offer.bundleVersionIds ?? []
|
|
103
|
+
],
|
|
104
|
+
entitlementSnapshot: options.entitlementSnapshot ?? null,
|
|
105
|
+
priceSnapshot: this.priceSnapshotFromOffer(offer),
|
|
106
|
+
promotionSnapshots: [
|
|
107
|
+
...offer.promotionSnapshots ?? []
|
|
108
|
+
],
|
|
109
|
+
promoCodeSnapshots: offer.promoCodeSnapshot ? [
|
|
110
|
+
offer.promoCodeSnapshot
|
|
111
|
+
] : [],
|
|
112
|
+
termsSnapshot: options.termsSnapshot ?? null,
|
|
113
|
+
lineItems
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
async createFromOffer(offer, options) {
|
|
117
|
+
return this.create(this.createDataFromOffer(offer, options));
|
|
118
|
+
}
|
|
119
|
+
lineItemsFromOffer(offer) {
|
|
120
|
+
const source = offer.lineItems ?? [];
|
|
121
|
+
if (source.length === 0) {
|
|
122
|
+
throw new UnprocessableEntityException({
|
|
123
|
+
code: "CHECKOUT_OFFER_LINE_ITEMS_REQUIRED",
|
|
124
|
+
message: "Aus einem CheckoutOffer kann nur ein Contract entstehen, wenn LineItems eingefroren sind."
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return appendImplicitDiscountLineItem({
|
|
128
|
+
billingCycle: offer.billingCycle,
|
|
129
|
+
priceBreakdown: offer.priceBreakdown,
|
|
130
|
+
lineItems: source,
|
|
131
|
+
promotionSnapshots: offer.promotionSnapshots ?? [],
|
|
132
|
+
promoCodeSnapshot: offer.promoCodeSnapshot ?? null
|
|
133
|
+
}).map((item) => this.offerLineItemToContractLineItem(item));
|
|
134
|
+
}
|
|
135
|
+
offerLineItemToContractLineItem(item) {
|
|
136
|
+
return {
|
|
137
|
+
kind: item.kind,
|
|
138
|
+
sourceKey: item.sourceKey,
|
|
139
|
+
sourceVersionId: item.sourceVersionId ?? null,
|
|
140
|
+
titleSnapshot: item.titleSnapshot,
|
|
141
|
+
descriptionSnapshot: item.descriptionSnapshot ?? null,
|
|
142
|
+
quantity: item.quantity,
|
|
143
|
+
unit: item.unit ?? null,
|
|
144
|
+
priceNet: item.priceNet,
|
|
145
|
+
priceGross: item.priceGross,
|
|
146
|
+
billingCycle: item.billingCycle,
|
|
147
|
+
minimumTermUntil: this.parseOptionalDate(item.minimumTermUntil, "lineItems.minimumTermUntil"),
|
|
148
|
+
featuresSnapshot: [
|
|
149
|
+
...item.featuresSnapshot ?? []
|
|
150
|
+
],
|
|
151
|
+
quotaEffectsSnapshot: {
|
|
152
|
+
...item.quotaEffectsSnapshot ?? {}
|
|
153
|
+
},
|
|
154
|
+
metadata: item.metadata ?? null
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
parseOptionalDate(value, field) {
|
|
158
|
+
if (value === null || value === void 0) return null;
|
|
159
|
+
const date = value instanceof Date ? new Date(value) : new Date(value);
|
|
160
|
+
if (Number.isNaN(date.getTime())) {
|
|
161
|
+
throw new UnprocessableEntityException({
|
|
162
|
+
code: "SUBSCRIPTION_CONTRACT_INVALID_DATE",
|
|
163
|
+
message: `${field} muss ein g\xFCltiges Datum sein.`
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return date;
|
|
167
|
+
}
|
|
168
|
+
priceSnapshotFromOffer(offer) {
|
|
169
|
+
const breakdown = offer.priceBreakdown;
|
|
170
|
+
return {
|
|
171
|
+
currency: breakdown.currency,
|
|
172
|
+
billingCycle: breakdown.billingCycle,
|
|
173
|
+
subtotalNet: breakdown.regularNet,
|
|
174
|
+
discountNet: Math.max(0, breakdown.regularNet - breakdown.effectiveNet),
|
|
175
|
+
totalNet: breakdown.effectiveNet,
|
|
176
|
+
vatRate: breakdown.vatRate,
|
|
177
|
+
totalGross: breakdown.effectiveGross
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
assertCreateData(data) {
|
|
181
|
+
if (data.lineItems.length === 0) {
|
|
182
|
+
throw new UnprocessableEntityException({
|
|
183
|
+
code: "SUBSCRIPTION_CONTRACT_LINE_ITEMS_REQUIRED",
|
|
184
|
+
message: "SubscriptionContract ben\xF6tigt mindestens eine LineItem."
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (data.effectiveUntil && data.effectiveUntil <= data.effectiveFrom) {
|
|
188
|
+
throw new UnprocessableEntityException({
|
|
189
|
+
code: "SUBSCRIPTION_CONTRACT_INVALID_WINDOW",
|
|
190
|
+
message: "effectiveUntil muss nach effectiveFrom liegen."
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const planLineItems = data.lineItems.filter((item) => item.kind === "plan");
|
|
194
|
+
if (planLineItems.length !== 1) {
|
|
195
|
+
throw new UnprocessableEntityException({
|
|
196
|
+
code: "SUBSCRIPTION_CONTRACT_PLAN_LINE_ITEM_REQUIRED",
|
|
197
|
+
message: "SubscriptionContract ben\xF6tigt genau eine Plan-Grundposition."
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
assertTerminable(existing, data) {
|
|
202
|
+
if (existing.status === "terminated" || existing.status === "superseded") {
|
|
203
|
+
throw new ConflictException(`SubscriptionContract '${existing.id}' ist bereits geschlossen`);
|
|
204
|
+
}
|
|
205
|
+
if (data.effectiveUntil <= existing.effectiveFrom) {
|
|
206
|
+
throw new UnprocessableEntityException({
|
|
207
|
+
code: "SUBSCRIPTION_CONTRACT_TERMINATION_BEFORE_START",
|
|
208
|
+
message: "effectiveUntil muss nach effectiveFrom des Contracts liegen."
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
cloneCreateData(data) {
|
|
213
|
+
return {
|
|
214
|
+
...data,
|
|
215
|
+
originalBundleVersionIds: [
|
|
216
|
+
...data.originalBundleVersionIds ?? []
|
|
217
|
+
],
|
|
218
|
+
promotionSnapshots: [
|
|
219
|
+
...data.promotionSnapshots ?? []
|
|
220
|
+
],
|
|
221
|
+
promoCodeSnapshots: [
|
|
222
|
+
...data.promoCodeSnapshots ?? []
|
|
223
|
+
],
|
|
224
|
+
termsSnapshot: data.termsSnapshot ? {
|
|
225
|
+
...data.termsSnapshot
|
|
226
|
+
} : null,
|
|
227
|
+
lineItems: data.lineItems.map((item) => this.cloneLineItemData(item))
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
cloneLineItemData(item) {
|
|
231
|
+
return {
|
|
232
|
+
...item,
|
|
233
|
+
featuresSnapshot: [
|
|
234
|
+
...item.featuresSnapshot
|
|
235
|
+
],
|
|
236
|
+
quotaEffectsSnapshot: {
|
|
237
|
+
...item.quotaEffectsSnapshot
|
|
238
|
+
},
|
|
239
|
+
metadata: item.metadata ? {
|
|
240
|
+
...item.metadata
|
|
241
|
+
} : null
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
SubscriptionContractService = _ts_decorate([
|
|
246
|
+
Injectable(),
|
|
247
|
+
_ts_param(0, Inject(SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN)),
|
|
248
|
+
_ts_metadata("design:type", Function),
|
|
249
|
+
_ts_metadata("design:paramtypes", [
|
|
250
|
+
typeof SubscriptionContractRepository === "undefined" ? Object : SubscriptionContractRepository
|
|
251
|
+
])
|
|
252
|
+
], SubscriptionContractService);
|
|
253
|
+
function contractLineItemToInvoiceLineItem(item) {
|
|
254
|
+
return {
|
|
255
|
+
sourceContractLineItemId: item.id,
|
|
256
|
+
sourceKey: item.sourceKey,
|
|
257
|
+
sourceVersionId: item.sourceVersionId,
|
|
258
|
+
kind: item.kind,
|
|
259
|
+
title: item.titleSnapshot,
|
|
260
|
+
description: item.descriptionSnapshot,
|
|
261
|
+
quantity: item.quantity,
|
|
262
|
+
unit: item.unit,
|
|
263
|
+
priceNet: item.priceNet,
|
|
264
|
+
priceGross: item.priceGross,
|
|
265
|
+
billingCycle: item.billingCycle,
|
|
266
|
+
minimumTermUntil: item.minimumTermUntil,
|
|
267
|
+
metadata: item.metadata
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
__name(contractLineItemToInvoiceLineItem, "contractLineItemToInvoiceLineItem");
|
|
271
|
+
function subscriptionContractToInvoiceSnapshot(contract) {
|
|
272
|
+
return {
|
|
273
|
+
contractId: contract.id,
|
|
274
|
+
projectKey: contract.projectKey,
|
|
275
|
+
tenantId: contract.tenantId,
|
|
276
|
+
originalOfferId: contract.originalOfferId,
|
|
277
|
+
currency: contract.priceSnapshot.currency,
|
|
278
|
+
billingCycle: contract.priceSnapshot.billingCycle,
|
|
279
|
+
effectiveFrom: contract.effectiveFrom,
|
|
280
|
+
effectiveUntil: contract.effectiveUntil,
|
|
281
|
+
subtotalNet: contract.priceSnapshot.subtotalNet,
|
|
282
|
+
discountNet: contract.priceSnapshot.discountNet,
|
|
283
|
+
totalNet: contract.priceSnapshot.totalNet,
|
|
284
|
+
vatRate: contract.priceSnapshot.vatRate,
|
|
285
|
+
totalGross: contract.priceSnapshot.totalGross,
|
|
286
|
+
lineItems: sortContractLineItemsForInvoice(contract.lineItems).map(contractLineItemToInvoiceLineItem)
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
__name(subscriptionContractToInvoiceSnapshot, "subscriptionContractToInvoiceSnapshot");
|
|
290
|
+
function sortContractLineItemsForInvoice(lineItems) {
|
|
291
|
+
return [
|
|
292
|
+
...lineItems
|
|
293
|
+
].sort((a, b) => lineItemKindPriority(a.kind) - lineItemKindPriority(b.kind) || a.createdAt.getTime() - b.createdAt.getTime() || a.id.localeCompare(b.id));
|
|
294
|
+
}
|
|
295
|
+
__name(sortContractLineItemsForInvoice, "sortContractLineItemsForInvoice");
|
|
296
|
+
function lineItemKindPriority(kind) {
|
|
297
|
+
switch (kind) {
|
|
298
|
+
case "plan":
|
|
299
|
+
return 10;
|
|
300
|
+
case "bundle":
|
|
301
|
+
return 20;
|
|
302
|
+
case "discount":
|
|
303
|
+
return 90;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
__name(lineItemKindPriority, "lineItemKindPriority");
|
|
307
|
+
|
|
308
|
+
// src/subscription-contract/subscription-contract.module.ts
|
|
309
|
+
import { Module } from "@nestjs/common";
|
|
310
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
311
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
312
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
313
|
+
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;
|
|
314
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
315
|
+
}
|
|
316
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
317
|
+
var SubscriptionContractModule = class _SubscriptionContractModule {
|
|
318
|
+
static {
|
|
319
|
+
__name(this, "SubscriptionContractModule");
|
|
320
|
+
}
|
|
321
|
+
static forRoot(options) {
|
|
322
|
+
return {
|
|
323
|
+
module: _SubscriptionContractModule,
|
|
324
|
+
global: options.global ?? false,
|
|
325
|
+
providers: [
|
|
326
|
+
asProvider(SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN, options.subscriptionContractRepository),
|
|
327
|
+
SubscriptionContractService,
|
|
328
|
+
...options.extraProviders ?? []
|
|
329
|
+
],
|
|
330
|
+
exports: [
|
|
331
|
+
SubscriptionContractService,
|
|
332
|
+
SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN
|
|
333
|
+
]
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
SubscriptionContractModule = _ts_decorate2([
|
|
338
|
+
Module({})
|
|
339
|
+
], SubscriptionContractModule);
|
|
340
|
+
|
|
341
|
+
export {
|
|
342
|
+
SubscriptionContractService,
|
|
343
|
+
contractLineItemToInvoiceLineItem,
|
|
344
|
+
subscriptionContractToInvoiceSnapshot,
|
|
345
|
+
sortContractLineItemsForInvoice,
|
|
346
|
+
SubscriptionContractModule
|
|
347
|
+
};
|