@mj-biz-apps/orders-entities 5.23.0 → 5.24.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.
Files changed (35) hide show
  1. package/dist/ProductEntity.d.ts +61 -0
  2. package/dist/ProductEntity.d.ts.map +1 -0
  3. package/dist/ProductEntity.js +146 -0
  4. package/dist/ProductEntity.js.map +1 -0
  5. package/dist/billing-location.d.ts +50 -0
  6. package/dist/billing-location.d.ts.map +1 -0
  7. package/dist/billing-location.js +439 -0
  8. package/dist/billing-location.js.map +1 -0
  9. package/dist/configuration-types.d.ts +38 -0
  10. package/dist/configuration-types.d.ts.map +1 -1
  11. package/dist/generated/entities/__mj_BizAppsOrders.d.ts +67 -1
  12. package/dist/generated/entities/__mj_BizAppsOrders.d.ts.map +1 -1
  13. package/dist/generated/entities/__mj_BizAppsOrders.js +103 -2
  14. package/dist/generated/entities/__mj_BizAppsOrders.js.map +1 -1
  15. package/dist/generated/remote_operations.d.ts +43 -2
  16. package/dist/generated/remote_operations.d.ts.map +1 -1
  17. package/dist/generated/remote_operations.js +1 -1
  18. package/dist/generated/remote_operations.js.map +1 -1
  19. package/dist/index.d.ts +7 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +7 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/pricing/OrderPricingService.d.ts +17 -0
  24. package/dist/pricing/OrderPricingService.d.ts.map +1 -1
  25. package/dist/pricing/OrderPricingService.js +14 -6
  26. package/dist/pricing/OrderPricingService.js.map +1 -1
  27. package/dist/pricing/PricingBehavior.d.ts +27 -0
  28. package/dist/pricing/PricingBehavior.d.ts.map +1 -1
  29. package/dist/pricing/PricingBehavior.js +23 -0
  30. package/dist/pricing/PricingBehavior.js.map +1 -1
  31. package/dist/pricing/linePricePick.d.ts +16 -0
  32. package/dist/pricing/linePricePick.d.ts.map +1 -1
  33. package/dist/pricing/linePricePick.js +21 -0
  34. package/dist/pricing/linePricePick.js.map +1 -1
  35. package/package.json +2 -2
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Shared Product subclass: a product takes its type's defaults when the type is chosen
3
+ * (bc-aidp-next-golive#277).
4
+ *
5
+ * `ProductType` carries `DefaultRevenueRecognitionTypeID`, `DefaultSubscriptionTypeID` and
6
+ * `DefaultIsTaxable`. Nothing copied them onto a new product, so `RevenueRecognitionTypeID` (NOT
7
+ * NULL) refused the save until it was set by hand, and `SubscriptionTypeID` / `IsTaxable` saved null.
8
+ *
9
+ * Lives here rather than in the form so every caller gets it: the form, a Remote Operation, an
10
+ * integration, a script.
11
+ */
12
+ import { type EntitySaveOptions, type FieldValueCollection } from '@memberjunction/core';
13
+ import { mjBizAppsOrdersProductEntity } from './generated/entity_subclasses.js';
14
+ import { OrdersEngine } from './pricing/OrdersEngine.js';
15
+ /** The product fields a product type supplies a default for. */
16
+ export type ProductDefaults = {
17
+ RevenueRecognitionTypeID: string | null;
18
+ SubscriptionTypeID: string | null;
19
+ IsTaxable: boolean | null;
20
+ };
21
+ export declare const PRODUCT_DEFAULT_FIELDS: readonly ["RevenueRecognitionTypeID", "SubscriptionTypeID", "IsTaxable"];
22
+ export type ProductDefaultField = (typeof PRODUCT_DEFAULT_FIELDS)[number];
23
+ /** The lookups default resolution reads. `OrdersEngine` satisfies it. */
24
+ export type ProductDefaultsLookup = Pick<OrdersEngine, 'ProductTypeByID' | 'ProductCategoryByID' | 'CategoryChain'>;
25
+ /**
26
+ * The defaults a product of this type, in this category, starts with. Null when the type is unknown.
27
+ *
28
+ * Taxability is the answer the taxability walk gives a product that says nothing itself — its
29
+ * category chain, nearest first, then the type. The type's `DefaultIsTaxable` alone would stamp
30
+ * "taxable" onto a product whose category is exempt.
31
+ */
32
+ export declare function ResolveProductDefaults(lookup: ProductDefaultsLookup, productTypeID: string | null | undefined, productCategoryID: string | null | undefined): ProductDefaults | null;
33
+ /**
34
+ * Which default fields to write, and with what.
35
+ *
36
+ * A field takes the new default when it is empty, or when it still holds the value this record
37
+ * stamped earlier — i.e. it came from the previous type, not from the user. A value the user chose
38
+ * is never overwritten. When the new type has no default for a field it stamped, the stamp is
39
+ * cleared, so switching Subscription → Merchandise does not leave Annual Rolling behind.
40
+ */
41
+ export declare function PlanProductDefaultWrites(current: ProductDefaults, stamped: Partial<ProductDefaults>, next: ProductDefaults): Partial<ProductDefaults>;
42
+ export declare class ProductEntity extends mjBizAppsOrdersProductEntity {
43
+ /** What this instance wrote from a type default, per field — the values it may replace later. */
44
+ private stampedDefaults;
45
+ /**
46
+ * Applies the defaults when the type or category changes. Form fields and the typed setters
47
+ * both write through `Set`; loads do not (they use `SetMany`), so a loaded product is untouched.
48
+ */
49
+ Set(FieldName: string, Value: unknown): void;
50
+ /** A record created with `ProductTypeID` in `newValues` never passes through `Set`. */
51
+ NewRecord(newValues?: FieldValueCollection): boolean;
52
+ /**
53
+ * The same fill before a new product saves, after loading the engine — a caller whose engine
54
+ * was not loaded when the type was set still saves with the type's defaults. Existing products
55
+ * are not touched here: a null `IsTaxable` on a saved product is not this save's to change.
56
+ */
57
+ Save(options?: EntitySaveOptions): Promise<boolean>;
58
+ /** Synchronous: reads the engine only when it is already loaded. */
59
+ protected applyTypeDefaults(): void;
60
+ }
61
+ //# sourceMappingURL=ProductEntity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProductEntity.d.ts","sourceRoot":"","sources":["../src/ProductEntity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAc,KAAK,iBAAiB,EAAE,KAAK,oBAAoB,EAAoC,MAAM,sBAAsB,CAAC;AAEvI,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAoB,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAKxE,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG;IAC1B,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,sBAAsB,0EAA2E,CAAC;AAC/G,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,yEAAyE;AACzE,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,YAAY,EAAE,iBAAiB,GAAG,qBAAqB,GAAG,eAAe,CAAC,CAAC;AAEpH;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAClC,MAAM,EAAE,qBAAqB,EAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC7C,eAAe,GAAG,IAAI,CAqBxB;AAYD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACpC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,EACjC,IAAI,EAAE,eAAe,GACtB,OAAO,CAAC,eAAe,CAAC,CAS1B;AAED,qBACa,aAAc,SAAQ,4BAA4B;IAC3D,iGAAiG;IACjG,OAAO,CAAC,eAAe,CAAgC;IAEvD;;;OAGG;IACa,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAS5D,uFAAuF;IACvE,SAAS,CAAC,SAAS,CAAC,EAAE,oBAAoB,GAAG,OAAO;IAMpE;;;;OAIG;IACmB,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAYzE,oEAAoE;IACpE,SAAS,CAAC,iBAAiB,IAAI,IAAI;CAqBtC"}
@@ -0,0 +1,146 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ /**
8
+ * Shared Product subclass: a product takes its type's defaults when the type is chosen
9
+ * (bc-aidp-next-golive#277).
10
+ *
11
+ * `ProductType` carries `DefaultRevenueRecognitionTypeID`, `DefaultSubscriptionTypeID` and
12
+ * `DefaultIsTaxable`. Nothing copied them onto a new product, so `RevenueRecognitionTypeID` (NOT
13
+ * NULL) refused the save until it was set by hand, and `SubscriptionTypeID` / `IsTaxable` saved null.
14
+ *
15
+ * Lives here rather than in the form so every caller gets it: the form, a Remote Operation, an
16
+ * integration, a script.
17
+ */
18
+ import { BaseEntity, LogError } from '@memberjunction/core';
19
+ import { RegisterClass } from '@memberjunction/global';
20
+ import { mjBizAppsOrdersProductEntity } from './generated/entity_subclasses.js';
21
+ import { LoadOrdersEngine, OrdersEngine } from './pricing/OrdersEngine.js';
22
+ import { ResolveTaxability } from './pricing/TaxResolver.js';
23
+ const ENTITY = 'MJ_BizApps_Orders: Products';
24
+ export const PRODUCT_DEFAULT_FIELDS = ['RevenueRecognitionTypeID', 'SubscriptionTypeID', 'IsTaxable'];
25
+ /**
26
+ * The defaults a product of this type, in this category, starts with. Null when the type is unknown.
27
+ *
28
+ * Taxability is the answer the taxability walk gives a product that says nothing itself — its
29
+ * category chain, nearest first, then the type. The type's `DefaultIsTaxable` alone would stamp
30
+ * "taxable" onto a product whose category is exempt.
31
+ */
32
+ export function ResolveProductDefaults(lookup, productTypeID, productCategoryID) {
33
+ const type = lookup.ProductTypeByID(productTypeID);
34
+ if (!type)
35
+ return null;
36
+ const chain = [];
37
+ for (const id of lookup.CategoryChain(productCategoryID)) {
38
+ const row = lookup.ProductCategoryByID(id);
39
+ if (!row)
40
+ break;
41
+ chain.push({ ID: row.ID, DefaultIsTaxable: row.DefaultIsTaxable, DefaultTaxCategory: row.DefaultTaxCategory });
42
+ }
43
+ const taxability = ResolveTaxability({ IsTaxable: null, TaxCategory: null }, chain, { DefaultIsTaxable: type.DefaultIsTaxable, DefaultTaxCategory: type.DefaultTaxCategory ?? null });
44
+ return {
45
+ RevenueRecognitionTypeID: type.DefaultRevenueRecognitionTypeID?.trim() || null,
46
+ SubscriptionTypeID: type.DefaultSubscriptionTypeID?.trim() || null,
47
+ IsTaxable: taxability.IsTaxable,
48
+ };
49
+ }
50
+ const isEmpty = (v) => v == null || (typeof v === 'string' && v.trim() === '');
51
+ const sameValue = (a, b) => {
52
+ if (isEmpty(a) && isEmpty(b))
53
+ return true;
54
+ if (typeof a === 'string' && typeof b === 'string')
55
+ return a.trim().toLowerCase() === b.trim().toLowerCase();
56
+ return a === b;
57
+ };
58
+ /**
59
+ * Which default fields to write, and with what.
60
+ *
61
+ * A field takes the new default when it is empty, or when it still holds the value this record
62
+ * stamped earlier — i.e. it came from the previous type, not from the user. A value the user chose
63
+ * is never overwritten. When the new type has no default for a field it stamped, the stamp is
64
+ * cleared, so switching Subscription → Merchandise does not leave Annual Rolling behind.
65
+ */
66
+ export function PlanProductDefaultWrites(current, stamped, next) {
67
+ const writes = {};
68
+ for (const field of PRODUCT_DEFAULT_FIELDS) {
69
+ const stillStamped = field in stamped && sameValue(stamped[field], current[field]);
70
+ if (!isEmpty(current[field]) && !stillStamped)
71
+ continue;
72
+ if (sameValue(current[field], next[field]))
73
+ continue;
74
+ writes[field] = next[field];
75
+ }
76
+ return writes;
77
+ }
78
+ let ProductEntity = class ProductEntity extends mjBizAppsOrdersProductEntity {
79
+ constructor() {
80
+ super(...arguments);
81
+ /** What this instance wrote from a type default, per field — the values it may replace later. */
82
+ this.stampedDefaults = {};
83
+ }
84
+ /**
85
+ * Applies the defaults when the type or category changes. Form fields and the typed setters
86
+ * both write through `Set`; loads do not (they use `SetMany`), so a loaded product is untouched.
87
+ */
88
+ Set(FieldName, Value) {
89
+ const watched = FieldName === 'ProductTypeID' || FieldName === 'ProductCategoryID';
90
+ const before = watched ? this.Get(FieldName) : undefined;
91
+ super.Set(FieldName, Value);
92
+ if (watched && !sameValue(before, this.Get(FieldName))) {
93
+ this.applyTypeDefaults();
94
+ }
95
+ }
96
+ /** A record created with `ProductTypeID` in `newValues` never passes through `Set`. */
97
+ NewRecord(newValues) {
98
+ const created = super.NewRecord(newValues);
99
+ if (created)
100
+ this.applyTypeDefaults();
101
+ return created;
102
+ }
103
+ /**
104
+ * The same fill before a new product saves, after loading the engine — a caller whose engine
105
+ * was not loaded when the type was set still saves with the type's defaults. Existing products
106
+ * are not touched here: a null `IsTaxable` on a saved product is not this save's to change.
107
+ */
108
+ async Save(options) {
109
+ if (!this.IsSaved) {
110
+ try {
111
+ await LoadOrdersEngine(this.ProviderToUse, this.ContextCurrentUser);
112
+ this.applyTypeDefaults();
113
+ }
114
+ catch (e) {
115
+ LogError(`Product type defaults not applied — OrdersEngine unavailable: ${e}`);
116
+ }
117
+ }
118
+ return super.Save(options);
119
+ }
120
+ /** Synchronous: reads the engine only when it is already loaded. */
121
+ applyTypeDefaults() {
122
+ const engine = OrdersEngine.Instance;
123
+ if (!engine.Loaded)
124
+ return;
125
+ const next = ResolveProductDefaults(engine, this.ProductTypeID, this.ProductCategoryID);
126
+ if (!next)
127
+ return;
128
+ const writes = PlanProductDefaultWrites({
129
+ RevenueRecognitionTypeID: this.RevenueRecognitionTypeID ?? null,
130
+ SubscriptionTypeID: this.SubscriptionTypeID ?? null,
131
+ IsTaxable: this.IsTaxable ?? null,
132
+ }, this.stampedDefaults, next);
133
+ if ('RevenueRecognitionTypeID' in writes)
134
+ this.RevenueRecognitionTypeID = writes.RevenueRecognitionTypeID;
135
+ if ('SubscriptionTypeID' in writes)
136
+ this.SubscriptionTypeID = writes.SubscriptionTypeID ?? null;
137
+ if ('IsTaxable' in writes)
138
+ this.IsTaxable = writes.IsTaxable ?? null;
139
+ this.stampedDefaults = { ...this.stampedDefaults, ...writes };
140
+ }
141
+ };
142
+ ProductEntity = __decorate([
143
+ RegisterClass(BaseEntity, ENTITY)
144
+ ], ProductEntity);
145
+ export { ProductEntity };
146
+ //# sourceMappingURL=ProductEntity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProductEntity.js","sourceRoot":"","sources":["../src/ProductEntity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Billing location — the facts a sale needs to be placed in a taxing jurisdiction.
3
+ *
4
+ * A card sale taken with no location can never be assigned to a state or country afterwards, so
5
+ * the self-serve checkout refuses to take payment without one. Country is ISO 3166-1 alpha-2;
6
+ * the region is the ISO 3166-2 subdivision code WITHOUT its country prefix (`IL`, not `US-IL`),
7
+ * because that is the form `TaxJurisdiction.RegionCode` holds and jurisdiction matching compares
8
+ * the two directly.
9
+ *
10
+ * The lists live here, beside the entities, so the widget's pickers and the server's check read
11
+ * the same data and cannot disagree about what a valid location is.
12
+ *
13
+ * @module @mj-biz-apps/orders-entities/billing-location
14
+ */
15
+ /** A country or subdivision as a picker shows it. */
16
+ export interface LocationOption {
17
+ Code: string;
18
+ Name: string;
19
+ }
20
+ /** A location that passed {@link CheckBillingLocation}, normalised to upper-case codes. */
21
+ export interface BillingLocation {
22
+ Country: string;
23
+ StateProvince: string | null;
24
+ PostalCode: string | null;
25
+ }
26
+ export type BillingLocationCheck = {
27
+ Valid: true;
28
+ Location: BillingLocation;
29
+ } | {
30
+ Valid: false;
31
+ Reason: string;
32
+ };
33
+ /** ISO 3166-1 alpha-2, by English short name. */
34
+ export declare const BILLING_COUNTRIES: ReadonlyArray<LocationOption>;
35
+ /** ISO 3166-2 subdivisions, country prefix removed. Only the countries that require one are listed. */
36
+ export declare const BILLING_SUBDIVISIONS: Readonly<Record<string, ReadonlyArray<LocationOption>>>;
37
+ /** The subdivisions to offer for a country — empty when the country does not require one. */
38
+ export declare function BillingSubdivisionsFor(countryCode: string | null | undefined): ReadonlyArray<LocationOption>;
39
+ /** True when the country's sales cannot be placed without a state or province. */
40
+ export declare function BillingSubdivisionRequired(countryCode: string | null | undefined): boolean;
41
+ /** True when the country's postal code is required, and so shape-checked. */
42
+ export declare function BillingPostalCodeRequired(countryCode: string | null | undefined): boolean;
43
+ /**
44
+ * Check a caller-supplied location and normalise it.
45
+ *
46
+ * Accepts only codes from the lists above: a free-text region such as "Illinois" is refused,
47
+ * because a name cannot be matched to a jurisdiction and a mistyped one would silently match none.
48
+ */
49
+ export declare function CheckBillingLocation(input: unknown): BillingLocationCheck;
50
+ //# sourceMappingURL=billing-location.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing-location.d.ts","sourceRoot":"","sources":["../src/billing-location.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,2FAA2F;AAC3F,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,MAAM,oBAAoB,GAC1B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,GAC1C;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,iDAAiD;AACjD,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,cAAc,CA0P3D,CAAC;AAEF,uGAAuG;AACvG,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC,CAqFxF,CAAC;AAcF,6FAA6F;AAC7F,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,aAAa,CAAC,cAAc,CAAC,CAE5G;AAED,kFAAkF;AAClF,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE1F;AAED,6EAA6E;AAC7E,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEzF;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAoBzE"}