@mj-biz-apps/orders-ng 5.2.0 → 5.3.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.
@@ -1,6 +1,7 @@
1
1
  import { Component, EventEmitter, Input, Output } from '@angular/core';
2
2
  import * as i0 from "@angular/core";
3
3
  import * as i1 from "@memberjunction/ng-base-forms";
4
+ import * as i2 from "./product-gl-links.component.js";
4
5
  /**
5
6
  * Droppable Product Tax, Charges & Accounting GL Widget.
6
7
  */
@@ -10,7 +11,7 @@ export class BizAppsProductAccountingWidgetComponent {
10
11
  FormContext;
11
12
  Navigate = new EventEmitter();
12
13
  static ɵfac = function BizAppsProductAccountingWidgetComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || BizAppsProductAccountingWidgetComponent)(); };
13
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: BizAppsProductAccountingWidgetComponent, selectors: [["bizapps-product-accounting-widget"]], inputs: { Product: "Product", EditMode: "EditMode", FormContext: "FormContext" }, outputs: { Navigate: "Navigate" }, standalone: false, decls: 11, vars: 16, consts: [[1, "mjo-acct-widget-wrap"], [1, "mjo-acct-card"], [1, "mjo-card-head"], [1, "fa-solid", "fa-scale-balanced"], [1, "mjo-card-body"], ["FieldName", "RevenueRecognitionTypeID", "Type", "textbox", "LinkType", "Record", 3, "Navigate", "Record", "ShowLabel", "EditMode", "FormContext"], ["FieldName", "IsTaxable", "Type", "checkbox", 3, "Navigate", "Record", "ShowLabel", "EditMode", "FormContext"], ["FieldName", "TaxCategory", "Type", "textbox", 3, "Navigate", "Record", "ShowLabel", "EditMode", "FormContext"], ["FieldName", "StandaloneSellingPrice", "Type", "number", 3, "Navigate", "Record", "ShowLabel", "EditMode", "FormContext"]], template: function BizAppsProductAccountingWidgetComponent_Template(rf, ctx) { if (rf & 1) {
14
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: BizAppsProductAccountingWidgetComponent, selectors: [["bizapps-product-accounting-widget"]], inputs: { Product: "Product", EditMode: "EditMode", FormContext: "FormContext" }, outputs: { Navigate: "Navigate" }, standalone: false, decls: 14, vars: 19, consts: [[1, "mjo-acct-widget-wrap"], [1, "mjo-acct-card"], [1, "mjo-card-head"], [1, "fa-solid", "fa-scale-balanced"], [1, "mjo-card-body"], ["FieldName", "RevenueRecognitionTypeID", "Type", "textbox", "LinkType", "Record", 3, "Navigate", "Record", "ShowLabel", "EditMode", "FormContext"], ["FieldName", "IsTaxable", "Type", "checkbox", 3, "Navigate", "Record", "ShowLabel", "EditMode", "FormContext"], ["FieldName", "TaxCategory", "Type", "textbox", 3, "Navigate", "Record", "ShowLabel", "EditMode", "FormContext"], ["FieldName", "StandaloneSellingPrice", "Type", "number", 3, "Navigate", "Record", "ShowLabel", "EditMode", "FormContext"], [3, "Navigate", "Product", "EditMode", "FormContext"]], template: function BizAppsProductAccountingWidgetComponent_Template(rf, ctx) { if (rf & 1) {
14
15
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2);
15
16
  i0.ɵɵelement(3, "i", 3);
16
17
  i0.ɵɵelementStart(4, "span");
@@ -27,6 +28,9 @@ export class BizAppsProductAccountingWidgetComponent {
27
28
  i0.ɵɵelementEnd();
28
29
  i0.ɵɵelementStart(10, "mj-form-field", 8);
29
30
  i0.ɵɵlistener("Navigate", function BizAppsProductAccountingWidgetComponent_Template_mj_form_field_Navigate_10_listener($event) { return ctx.Navigate.emit($event); });
31
+ i0.ɵɵelementEnd()()();
32
+ i0.ɵɵelementStart(11, "div", 1)(12, "div", 4)(13, "bizapps-product-gl-links", 9);
33
+ i0.ɵɵlistener("Navigate", function BizAppsProductAccountingWidgetComponent_Template_bizapps_product_gl_links_Navigate_13_listener($event) { return ctx.Navigate.emit($event); });
30
34
  i0.ɵɵelementEnd()()()();
31
35
  } if (rf & 2) {
32
36
  i0.ɵɵadvance(7);
@@ -37,11 +41,13 @@ export class BizAppsProductAccountingWidgetComponent {
37
41
  i0.ɵɵproperty("Record", ctx.Product)("ShowLabel", true)("EditMode", ctx.EditMode)("FormContext", ctx.FormContext);
38
42
  i0.ɵɵadvance();
39
43
  i0.ɵɵproperty("Record", ctx.Product)("ShowLabel", true)("EditMode", ctx.EditMode)("FormContext", ctx.FormContext);
40
- } }, dependencies: [i1.MjFormFieldComponent], styles: [".mjo-acct-widget-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4, 16px);\n width: 100%;\n}\n\n.mjo-acct-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card, rgba(255, 255, 255, 0.05));\n border: 1px solid var(--mj-border-default, rgba(255, 255, 255, 0.12));\n border-radius: var(--mj-radius-lg, 10px);\n overflow: hidden;\n}\n\n.mjo-card-head[_ngcontent-%COMP%] {\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken, rgba(0, 0, 0, 0.1));\n border-bottom: 1px solid var(--mj-border-default, rgba(255, 255, 255, 0.1));\n font-size: 13.5px;\n font-weight: 700;\n color: var(--mj-text-primary, #0f172a);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mjo-card-head[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary, #0284c7);\n}\n\n.mjo-card-body[_ngcontent-%COMP%] {\n padding: 16px;\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));\n gap: 16px;\n}"] });
44
+ i0.ɵɵadvance(3);
45
+ i0.ɵɵproperty("Product", ctx.Product)("EditMode", ctx.EditMode)("FormContext", ctx.FormContext);
46
+ } }, dependencies: [i1.MjFormFieldComponent, i2.BizAppsProductGLLinksComponent], styles: [".mjo-acct-widget-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4, 16px);\n width: 100%;\n}\n\n.mjo-acct-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card, rgba(255, 255, 255, 0.05));\n border: 1px solid var(--mj-border-default, rgba(255, 255, 255, 0.12));\n border-radius: var(--mj-radius-lg, 10px);\n overflow: hidden;\n}\n\n.mjo-card-head[_ngcontent-%COMP%] {\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken, rgba(0, 0, 0, 0.1));\n border-bottom: 1px solid var(--mj-border-default, rgba(255, 255, 255, 0.1));\n font-size: 13.5px;\n font-weight: 700;\n color: var(--mj-text-primary, #0f172a);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mjo-card-head[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary, #0284c7);\n}\n\n.mjo-card-body[_ngcontent-%COMP%] {\n padding: 16px;\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));\n gap: 16px;\n}"] });
41
47
  }
42
48
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(BizAppsProductAccountingWidgetComponent, [{
43
49
  type: Component,
44
- args: [{ standalone: false, selector: 'bizapps-product-accounting-widget', template: "<div class=\"mjo-acct-widget-wrap\">\n <div class=\"mjo-acct-card\">\n <div class=\"mjo-card-head\">\n <i class=\"fa-solid fa-scale-balanced\"></i>\n <span>General Ledger &amp; Revenue Recognition Classification</span>\n </div>\n <div class=\"mjo-card-body\">\n <mj-form-field \n [Record]=\"Product\"\n [ShowLabel]=\"true\"\n FieldName=\"RevenueRecognitionTypeID\"\n Type=\"textbox\"\n [EditMode]=\"EditMode\"\n [FormContext]=\"FormContext\"\n LinkType=\"Record\"\n (Navigate)=\"Navigate.emit($event)\"\n ></mj-form-field>\n <mj-form-field \n [Record]=\"Product\"\n [ShowLabel]=\"true\"\n FieldName=\"IsTaxable\"\n Type=\"checkbox\"\n [EditMode]=\"EditMode\"\n [FormContext]=\"FormContext\"\n (Navigate)=\"Navigate.emit($event)\"\n ></mj-form-field>\n <mj-form-field \n [Record]=\"Product\"\n [ShowLabel]=\"true\"\n FieldName=\"TaxCategory\"\n Type=\"textbox\"\n [EditMode]=\"EditMode\"\n [FormContext]=\"FormContext\"\n (Navigate)=\"Navigate.emit($event)\"\n ></mj-form-field>\n <mj-form-field \n [Record]=\"Product\"\n [ShowLabel]=\"true\"\n FieldName=\"StandaloneSellingPrice\"\n Type=\"number\"\n [EditMode]=\"EditMode\"\n [FormContext]=\"FormContext\"\n (Navigate)=\"Navigate.emit($event)\"\n ></mj-form-field>\n </div>\n </div>\n</div>\n", styles: [".mjo-acct-widget-wrap {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4, 16px);\n width: 100%;\n}\n\n.mjo-acct-card {\n background: var(--mj-bg-surface-card, rgba(255, 255, 255, 0.05));\n border: 1px solid var(--mj-border-default, rgba(255, 255, 255, 0.12));\n border-radius: var(--mj-radius-lg, 10px);\n overflow: hidden;\n}\n\n.mjo-card-head {\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken, rgba(0, 0, 0, 0.1));\n border-bottom: 1px solid var(--mj-border-default, rgba(255, 255, 255, 0.1));\n font-size: 13.5px;\n font-weight: 700;\n color: var(--mj-text-primary, #0f172a);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mjo-card-head i {\n color: var(--mj-brand-primary, #0284c7);\n}\n\n.mjo-card-body {\n padding: 16px;\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));\n gap: 16px;\n}\n"] }]
50
+ args: [{ standalone: false, selector: 'bizapps-product-accounting-widget', template: "<div class=\"mjo-acct-widget-wrap\">\n <div class=\"mjo-acct-card\">\n <div class=\"mjo-card-head\">\n <i class=\"fa-solid fa-scale-balanced\"></i>\n <span>General Ledger &amp; Revenue Recognition Classification</span>\n </div>\n <div class=\"mjo-card-body\">\n <mj-form-field \n [Record]=\"Product\"\n [ShowLabel]=\"true\"\n FieldName=\"RevenueRecognitionTypeID\"\n Type=\"textbox\"\n [EditMode]=\"EditMode\"\n [FormContext]=\"FormContext\"\n LinkType=\"Record\"\n (Navigate)=\"Navigate.emit($event)\"\n ></mj-form-field>\n <mj-form-field \n [Record]=\"Product\"\n [ShowLabel]=\"true\"\n FieldName=\"IsTaxable\"\n Type=\"checkbox\"\n [EditMode]=\"EditMode\"\n [FormContext]=\"FormContext\"\n (Navigate)=\"Navigate.emit($event)\"\n ></mj-form-field>\n <mj-form-field \n [Record]=\"Product\"\n [ShowLabel]=\"true\"\n FieldName=\"TaxCategory\"\n Type=\"textbox\"\n [EditMode]=\"EditMode\"\n [FormContext]=\"FormContext\"\n (Navigate)=\"Navigate.emit($event)\"\n ></mj-form-field>\n <mj-form-field \n [Record]=\"Product\"\n [ShowLabel]=\"true\"\n FieldName=\"StandaloneSellingPrice\"\n Type=\"number\"\n [EditMode]=\"EditMode\"\n [FormContext]=\"FormContext\"\n (Navigate)=\"Navigate.emit($event)\"\n ></mj-form-field>\n </div>\n </div>\n\n <!--\n bizapps-orders#113 \u2014 the GL accounts this product books to.\n\n Andrew expected these HERE, under Accounting, and the section showed only the\n product's own columns. The links live in accounting, but they are polymorphic\n ((EntityID, RecordID)) and accounting must not depend on orders, so its own screen\n cannot even name a product. Rendering them from this side is what makes the pair\n something nobody has to type.\n -->\n <div class=\"mjo-acct-card\">\n <div class=\"mjo-card-body\">\n <bizapps-product-gl-links\n [Product]=\"Product\"\n [EditMode]=\"EditMode\"\n [FormContext]=\"FormContext\"\n (Navigate)=\"Navigate.emit($event)\">\n </bizapps-product-gl-links>\n </div>\n </div>\n</div>\n", styles: [".mjo-acct-widget-wrap {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-4, 16px);\n width: 100%;\n}\n\n.mjo-acct-card {\n background: var(--mj-bg-surface-card, rgba(255, 255, 255, 0.05));\n border: 1px solid var(--mj-border-default, rgba(255, 255, 255, 0.12));\n border-radius: var(--mj-radius-lg, 10px);\n overflow: hidden;\n}\n\n.mjo-card-head {\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken, rgba(0, 0, 0, 0.1));\n border-bottom: 1px solid var(--mj-border-default, rgba(255, 255, 255, 0.1));\n font-size: 13.5px;\n font-weight: 700;\n color: var(--mj-text-primary, #0f172a);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mjo-card-head i {\n color: var(--mj-brand-primary, #0284c7);\n}\n\n.mjo-card-body {\n padding: 16px;\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));\n gap: 16px;\n}\n"] }]
45
51
  }], null, { Product: [{
46
52
  type: Input
47
53
  }], EditMode: [{
@@ -1 +1 @@
1
- {"version":3,"file":"product-accounting-widget.component.js","sourceRoot":"","sources":["../../../../../src/lib/custom/Product/widgets/product-accounting-widget.component.ts","../../../../../src/lib/custom/Product/widgets/product-accounting-widget.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;;;AAIvE;;GAEG;AAOH,MAAM,OAAO,uCAAuC;IAChC,OAAO,CAAgC;IACvC,QAAQ,GAAG,KAAK,CAAC;IACjB,WAAW,CAAe;IAEzB,QAAQ,GAAG,IAAI,YAAY,EAAuB,CAAC;iIAL3D,uCAAuC;6DAAvC,uCAAuC;YCX5C,AADJ,AADJ,8BAAkC,aACH,aACI;YACvB,uBAA0C;YAC1C,4BAAM;YAAA,mEAAuD;YACjE,AADiE,iBAAO,EAClE;YAEF,AADJ,8BAA2B,uBAUtB;YADG,uIAAY,yBAAqB,IAAC;YACrC,iBAAgB;YACjB,wCAQC;YADG,uIAAY,yBAAqB,IAAC;YACrC,iBAAgB;YACjB,wCAQC;YADG,uIAAY,yBAAqB,IAAC;YACrC,iBAAgB;YACjB,yCAQC;YADG,wIAAY,yBAAqB,IAAC;YAIlD,AADI,AADI,AADK,iBAAgB,EACf,EACJ,EACJ;;YAtCU,eAAkB;YAKlB,AADA,AAHA,AADA,oCAAkB,mBACA,0BAGG,gCACM;YAK3B,cAAkB;YAKlB,AADA,AAHA,AADA,oCAAkB,mBACA,0BAGG,gCACM;YAI3B,cAAkB;YAKlB,AADA,AAHA,AADA,oCAAkB,mBACA,0BAGG,gCACM;YAI3B,cAAkB;YAKlB,AADA,AAHA,AADA,oCAAkB,mBACA,0BAGG,gCACM;;;iFD5B9B,uCAAuC;cANnD,SAAS;6BACM,KAAK,YACP,mCAAmC;;kBAK5C,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBAEL,MAAM;;kFALE,uCAAuC"}
1
+ {"version":3,"file":"product-accounting-widget.component.js","sourceRoot":"","sources":["../../../../../src/lib/custom/Product/widgets/product-accounting-widget.component.ts","../../../../../src/lib/custom/Product/widgets/product-accounting-widget.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;;;;AAIvE;;GAEG;AAOH,MAAM,OAAO,uCAAuC;IAChC,OAAO,CAAgC;IACvC,QAAQ,GAAG,KAAK,CAAC;IACjB,WAAW,CAAe;IAEzB,QAAQ,GAAG,IAAI,YAAY,EAAuB,CAAC;iIAL3D,uCAAuC;6DAAvC,uCAAuC;YCX5C,AADJ,AADJ,8BAAkC,aACH,aACI;YACvB,uBAA0C;YAC1C,4BAAM;YAAA,mEAAuD;YACjE,AADiE,iBAAO,EAClE;YAEF,AADJ,8BAA2B,uBAUtB;YADG,uIAAY,yBAAqB,IAAC;YACrC,iBAAgB;YACjB,wCAQC;YADG,uIAAY,yBAAqB,IAAC;YACrC,iBAAgB;YACjB,wCAQC;YADG,uIAAY,yBAAqB,IAAC;YACrC,iBAAgB;YACjB,yCAQC;YADG,wIAAY,yBAAqB,IAAC;YAG9C,AADI,AADK,iBAAgB,EACf,EACJ;YAaE,AADJ,AADJ,+BAA2B,cACI,mCAKgB;YAAnC,mJAAY,yBAAqB,IAAC;YAIlD,AADI,AADI,AADI,iBAA2B,EACzB,EACJ,EACJ;;YA1DU,eAAkB;YAKlB,AADA,AAHA,AADA,oCAAkB,mBACA,0BAGG,gCACM;YAK3B,cAAkB;YAKlB,AADA,AAHA,AADA,oCAAkB,mBACA,0BAGG,gCACM;YAI3B,cAAkB;YAKlB,AADA,AAHA,AADA,oCAAkB,mBACA,0BAGG,gCACM;YAI3B,cAAkB;YAKlB,AADA,AAHA,AADA,oCAAkB,mBACA,0BAGG,gCACM;YAkB3B,eAAmB;YAEnB,AADA,AADA,qCAAmB,0BACE,gCACM;;;iFDhD9B,uCAAuC;cANnD,SAAS;6BACM,KAAK,YACP,mCAAmC;;kBAK5C,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBAEL,MAAM;;kFALE,uCAAuC"}
@@ -0,0 +1,460 @@
1
+ import { ChangeDetectorRef, EventEmitter, OnDestroy, OnInit } from '@angular/core';
2
+ import type { FormContext, FormNavigationEvent } from '@memberjunction/ng-base-forms';
3
+ import type { mjBizAppsOrdersProductEntity } from '@mj-biz-apps/orders-entities';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * The only fields the in-force resolver reads.
7
+ *
8
+ * Structural on purpose: the links arrive either as accounting's generated entity objects (from the
9
+ * engine cache) or as plain view rows (from the fallback read), and those are different types that
10
+ * happen to carry the same five fields. Naming the fields rather than either concrete type is what
11
+ * lets one resolver serve both without a cast at each call site.
12
+ */
13
+ export interface GLLinkLike {
14
+ ID: unknown;
15
+ GLAccountID: unknown;
16
+ GLAccountRoleID: unknown;
17
+ Status: unknown;
18
+ StartedAt: unknown;
19
+ EndedAt: unknown;
20
+ }
21
+ /**
22
+ * May this GL account be offered for a product owned by `productCompanyID`?
23
+ *
24
+ * A named rule rather than an inline filter, because it decides whether a link the user creates will
25
+ * ever be reachable, and that deserves to be pinned by a test rather than reviewed by eye.
26
+ *
27
+ * An account belonging to another company is not offerable: `GLAccountResolver.Resolve` passes the
28
+ * order line's company down as `expectedCompanyID` and `AccountingBridge` filters candidates by the
29
+ * ACCOUNT's company before the window rules run, so such a link is silently SKIPPED at booking time
30
+ * rather than used. Dead configuration looks exactly like working configuration, which is why the
31
+ * panel must not be able to create it.
32
+ *
33
+ * A blank `productCompanyID` offers everything. `Product.CompanyID` is NOT NULL so this should not
34
+ * happen, but this runs in a browser against whatever the form holds; an empty picker would read as
35
+ * "no accounts exist" and give the user nothing to act on, where the unfiltered list is at worst what
36
+ * shipped before.
37
+ */
38
+ /**
39
+ * The comparable form of an id.
40
+ *
41
+ * Ids reach this component from two sources that disagree on case: the engine cache lowercases, while
42
+ * a direct view read returns SQL Server's uppercase `uniqueidentifier` rendering. Accounting's own
43
+ * engine routes every id comparison through the same normalisation for exactly this reason, and the
44
+ * audit caught the one comparison here that did not — it rendered both edit pickers blank and warned
45
+ * that a correctly-configured account was "not offered".
46
+ */
47
+ /**
48
+ * One entry in the GL-account picker.
49
+ *
50
+ * `Disabled` exists for exactly one case: a link that already points at an account this product's
51
+ * company cannot use. That option must be VISIBLE, so the select never renders blank on a link that
52
+ * has an account, and UNSELECTABLE, so the repair path cannot re-create the unreachable link.
53
+ */
54
+ export interface AccountOption {
55
+ ID: string;
56
+ Label: string;
57
+ Disabled?: boolean;
58
+ }
59
+ export declare function idKey(id: unknown): string;
60
+ export declare function AccountIsOfferable(accountCompanyID: string | null | undefined, productCompanyID: string | null | undefined): boolean;
61
+ /** One link, flattened for display. Nothing here is computed — every field is read off the row. */
62
+ export interface ProductGLLinkRow {
63
+ ID: string;
64
+ /**
65
+ * The role and account IDS, carried rather than re-derived.
66
+ *
67
+ * These used to be looked up when the Edit form opened — the role by matching `RoleName`, the
68
+ * account by finding the first picker label starting with the row's code. Both are wrong for the
69
+ * same reason: neither name nor code is unique. GL account codes REPEAT ACROSS COMPANIES by
70
+ * design — "40000 Sales" exists in every one of them — so the code search returned whichever
71
+ * company sorted first, and saving a not-yet-applied link wrote that arbitrary account.
72
+ *
73
+ * The ids are right here when the row is built. Carrying them removes the search, and with it the
74
+ * class of bug.
75
+ */
76
+ RoleID: string;
77
+ AccountID: string;
78
+ RoleName: string;
79
+ AccountCode: string;
80
+ AccountName: string;
81
+ Status: string;
82
+ StartedAt: string | null;
83
+ EndedAt: string | null;
84
+ /** True when this is the link that would actually be used today for its role. */
85
+ Active: boolean;
86
+ }
87
+ /**
88
+ * The GL accounts a product books to — read from the product's own form (bizapps-orders#113).
89
+ *
90
+ * ── WHY THIS LIVES IN ORDERS AND NOT IN ACCOUNTING ──
91
+ *
92
+ * `GLAccountLink` is accounting's entity, so the instinct is to put its UI there. Accounting's own
93
+ * links screen explains why that cannot work for products, in its `LinkRow` comment:
94
+ *
95
+ * > These links are POLYMORPHIC — `(EntityID, RecordID)` can point at anything, including orders'
96
+ * > Products and Product Categories. Accounting must not depend on orders, so those stay unnamed
97
+ * > here BY DESIGN.
98
+ *
99
+ * So on accounting's screen a product-linked row shows a bare UUID and says so honestly. Andrew's
100
+ * report (#113) is that same boundary seen from the other side: he could not find a product's accounts,
101
+ * and creating a link by hand meant copying the Product's ID into a text box.
102
+ *
103
+ * Rendering it HERE inverts the dependency the right way round. Orders already depends on accounting
104
+ * — `AccountingBridge` calls the engine on both booking paths — and orders is the app that knows what
105
+ * a Product is. The polymorphic pair stops being something a human types: `EntityID` is this app's
106
+ * Products entity and `RecordID` is the record already on screen.
107
+ *
108
+ * ── WHY THE ENGINE AND NOT A QUERY ──
109
+ *
110
+ * `AccountingEngineBase` caches roles, accounts and links client-side and is the same primitive the
111
+ * booking pipeline resolves through (`ResolveLinkedAccount`). Reading from it means this panel cannot
112
+ * disagree with what an order will actually book — a re-implemented query could, and the first time it
113
+ * did, the screen would be lying about money.
114
+ *
115
+ * ── WHAT IS DELIBERATELY NOT HERE ──
116
+ *
117
+ * No fallback chain. A product with no direct link still books, through category and company defaults,
118
+ * and `GlResolutionPreviewComponent` in accounting-ng already renders that chain. Showing a resolved
119
+ * account here without saying it came from a category would read as "this product is linked" when it is
120
+ * not, which is the same confusion #112 caused one screen over.
121
+ */
122
+ export declare class BizAppsProductGLLinksComponent implements OnInit, OnDestroy {
123
+ private readonly cdr;
124
+ Product: mjBizAppsOrdersProductEntity;
125
+ EditMode: boolean;
126
+ FormContext?: FormContext;
127
+ Navigate: EventEmitter<FormNavigationEvent>;
128
+ Rows: ProductGLLinkRow[];
129
+ Loading: boolean;
130
+ /** Set when the links cannot be read at all. Shown instead of an empty list, which would lie. */
131
+ LoadError: string | null;
132
+ constructor(cdr: ChangeDetectorRef);
133
+ ngOnInit(): Promise<void>;
134
+ /**
135
+ * Re-reads the links.
136
+ *
137
+ * ── WHY A WRITE MUST PASS `true` ──
138
+ *
139
+ * `load()` prefers the engine's cached links and only falls back to a view read when the cache
140
+ * holds none for this product. That is right for a plain refresh and WRONG straight after a write:
141
+ * the cache is a snapshot taken at `Config()` time, so a product that already had one link would
142
+ * keep showing exactly that one — the row just added, or the retirement just applied, would be
143
+ * invisible until something else reloaded the engine.
144
+ *
145
+ * It survived the first browser test only because that test started from a product with NO links,
146
+ * where the cache is empty and the fallback runs anyway. Adding a second link is the case that
147
+ * would have shown nothing.
148
+ *
149
+ * @param reloadEngine - force the accounting engine to re-read before rendering. Every write path
150
+ * defaults TRUE. `ngOnInit` passes false, because a first mount is the one
151
+ * place a cached answer is the right one; the refresh button and every write
152
+ * take the default, because both are asking the panel to go and look.
153
+ */
154
+ /**
155
+ * Set in `ngOnDestroy`, checked before every `detectChanges`.
156
+ *
157
+ * Every write ends with `finally { Saving = false; cdr.detectChanges(); }` AFTER an awaited save
158
+ * and engine reload. Navigate away mid-save and those resolve against a torn-down view, so
159
+ * `detectChanges` throws `ViewDestroyedError` — and because it throws from `finally`, the
160
+ * preceding `catch` cannot absorb it and it escapes as an unhandled rejection. This file's own
161
+ * comment elsewhere notes that a console error is treated as a broken screen by the Playwright
162
+ * keystone, so it would fail a suite rather than merely litter the console.
163
+ */
164
+ private destroyed;
165
+ ngOnDestroy(): void;
166
+ /** `detectChanges`, unless the view is gone. */
167
+ private tick;
168
+ /**
169
+ * `reloadEngine` DEFAULTS TRUE, and the default is the whole point.
170
+ *
171
+ * It used to default false, so the refresh icon re-ran `load()` against a cache nobody had
172
+ * invalidated — and `load()`'s own `Config(false, …)` is a no-op once the engine is loaded. A
173
+ * colleague retiring a link from accounting's own screen was therefore invisible here: the button
174
+ * rendered the identical stale row, still chipped "In force", for the rest of the session.
175
+ *
176
+ * A user who presses refresh is asking the panel to go and look. Writes already passed `true`
177
+ * explicitly; making that the default means the only path that can serve a cached answer is the
178
+ * initial load, which is the one place a cache is what you want.
179
+ */
180
+ Refresh(reloadEngine?: boolean): Promise<void>;
181
+ /**
182
+ * What the status chip says.
183
+ *
184
+ * The three states are NOT the two the `Status` column has. A link can be stored `Active` and still
185
+ * not be the one that books — superseded by a later link on the same role — and rendering the raw
186
+ * column would put the word "Active" on both rows. Saying SUPERSEDED is the whole reason this panel
187
+ * resolves through accounting's picker rather than reading a flag.
188
+ */
189
+ /**
190
+ * Why a row is not the one in force.
191
+ *
192
+ * `Active === false` has three causes and this used to print "Superseded" for all of them. A link
193
+ * added to take over next quarter therefore rendered as "Superseded" — it supersedes something, it
194
+ * is not superseded — beside a Remove button saying it had not started. Two controls in one row
195
+ * telling opposite stories is how a user concludes the save was rejected and adds another link.
196
+ */
197
+ StatusLabel(row: ProductGLLinkRow): string;
198
+ /**
199
+ * What Remove actually does to THIS row, said accurately.
200
+ *
201
+ * ── THE CONTROL USED TO ASSERT SOMETHING FALSE ────────────────────────────────────────────────
202
+ *
203
+ * Its title read "It has not started yet, so nothing has booked through it." That is true of a link
204
+ * dated in the future and FALSE of a link dated today, because `pickActiveLinkIndex` skips only
205
+ * when `t < started` — a link starting at today's UTC midnight is already the one resolution
206
+ * picks. `OpenDraft` defaults the start to today, so every link this panel creates spends its
207
+ * first UTC day in exactly that state: chip reading "In force", button promising nothing had
208
+ * booked, and `Delete()` behind it.
209
+ *
210
+ * The button stays, because it has to. `CK_GLAccountLink_Window` enforces `EndedAt > StartedAt`,
211
+ * so a link created today CANNOT be retired — Remove is the only way to undo a mistake made today.
212
+ * What was wrong was the sentence, not the affordance.
213
+ */
214
+ RemoveWarning(row: ProductGLLinkRow): string;
215
+ /** Opens accounting's Account Links screen, which is where a link is created or retired. */
216
+ OpenLink(row: ProductGLLinkRow): void;
217
+ /** Roles and accounts to choose from, filled by {@link Refresh} off the same engine the reader uses. */
218
+ Roles: Array<{
219
+ ID: string;
220
+ Name: string;
221
+ }>;
222
+ Accounts: AccountOption[];
223
+ /** The add form. Null when closed — opening it is a deliberate act, not the default state. */
224
+ Draft: {
225
+ RoleID: string;
226
+ AccountID: string;
227
+ StartedAt: string;
228
+ } | null;
229
+ /** Set when a write is refused. The SERVER's message, verbatim — see {@link AddLink}. */
230
+ WriteError: string | null;
231
+ Saving: boolean;
232
+ /** A product must exist before anything can point at it: `RecordID` is its primary key. */
233
+ get CanWrite(): boolean;
234
+ OpenDraft(): void;
235
+ CancelDraft(): void;
236
+ /**
237
+ * The link being edited, or null. `Applied` decides how much of it may change — see {@link OpenEdit}.
238
+ */
239
+ Editing: {
240
+ ID: string;
241
+ RoleID: string;
242
+ AccountID: string;
243
+ StartedAt: string;
244
+ EndedAt: string;
245
+ Applied: boolean;
246
+ } | null;
247
+ /**
248
+ * The options the EDIT picker shows: the company-scoped list, plus this link's CURRENT account when
249
+ * that account is not in it.
250
+ *
251
+ * ── WHY THE SCOPED LIST IS NOT ENOUGH ON ITS OWN ──────────────────────────────────────────────
252
+ *
253
+ * Scoping accounts to the product's company (PR #125 review) is right for CHOOSING, but a link that
254
+ * already points somewhere else still has to render. Such links exist: nothing stopped the panel
255
+ * creating them before this change, and nothing stops another tool creating one now. Showing only
256
+ * the scoped list would leave the select with no matching option — blank — on a link that plainly
257
+ * has an account.
258
+ *
259
+ * The template a few lines above already states the rule this would break: hiding a value "would
260
+ * read as 'this link has no account', which is the confusion #112 was". A filtered picker on an
261
+ * existing record must never hide that record's current value.
262
+ *
263
+ * The current account is labelled so the reader can tell it apart from the offerable ones, and the
264
+ * ordinary edit rules still apply — an applied link cannot change its account at all, and a
265
+ * not-yet-applied one can be moved onto a valid account, which is the repair path.
266
+ */
267
+ get EditAccounts(): ReadonlyArray<AccountOption>;
268
+ /**
269
+ * Frozen when the edit opens, NOT derived from the live `ngModel` value.
270
+ *
271
+ * Deriving it was wrong twice. It allocated a fresh array and object on every change-detection
272
+ * pass — the hazard this codebase already documents with its frozen-empty constant elsewhere — and,
273
+ * worse, the option deleted itself: the moment a user picked a valid account to repair a
274
+ * cross-company link, `current` matched the scoped list and the original option vanished, so they
275
+ * could neither compare the two nor change their mind without cancelling the whole edit.
276
+ */
277
+ private EditAccountOptions;
278
+ /**
279
+ * The role options for one edit, with the link's current role re-admitted when the engine has no
280
+ * such role.
281
+ *
282
+ * Accounts got this treatment and roles did not, which left the identical hole one field over. A
283
+ * link whose role is missing from the engine cache — deleted, or filtered out by row-level
284
+ * permissions — renders `(unknown role)` in the table, and the select then matched no option and
285
+ * rendered BLANK. Carrying `RoleID` on the row fixed the duplicate-name case only; it cannot put a
286
+ * matching `<option>` in a list that does not contain one.
287
+ *
288
+ * Disabled for the same reason as the account equivalent: visible so the picker never reads as
289
+ * "this link has no role", unselectable so a save cannot write an orphan id back.
290
+ */
291
+ get EditRoles(): ReadonlyArray<AccountOption>;
292
+ private EditRoleOptions;
293
+ private roleOptionsForEditing;
294
+ /** The options for one edit, with the link's current account re-admitted when it is not offerable. */
295
+ private optionsForEditing;
296
+ /**
297
+ * Opens an edit for one link.
298
+ *
299
+ * ── WHAT MAY CHANGE DEPENDS ON WHETHER IT HAS BOOKED ──
300
+ *
301
+ * #113 asks for "adding/editing/deleting" and editing has to exist. But a link is not an ordinary
302
+ * record: while it is in force it is the reason journal entries name the account they name. Letting
303
+ * someone re-point the account or move the start date on such a link would silently rewrite the
304
+ * explanation for money that has already moved, and nothing else records what the mapping used to
305
+ * be.
306
+ *
307
+ * So the split follows {@link HasApplied}, the same boundary Remove uses:
308
+ *
309
+ * · NOT applied yet — nothing has booked through it, so role, account and start date are all
310
+ * editable. This is the "I picked the wrong account a minute ago" case.
311
+ * · ALREADY applied — only the END date may change. That is a correction to when the mapping
312
+ * stopped, which is a statement about the future of a window rather than a rewrite of its past.
313
+ * To change where an applied product books, add a link with a later start; superseding is the
314
+ * accounting-correct edit and `pickActiveLinkIndex` already understands it.
315
+ */
316
+ OpenEdit(row: ProductGLLinkRow): void;
317
+ CancelEdit(): void;
318
+ /**
319
+ * Writes the edit.
320
+ *
321
+ * Only the fields the tier allows are assigned — the guard is here as well as in the template, so a
322
+ * stale render cannot rewrite an applied link's account by being clicked after the boundary moved.
323
+ * An empty end date clears it, which is how a retire applied by mistake is undone.
324
+ */
325
+ /**
326
+ * Has this link applied AS OF NOW — read from the LIVE row, never from the edit snapshot.
327
+ *
328
+ * `Editing.Applied` is captured when the form opens and the template reads the same captured
329
+ * value. That is fine for deciding what to RENDER, and wrong for deciding what to WRITE: a form
330
+ * opened at 23:59 on a link starting tomorrow is still open at 00:01, when the link has come into
331
+ * force. Trusting the snapshot there let a save rewrite the role, account and start date of a link
332
+ * that was by then explaining journal entries.
333
+ *
334
+ * A row that has vanished counts as APPLIED. The safe direction is refusing an edit that might
335
+ * have been allowed, not permitting one that rewrites history because the row could not be found.
336
+ */
337
+ private appliedNowFor;
338
+ SaveEdit(): Promise<void>;
339
+ /**
340
+ * `yyyy-MM-dd` for a date input, in UTC.
341
+ *
342
+ * The same conversion the sales workspace isolates in `deal-workspace.dates.ts`: an
343
+ * `<input type="date">` reads and writes strings while the field holds a Date, and handing an input
344
+ * a Date renders it BLANK with no error. UTC because the window is stored and displayed in UTC.
345
+ */
346
+ private asDateInput;
347
+ /**
348
+ * Creates the link.
349
+ *
350
+ * The polymorphic pair is NOT typed by a human, and that is the entire point of doing this here:
351
+ * `EntityID` is orders' Products entity and `RecordID` is the record already on screen. On
352
+ * accounting's own screen a person would have to paste the product's UUID into a text box, which is
353
+ * what #113 is reporting.
354
+ *
355
+ * ── THE REFUSAL IS SURFACED, NOT RE-IMPLEMENTED ──
356
+ *
357
+ * `GLAccountLinkEntityServer` refuses two ACTIVE links for the same (record, role) whose accounts
358
+ * share a company AND share a `StartedAt`, because the tie-break is a strict `>` and resolution
359
+ * would otherwise pick arbitrarily between two accounts that both balance. This does not restate
360
+ * that rule client-side: a copy would drift from it, and the copy would be the one that silently
361
+ * disagreed. It saves, and shows the server's own message when the server says no — which is also
362
+ * how the human learns that superseding means a LATER start date rather than a duplicate.
363
+ */
364
+ AddLink(): Promise<void>;
365
+ /**
366
+ * Whether a link can have explained any money yet.
367
+ *
368
+ * `pickActiveLinkIndex` treats a window as applying when `StartedAt <= now <= EndedAt`, so a link
369
+ * that starts TODAY OR LATER has not yet been the answer to any resolution. That is the boundary
370
+ * between the two destructive-looking actions below, and it is deliberately conservative: dated in
371
+ * the past means assume it booked something.
372
+ */
373
+ HasApplied(row: ProductGLLinkRow): boolean;
374
+ /**
375
+ * Ends a link's window, which is how accounting retires a mapping that has been in force.
376
+ *
377
+ * ── WHY THIS IS NOT A DELETE ──
378
+ *
379
+ * A GL link explains where money went. Deleting one that has already booked would remove the
380
+ * explanation for journal entries that still exist, and nothing else records which mapping was in
381
+ * force at the time. Ending the window keeps the history and stops the link applying.
382
+ *
383
+ * ── AND WHAT "TODAY" ACTUALLY MEANS HERE ──
384
+ *
385
+ * `EndedAt` is stored at MIDNIGHT UTC, and `pickActiveLinkIndex` excludes a link once `now > ended`.
386
+ * Midnight has already passed by the time anyone clicks, so retiring stops the link IMMEDIATELY
387
+ * rather than at the end of the day. Verified in the browser: a link dated 2020-01-01 retired on
388
+ * 2026-08-28 rendered as Superseded on the spot, not as still in force.
389
+ *
390
+ * This comment previously claimed the opposite — "applies for the whole of today and stops
391
+ * tomorrow" — and the button's tooltip said so too. The behaviour is the defensible one; the
392
+ * description was wrong, and it is the description that changed.
393
+ */
394
+ /**
395
+ * Closes an edit form that is bound to `id`.
396
+ *
397
+ * Retire and Remove used to leave it open, and the template only hides a row's EDIT button while
398
+ * that row is being edited — Retire and Remove stayed live. So the two orderings both corrupted:
399
+ * Retire then Save wrote `EndedAt = null` from the stale form and silently UN-RETIRED the link;
400
+ * Remove then Save threw "could not be re-read" on a record that no longer existed, which reads as
401
+ * a broken screen rather than "that record is gone".
402
+ */
403
+ private closeEditFor;
404
+ RetireLink(row: ProductGLLinkRow): Promise<void>;
405
+ /**
406
+ * Deletes a link that cannot have explained anything yet.
407
+ *
408
+ * ── WHY THIS EXISTS DESPITE THE ARGUMENT AGAINST DELETING ──
409
+ *
410
+ * Retiring is right for a mapping that has been in force. It is USELESS for one created by
411
+ * mistake a minute ago: the server refuses `EndedAt` on or before `StartedAt` ("The end date must
412
+ * be after the start date"), so a link mistyped today could be neither retired nor removed. That
413
+ * was a real hole — found by clicking Retire on a link the same test had just created.
414
+ *
415
+ * The boundary is {@link HasApplied}: a link starting today or later has never been the answer to
416
+ * a resolution, so deleting it destroys no explanation of anything. One that started earlier keeps
417
+ * the retire path and cannot be deleted from here at all.
418
+ */
419
+ RemoveLink(row: ProductGLLinkRow): Promise<void>;
420
+ /**
421
+ * The sentence a human should read out of a refused save.
422
+ *
423
+ * `CompleteMessage` can be a JSON blob of validation results — the retire failure arrived as
424
+ * `{"Source":"EndedAt","Message":"The end date must be after the start date.",...}`, and showing
425
+ * that verbatim buries the one sentence that matters inside punctuation. This pulls the `Message`
426
+ * out when it is there and falls back to the raw text when it is not, so nothing is ever swallowed.
427
+ */
428
+ private readableError;
429
+ /** Today in UTC as `yyyy-MM-dd` — the same zone the window is stored and rendered in. */
430
+ private today;
431
+ private load;
432
+ /** The view read, used only when the engine cache holds nothing for this product. */
433
+ private readDirect;
434
+ /**
435
+ * The ids of the links actually IN FORCE today — one per role at most, decided by accounting.
436
+ *
437
+ * ── WHY THIS IS NOT A WINDOW TEST ──
438
+ *
439
+ * The obvious implementation, and the one this replaced, asks of each link "is it Active and does
440
+ * today fall inside its window?" and marks every link that passes. That is wrong whenever a role
441
+ * has more than one qualifying link — a mapping being superseded while the old row is still open,
442
+ * which is exactly what an accountant does when they re-point a product mid-year. Both rows pass
443
+ * the window test, so the panel would show TWO active accounts for one role while an order books
444
+ * through exactly one of them. A screen that disagrees with the booking about where money lands is
445
+ * worse than no screen.
446
+ *
447
+ * `pickActiveLinkIndex` is accounting's own picker — the pure function behind
448
+ * `ResolveLinkedAccount`, exported by that package for precisely this kind of reuse. It applies the
449
+ * window AND the tie-break this panel has no business restating: latest `StartedAt` wins, and a
450
+ * null `StartedAt` loses to any dated one. Calling it means "active" here can only ever mean what
451
+ * the booking pipeline means.
452
+ *
453
+ * Grouped by ROLE because that is the unit the picker resolves: a product legitimately has a
454
+ * revenue link and a deferred-revenue link at once, and they do not compete.
455
+ */
456
+ private inForceIDs;
457
+ static ɵfac: i0.ɵɵFactoryDeclaration<BizAppsProductGLLinksComponent, never>;
458
+ static ɵcmp: i0.ɵɵComponentDeclaration<BizAppsProductGLLinksComponent, "bizapps-product-gl-links", never, { "Product": { "alias": "Product"; "required": false; }; "EditMode": { "alias": "EditMode"; "required": false; }; "FormContext": { "alias": "FormContext"; "required": false; }; }, { "Navigate": "Navigate"; }, never, never, false, never>;
459
+ }
460
+ //# sourceMappingURL=product-gl-links.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-gl-links.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/custom/Product/widgets/product-gl-links.component.ts"],"names":[],"mappings":"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"}