@mj-biz-apps/orders-ng 5.1.0 → 5.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.
Files changed (139) hide show
  1. package/dist/checkout-element/main.js +38080 -0
  2. package/dist/lib/checkout-widget/checkout-draft-line.d.ts +25 -0
  3. package/dist/lib/checkout-widget/checkout-draft-line.d.ts.map +1 -0
  4. package/dist/lib/checkout-widget/checkout-draft-line.js +46 -0
  5. package/dist/lib/checkout-widget/checkout-draft-line.js.map +1 -0
  6. package/dist/lib/checkout-widget/checkout-public-host.component.d.ts +80 -0
  7. package/dist/lib/checkout-widget/checkout-public-host.component.d.ts.map +1 -0
  8. package/dist/lib/checkout-widget/checkout-public-host.component.js +360 -0
  9. package/dist/lib/checkout-widget/checkout-public-host.component.js.map +1 -0
  10. package/dist/lib/checkout-widget/checkout-widget.component.d.ts +143 -0
  11. package/dist/lib/checkout-widget/checkout-widget.component.d.ts.map +1 -0
  12. package/dist/lib/checkout-widget/checkout-widget.component.js +873 -0
  13. package/dist/lib/checkout-widget/checkout-widget.component.js.map +1 -0
  14. package/dist/lib/custom/OrderHeader/order-header-form.component.d.ts +1 -0
  15. package/dist/lib/custom/OrderHeader/order-header-form.component.d.ts.map +1 -1
  16. package/dist/lib/custom/OrderHeader/order-header-form.component.js +10 -6
  17. package/dist/lib/custom/OrderHeader/order-header-form.component.js.map +1 -1
  18. package/dist/lib/custom/OrderHeader/order-lines-editor.component.d.ts +2 -0
  19. package/dist/lib/custom/OrderHeader/order-lines-editor.component.d.ts.map +1 -1
  20. package/dist/lib/custom/OrderHeader/order-lines-editor.component.js +37 -11
  21. package/dist/lib/custom/OrderHeader/order-lines-editor.component.js.map +1 -1
  22. package/dist/lib/form-panels/party-order-stats.js +2 -2
  23. package/dist/lib/form-panels/party-order-stats.js.map +1 -1
  24. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutSession/mjbizappsorderscheckoutsession.form.component.d.ts +10 -0
  25. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutSession/mjbizappsorderscheckoutsession.form.component.d.ts.map +1 -0
  26. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutSession/mjbizappsorderscheckoutsession.form.component.js +103 -0
  27. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutSession/mjbizappsorderscheckoutsession.form.component.js.map +1 -0
  28. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutWidget/mjbizappsorderscheckoutwidget.form.component.d.ts +10 -0
  29. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutWidget/mjbizappsorderscheckoutwidget.form.component.d.ts.map +1 -0
  30. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutWidget/mjbizappsorderscheckoutwidget.form.component.js +136 -0
  31. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutWidget/mjbizappsorderscheckoutwidget.form.component.js.map +1 -0
  32. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutWidgetDistribution/mjbizappsorderscheckoutwidgetdistribution.form.component.d.ts +10 -0
  33. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutWidgetDistribution/mjbizappsorderscheckoutwidgetdistribution.form.component.d.ts.map +1 -0
  34. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutWidgetDistribution/mjbizappsorderscheckoutwidgetdistribution.form.component.js +106 -0
  35. package/dist/lib/generated/Entities/mjBizAppsOrdersCheckoutWidgetDistribution/mjbizappsorderscheckoutwidgetdistribution.form.component.js.map +1 -0
  36. package/dist/lib/generated/Entities/mjBizAppsOrdersEventOrderLine/mjbizappsorderseventorderline.form.component.js +9 -9
  37. package/dist/lib/generated/Entities/mjBizAppsOrdersEventOrderLine/mjbizappsorderseventorderline.form.component.js.map +1 -1
  38. package/dist/lib/generated/Entities/mjBizAppsOrdersEventProduct/mjbizappsorderseventproduct.form.component.js +12 -12
  39. package/dist/lib/generated/Entities/mjBizAppsOrdersEventProduct/mjbizappsorderseventproduct.form.component.js.map +1 -1
  40. package/dist/lib/generated/Entities/mjBizAppsOrdersOrderCompanyPolicy/mjbizappsordersordercompanypolicy.form.component.d.ts.map +1 -1
  41. package/dist/lib/generated/Entities/mjBizAppsOrdersOrderCompanyPolicy/mjbizappsordersordercompanypolicy.form.component.js +16 -10
  42. package/dist/lib/generated/Entities/mjBizAppsOrdersOrderCompanyPolicy/mjbizappsordersordercompanypolicy.form.component.js.map +1 -1
  43. package/dist/lib/generated/Entities/mjBizAppsOrdersOrderHeader/mjbizappsordersorderheader.form.component.d.ts.map +1 -1
  44. package/dist/lib/generated/Entities/mjBizAppsOrdersOrderHeader/mjbizappsordersorderheader.form.component.js +78 -52
  45. package/dist/lib/generated/Entities/mjBizAppsOrdersOrderHeader/mjbizappsordersorderheader.form.component.js.map +1 -1
  46. package/dist/lib/generated/Entities/mjBizAppsOrdersOrderLine/mjbizappsordersorderline.form.component.d.ts.map +1 -1
  47. package/dist/lib/generated/Entities/mjBizAppsOrdersOrderLine/mjbizappsordersorderline.form.component.js +88 -82
  48. package/dist/lib/generated/Entities/mjBizAppsOrdersOrderLine/mjbizappsordersorderline.form.component.js.map +1 -1
  49. package/dist/lib/generated/Entities/mjBizAppsOrdersPaymentHeader/mjbizappsorderspaymentheader.form.component.js +3 -3
  50. package/dist/lib/generated/Entities/mjBizAppsOrdersPaymentHeader/mjbizappsorderspaymentheader.form.component.js.map +1 -1
  51. package/dist/lib/generated/Entities/mjBizAppsOrdersPaymentIntent/mjbizappsorderspaymentintent.form.component.d.ts.map +1 -1
  52. package/dist/lib/generated/Entities/mjBizAppsOrdersPaymentIntent/mjbizappsorderspaymentintent.form.component.js +23 -5
  53. package/dist/lib/generated/Entities/mjBizAppsOrdersPaymentIntent/mjbizappsorderspaymentintent.form.component.js.map +1 -1
  54. package/dist/lib/generated/Entities/mjBizAppsOrdersProduct/mjbizappsordersproduct.form.component.d.ts.map +1 -1
  55. package/dist/lib/generated/Entities/mjBizAppsOrdersProduct/mjbizappsordersproduct.form.component.js +75 -69
  56. package/dist/lib/generated/Entities/mjBizAppsOrdersProduct/mjbizappsordersproduct.form.component.js.map +1 -1
  57. package/dist/lib/generated/Entities/mjBizAppsOrdersProductCategory/mjbizappsordersproductcategory.form.component.d.ts.map +1 -1
  58. package/dist/lib/generated/Entities/mjBizAppsOrdersProductCategory/mjbizappsordersproductcategory.form.component.js +37 -31
  59. package/dist/lib/generated/Entities/mjBizAppsOrdersProductCategory/mjbizappsordersproductcategory.form.component.js.map +1 -1
  60. package/dist/lib/generated/Entities/mjBizAppsOrdersProductType/mjbizappsordersproducttype.form.component.d.ts.map +1 -1
  61. package/dist/lib/generated/Entities/mjBizAppsOrdersProductType/mjbizappsordersproducttype.form.component.js +24 -16
  62. package/dist/lib/generated/Entities/mjBizAppsOrdersProductType/mjbizappsordersproducttype.form.component.js.map +1 -1
  63. package/dist/lib/generated/generated-forms.module.d.ts +54 -51
  64. package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
  65. package/dist/lib/generated/generated-forms.module.js +27 -18
  66. package/dist/lib/generated/generated-forms.module.js.map +1 -1
  67. package/dist/lib/pages/catalog/pricing.page.d.ts +3 -24
  68. package/dist/lib/pages/catalog/pricing.page.d.ts.map +1 -1
  69. package/dist/lib/pages/catalog/pricing.page.js +158 -214
  70. package/dist/lib/pages/catalog/pricing.page.js.map +1 -1
  71. package/dist/lib/pages/catalog/products.page.d.ts +6 -29
  72. package/dist/lib/pages/catalog/products.page.d.ts.map +1 -1
  73. package/dist/lib/pages/catalog/products.page.js +255 -315
  74. package/dist/lib/pages/catalog/products.page.js.map +1 -1
  75. package/dist/lib/pages/orders/fulfillment.page.d.ts +14 -97
  76. package/dist/lib/pages/orders/fulfillment.page.d.ts.map +1 -1
  77. package/dist/lib/pages/orders/fulfillment.page.js +93 -258
  78. package/dist/lib/pages/orders/fulfillment.page.js.map +1 -1
  79. package/dist/lib/pages/orders/order-document.page.js +1 -1
  80. package/dist/lib/pages/orders/order-document.page.js.map +1 -1
  81. package/dist/lib/pages/orders/orders-dashboard.page.d.ts +29 -58
  82. package/dist/lib/pages/orders/orders-dashboard.page.d.ts.map +1 -1
  83. package/dist/lib/pages/orders/orders-dashboard.page.js +602 -352
  84. package/dist/lib/pages/orders/orders-dashboard.page.js.map +1 -1
  85. package/dist/lib/pages/orders/orders-list.page.d.ts +8 -58
  86. package/dist/lib/pages/orders/orders-list.page.d.ts.map +1 -1
  87. package/dist/lib/pages/orders/orders-list.page.js +52 -237
  88. package/dist/lib/pages/orders/orders-list.page.js.map +1 -1
  89. package/dist/lib/pages/payments/account-credit.page.d.ts +7 -17
  90. package/dist/lib/pages/payments/account-credit.page.d.ts.map +1 -1
  91. package/dist/lib/pages/payments/account-credit.page.js +99 -85
  92. package/dist/lib/pages/payments/account-credit.page.js.map +1 -1
  93. package/dist/lib/pages/payments/payments-dashboard.page.d.ts +4 -15
  94. package/dist/lib/pages/payments/payments-dashboard.page.d.ts.map +1 -1
  95. package/dist/lib/pages/payments/payments-dashboard.page.js +76 -111
  96. package/dist/lib/pages/payments/payments-dashboard.page.js.map +1 -1
  97. package/dist/lib/pages/payments/payments-list.page.d.ts +7 -41
  98. package/dist/lib/pages/payments/payments-list.page.d.ts.map +1 -1
  99. package/dist/lib/pages/payments/payments-list.page.js +51 -130
  100. package/dist/lib/pages/payments/payments-list.page.js.map +1 -1
  101. package/dist/lib/pages/receivables/customer-ar.page.d.ts +6 -8
  102. package/dist/lib/pages/receivables/customer-ar.page.d.ts.map +1 -1
  103. package/dist/lib/pages/receivables/customer-ar.page.js +112 -100
  104. package/dist/lib/pages/receivables/customer-ar.page.js.map +1 -1
  105. package/dist/lib/pages/receivables/overdue.page.d.ts +6 -3
  106. package/dist/lib/pages/receivables/overdue.page.d.ts.map +1 -1
  107. package/dist/lib/pages/receivables/overdue.page.js +61 -65
  108. package/dist/lib/pages/receivables/overdue.page.js.map +1 -1
  109. package/dist/lib/pages/receivables/subscriptions.page.d.ts +5 -9
  110. package/dist/lib/pages/receivables/subscriptions.page.d.ts.map +1 -1
  111. package/dist/lib/pages/receivables/subscriptions.page.js +139 -153
  112. package/dist/lib/pages/receivables/subscriptions.page.js.map +1 -1
  113. package/dist/lib/panels/order-stages.d.ts +12 -16
  114. package/dist/lib/panels/order-stages.d.ts.map +1 -1
  115. package/dist/lib/panels/order-stages.js +6 -42
  116. package/dist/lib/panels/order-stages.js.map +1 -1
  117. package/dist/lib/panels/party-orders-overview.component.d.ts +3 -1
  118. package/dist/lib/panels/party-orders-overview.component.d.ts.map +1 -1
  119. package/dist/lib/panels/party-orders-overview.component.js +18 -6
  120. package/dist/lib/panels/party-orders-overview.component.js.map +1 -1
  121. package/dist/lib/panels/status-stepper.component.d.ts +1 -1
  122. package/dist/lib/panels/status-stepper.component.d.ts.map +1 -1
  123. package/dist/lib/services/pricing-scheduler.service.d.ts +3 -4
  124. package/dist/lib/services/pricing-scheduler.service.d.ts.map +1 -1
  125. package/dist/lib/services/pricing-scheduler.service.js +3 -4
  126. package/dist/lib/services/pricing-scheduler.service.js.map +1 -1
  127. package/dist/public-api.d.ts +3 -2
  128. package/dist/public-api.d.ts.map +1 -1
  129. package/dist/public-api.js +3 -2
  130. package/dist/public-api.js.map +1 -1
  131. package/package.json +28 -16
  132. package/dist/lib/pages/orders/order-editor.page.d.ts +0 -547
  133. package/dist/lib/pages/orders/order-editor.page.d.ts.map +0 -1
  134. package/dist/lib/pages/orders/order-editor.page.js +0 -2269
  135. package/dist/lib/pages/orders/order-editor.page.js.map +0 -1
  136. package/dist/lib/pages/orders/order-workspace.page.d.ts +0 -120
  137. package/dist/lib/pages/orders/order-workspace.page.d.ts.map +0 -1
  138. package/dist/lib/pages/orders/order-workspace.page.js +0 -443
  139. package/dist/lib/pages/orders/order-workspace.page.js.map +0 -1
@@ -1,2269 +0,0 @@
1
- import { ChangeDetectorRef, Component, EventEmitter, HostListener, Input, Output, inject, } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { FormsModule } from '@angular/forms';
4
- import { OrderHeaderEntity } from '@mj-biz-apps/orders-entities';
5
- import { Metadata } from '@memberjunction/core';
6
- import { MJO_ENTITIES } from '../../data/entity-names.js';
7
- import { GetPaymentNumbers, GetLineDimensionsForOrder, GetOrderLines, GetOrders, GetPaymentLinesForOrder, JournalEntryViewParams, RecentCustomers, SearchCustomers, SubscriptionViewParams, WasTruncated } from '../../data/orders-queries.js';
8
- import { MJOPricingScheduler, } from '../../services/pricing-scheduler.service.js';
9
- import { MJOMoneyStripComponent } from '../../panels/money-strip.component.js';
10
- import { MJOStatusStepperComponent } from '../../panels/status-stepper.component.js';
11
- import { MJOJournalEntryPreviewComponent } from '../../panels/journal-entry-preview.component.js';
12
- import { MJODecompositionLadderComponent } from '../../panels/decomposition-ladder.component.js';
13
- import { MJOConsequenceChipComponent, MJOPriceSourceBadgeComponent, MJOStatedValueComponent, } from '../../panels/chips.component.js';
14
- import { MJOMoneyPipe, FormatDate, FormatMoney } from '../../panels/money-format.js';
15
- import { BuildOrderStages } from '../../panels/order-stages.js';
16
- import { MJButtonDirective, MJDropdownComponent, MJTabNavComponent } from '@memberjunction/ng-ui-components';
17
- // The MODULE, not the component: `mj-entity-data-grid` is declared (standalone: false), so a
18
- // standalone host imports its module. Same route accounting's generated forms take.
19
- import { EntityViewerModule } from '@memberjunction/ng-entity-viewer';
20
- import * as i0 from "@angular/core";
21
- import * as i1 from "@memberjunction/ng-entity-viewer";
22
- import * as i2 from "@angular/forms";
23
- const _c0 = () => ({ Sign: "absolute" });
24
- const _c1 = () => ({ Zero: "\u2014" });
25
- const _forTrack0 = ($index, $item) => $item.Code;
26
- const _forTrack1 = ($index, $item) => $item.ID;
27
- const _forTrack2 = ($index, $item) => $item["ID"];
28
- function MJOOrderEditorPageComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
29
- const _r1 = i0.ɵɵgetCurrentView();
30
- i0.ɵɵelementStart(0, "mj-dropdown", 21);
31
- i0.ɵɵlistener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_11_Template_mj_dropdown_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetOrderType($event)); });
32
- i0.ɵɵelementEnd();
33
- } if (rf & 2) {
34
- const ctx_r1 = i0.ɵɵnextContext();
35
- i0.ɵɵclassProp("ed-identity__input--default", ctx_r1.IsDefault("OrderType"));
36
- i0.ɵɵproperty("title", ctx_r1.IsDefault("OrderType") ? "Default \u2014 not chosen yet" : "")("Data", ctx_r1.OrderTypes)("ValuePrimitive", true)("ngModel", ctx_r1.Order.OrderType);
37
- } }
38
- function MJOOrderEditorPageComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
39
- i0.ɵɵelementStart(0, "span", 6);
40
- i0.ɵɵtext(1);
41
- i0.ɵɵelementEnd();
42
- } if (rf & 2) {
43
- const ctx_r1 = i0.ɵɵnextContext();
44
- i0.ɵɵadvance();
45
- i0.ɵɵtextInterpolate(ctx_r1.Order.OrderType);
46
- } }
47
- function MJOOrderEditorPageComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
48
- const _r3 = i0.ɵɵgetCurrentView();
49
- i0.ɵɵelementStart(0, "mj-dropdown", 22);
50
- i0.ɵɵlistener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_16_Template_mj_dropdown_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetOwningCompany($event)); });
51
- i0.ɵɵelementEnd();
52
- } if (rf & 2) {
53
- const ctx_r1 = i0.ɵɵnextContext();
54
- i0.ɵɵproperty("title", ctx_r1.OwningCompanyName)("Data", ctx_r1.Companies)("ValuePrimitive", true)("ngModel", ctx_r1.Order.CompanyID);
55
- } }
56
- function MJOOrderEditorPageComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
57
- i0.ɵɵelementStart(0, "span", 6);
58
- i0.ɵɵtext(1);
59
- i0.ɵɵelementEnd();
60
- } if (rf & 2) {
61
- const ctx_r1 = i0.ɵɵnextContext();
62
- i0.ɵɵadvance();
63
- i0.ɵɵtextInterpolate(ctx_r1.OwningCompanyName);
64
- } }
65
- function MJOOrderEditorPageComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
66
- const _r4 = i0.ɵɵgetCurrentView();
67
- i0.ɵɵelementStart(0, "input", 23);
68
- i0.ɵɵlistener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_21_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetHeaderField("OrderDate", $event)); });
69
- i0.ɵɵelementEnd();
70
- } if (rf & 2) {
71
- const ctx_r1 = i0.ɵɵnextContext();
72
- i0.ɵɵclassProp("ed-identity__input--default", ctx_r1.IsDefault("OrderDate"));
73
- i0.ɵɵproperty("title", ctx_r1.IsDefault("OrderDate") ? "Defaults to today \u2014 change it if the order was taken on another date" : "")("ngModel", ctx_r1.DateValue(ctx_r1.Order.OrderDate));
74
- } }
75
- function MJOOrderEditorPageComponent_Conditional_22_Template(rf, ctx) { if (rf & 1) {
76
- i0.ɵɵelementStart(0, "span", 6);
77
- i0.ɵɵtext(1);
78
- i0.ɵɵelementEnd();
79
- } if (rf & 2) {
80
- const ctx_r1 = i0.ɵɵnextContext();
81
- i0.ɵɵadvance();
82
- i0.ɵɵtextInterpolate(ctx_r1.DateValue(ctx_r1.Order.OrderDate));
83
- } }
84
- function MJOOrderEditorPageComponent_Conditional_26_Template(rf, ctx) { if (rf & 1) {
85
- const _r5 = i0.ɵɵgetCurrentView();
86
- i0.ɵɵelementStart(0, "input", 24);
87
- i0.ɵɵlistener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_26_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetHeaderField("DueDate", $event)); });
88
- i0.ɵɵelementEnd();
89
- } if (rf & 2) {
90
- const ctx_r1 = i0.ɵɵnextContext();
91
- i0.ɵɵproperty("ngModel", ctx_r1.DateValue(ctx_r1.Order.DueDate));
92
- } }
93
- function MJOOrderEditorPageComponent_Conditional_27_Template(rf, ctx) { if (rf & 1) {
94
- i0.ɵɵelementStart(0, "span", 6);
95
- i0.ɵɵtext(1);
96
- i0.ɵɵelementEnd();
97
- } if (rf & 2) {
98
- const ctx_r1 = i0.ɵɵnextContext();
99
- i0.ɵɵadvance();
100
- i0.ɵɵtextInterpolate(ctx_r1.Order.DueDate ?? "\u2014");
101
- } }
102
- function MJOOrderEditorPageComponent_Conditional_31_Template(rf, ctx) { if (rf & 1) {
103
- const _r6 = i0.ɵɵgetCurrentView();
104
- i0.ɵɵelementStart(0, "input", 25);
105
- i0.ɵɵlistener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_31_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetHeaderField("ExternalDocumentNumber", $event)); });
106
- i0.ɵɵelementEnd();
107
- } if (rf & 2) {
108
- const ctx_r1 = i0.ɵɵnextContext();
109
- i0.ɵɵproperty("ngModel", ctx_r1.Order.ExternalDocumentNumber ?? "");
110
- } }
111
- function MJOOrderEditorPageComponent_Conditional_32_Template(rf, ctx) { if (rf & 1) {
112
- i0.ɵɵelementStart(0, "span", 4);
113
- i0.ɵɵtext(1);
114
- i0.ɵɵelementEnd();
115
- } if (rf & 2) {
116
- const ctx_r1 = i0.ɵɵnextContext();
117
- i0.ɵɵadvance();
118
- i0.ɵɵtextInterpolate(ctx_r1.Order.ExternalDocumentNumber ?? "\u2014");
119
- } }
120
- function MJOOrderEditorPageComponent_Conditional_36_For_8_Template(rf, ctx) { if (rf & 1) {
121
- const _r7 = i0.ɵɵgetCurrentView();
122
- i0.ɵɵelementStart(0, "button", 31);
123
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_36_For_8_Template_button_click_0_listener() { const issue_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.GoToIssue(issue_r8.Section)); });
124
- i0.ɵɵtext(1);
125
- i0.ɵɵelementEnd();
126
- } if (rf & 2) {
127
- const issue_r8 = ctx.$implicit;
128
- const ctx_r1 = i0.ɵɵnextContext(2);
129
- i0.ɵɵproperty("title", "Go to " + ctx_r1.SectionLabel(issue_r8.Section));
130
- i0.ɵɵadvance();
131
- i0.ɵɵtextInterpolate1(" ", issue_r8.Message, " ");
132
- } }
133
- function MJOOrderEditorPageComponent_Conditional_36_Template(rf, ctx) { if (rf & 1) {
134
- i0.ɵɵelementStart(0, "div", 15);
135
- i0.ɵɵelement(1, "i", 26);
136
- i0.ɵɵelementStart(2, "span", 27);
137
- i0.ɵɵtext(3);
138
- i0.ɵɵelementEnd();
139
- i0.ɵɵelementStart(4, "span", 28);
140
- i0.ɵɵtext(5, "before you can confirm");
141
- i0.ɵɵelementEnd();
142
- i0.ɵɵelementStart(6, "span", 29);
143
- i0.ɵɵrepeaterCreate(7, MJOOrderEditorPageComponent_Conditional_36_For_8_Template, 2, 2, "button", 30, _forTrack0);
144
- i0.ɵɵelementEnd()();
145
- } if (rf & 2) {
146
- const ctx_r1 = i0.ɵɵnextContext();
147
- i0.ɵɵadvance(3);
148
- i0.ɵɵtextInterpolate(ctx_r1.Issues.length);
149
- i0.ɵɵadvance(4);
150
- i0.ɵɵrepeater(ctx_r1.Issues);
151
- } }
152
- function MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_4_For_2_Conditional_5_Template(rf, ctx) { if (rf & 1) {
153
- i0.ɵɵtext(0);
154
- } if (rf & 2) {
155
- const option_r11 = i0.ɵɵnextContext().$implicit;
156
- i0.ɵɵtextInterpolate1(" ", option_r11.SKU, " \u00B7 ");
157
- } }
158
- function MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
159
- const _r10 = i0.ɵɵgetCurrentView();
160
- i0.ɵɵelementStart(0, "li")(1, "button", 59);
161
- i0.ɵɵlistener("mousedown", function MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_4_For_2_Template_button_mousedown_1_listener() { const option_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.AddProduct(option_r11)); });
162
- i0.ɵɵelementStart(2, "span", 60);
163
- i0.ɵɵtext(3);
164
- i0.ɵɵelementEnd();
165
- i0.ɵɵelementStart(4, "span", 51);
166
- i0.ɵɵconditionalCreate(5, MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_4_For_2_Conditional_5_Template, 1, 1);
167
- i0.ɵɵtext(6);
168
- i0.ɵɵelementEnd();
169
- i0.ɵɵelementStart(7, "span", 61);
170
- i0.ɵɵtext(8);
171
- i0.ɵɵpipe(9, "mjoMoney");
172
- i0.ɵɵelementEnd()()();
173
- } if (rf & 2) {
174
- const option_r11 = ctx.$implicit;
175
- i0.ɵɵadvance(3);
176
- i0.ɵɵtextInterpolate(option_r11.Name);
177
- i0.ɵɵadvance(2);
178
- i0.ɵɵconditional(option_r11.SKU ? 5 : -1);
179
- i0.ɵɵadvance();
180
- i0.ɵɵtextInterpolate1(" ", option_r11.CompanyName, " ");
181
- i0.ɵɵadvance(2);
182
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(9, 4, option_r11.ListPrice));
183
- } }
184
- function MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
185
- i0.ɵɵelementStart(0, "ul", 57);
186
- i0.ɵɵrepeaterCreate(1, MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_4_For_2_Template, 10, 6, "li", null, _forTrack1);
187
- i0.ɵɵelementEnd();
188
- } if (rf & 2) {
189
- const ctx_r1 = i0.ɵɵnextContext(3);
190
- i0.ɵɵadvance();
191
- i0.ɵɵrepeater(ctx_r1.ProductMatches);
192
- } }
193
- function MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_5_Conditional_2_Template(rf, ctx) { if (rf & 1) {
194
- i0.ɵɵelementStart(0, "b");
195
- i0.ɵɵtext(1, "The catalogue list was capped, so this may exist beyond it.");
196
- i0.ɵɵelementEnd();
197
- } }
198
- function MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
199
- i0.ɵɵelementStart(0, "div", 58);
200
- i0.ɵɵtext(1);
201
- i0.ɵɵconditionalCreate(2, MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_5_Conditional_2_Template, 2, 0, "b");
202
- i0.ɵɵelementEnd();
203
- } if (rf & 2) {
204
- const ctx_r1 = i0.ɵɵnextContext(3);
205
- i0.ɵɵadvance();
206
- i0.ɵɵtextInterpolate1(" No catalogue match for \u201C", ctx_r1.ProductQuery, "\u201D. ");
207
- i0.ɵɵadvance();
208
- i0.ɵɵconditional(ctx_r1.CatalogTruncated ? 2 : -1);
209
- } }
210
- function MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Template(rf, ctx) { if (rf & 1) {
211
- const _r9 = i0.ɵɵgetCurrentView();
212
- i0.ɵɵelementStart(0, "div", 32)(1, "label", 54);
213
- i0.ɵɵelement(2, "i", 55);
214
- i0.ɵɵelementStart(3, "input", 56);
215
- i0.ɵɵlistener("focus", function MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Template_input_focus_3_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnProductFocus()); });
216
- i0.ɵɵtwoWayListener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Template_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.ProductQuery, $event) || (ctx_r1.ProductQuery = $event); return i0.ɵɵresetView($event); });
217
- i0.ɵɵlistener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Template_input_ngModelChange_3_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnProductQueryChange()); });
218
- i0.ɵɵelementEnd()();
219
- i0.ɵɵconditionalCreate(4, MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_4_Template, 3, 0, "ul", 57)(5, MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Conditional_5_Template, 3, 2, "div", 58);
220
- i0.ɵɵelementEnd();
221
- } if (rf & 2) {
222
- const ctx_r1 = i0.ɵɵnextContext(2);
223
- i0.ɵɵadvance(3);
224
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.ProductQuery);
225
- i0.ɵɵadvance();
226
- i0.ɵɵconditional(ctx_r1.ProductMatches.length ? 4 : ctx_r1.ProductQuery.trim().length >= 2 ? 5 : -1);
227
- } }
228
- function MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_10_Conditional_0_Template(rf, ctx) { if (rf & 1) {
229
- i0.ɵɵelementStart(0, "mjo-consequence-chip", 79);
230
- i0.ɵɵtext(1, "Ships");
231
- i0.ɵɵelementEnd();
232
- } }
233
- function MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_10_Conditional_1_Template(rf, ctx) { if (rf & 1) {
234
- i0.ɵɵelementStart(0, "mjo-consequence-chip", 80);
235
- i0.ɵɵtext(1, "Untaxable");
236
- i0.ɵɵelementEnd();
237
- } }
238
- function MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_10_Template(rf, ctx) { if (rf & 1) {
239
- i0.ɵɵconditionalCreate(0, MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_10_Conditional_0_Template, 2, 0, "mjo-consequence-chip", 79);
240
- i0.ɵɵconditionalCreate(1, MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_10_Conditional_1_Template, 2, 0, "mjo-consequence-chip", 80);
241
- } if (rf & 2) {
242
- const product_r14 = ctx;
243
- i0.ɵɵconditional(product_r14.TypeName === "Goods" ? 0 : -1);
244
- i0.ɵɵadvance();
245
- i0.ɵɵconditional(!product_r14.Taxable ? 1 : -1);
246
- } }
247
- function MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_19_Template(rf, ctx) { if (rf & 1) {
248
- i0.ɵɵelementStart(0, "div", 73);
249
- i0.ɵɵtext(1);
250
- i0.ɵɵelementEnd();
251
- } if (rf & 2) {
252
- i0.ɵɵadvance();
253
- i0.ɵɵtextInterpolate(ctx);
254
- } }
255
- function MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_21_Template(rf, ctx) { if (rf & 1) {
256
- i0.ɵɵelementStart(0, "span", 74);
257
- i0.ɵɵtext(1);
258
- i0.ɵɵpipe(2, "mjoMoney");
259
- i0.ɵɵelementEnd();
260
- } if (rf & 2) {
261
- i0.ɵɵadvance();
262
- i0.ɵɵtextInterpolate1("\u2212", i0.ɵɵpipeBind2(2, 1, ctx, i0.ɵɵpureFunction0(4, _c0)));
263
- } }
264
- function MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_22_Template(rf, ctx) { if (rf & 1) {
265
- i0.ɵɵelementStart(0, "span", 63);
266
- i0.ɵɵtext(1, "\u2014");
267
- i0.ɵɵelementEnd();
268
- } }
269
- function MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_31_Template(rf, ctx) { if (rf & 1) {
270
- const _r15 = i0.ɵɵgetCurrentView();
271
- i0.ɵɵelementStart(0, "button", 81);
272
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_31_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r15); const line_r13 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.Remove(line_r13)); });
273
- i0.ɵɵelement(1, "i", 82);
274
- i0.ɵɵelementEnd();
275
- } }
276
- function MJOOrderEditorPageComponent_Conditional_39_For_27_Template(rf, ctx) { if (rf & 1) {
277
- const _r12 = i0.ɵɵgetCurrentView();
278
- i0.ɵɵelementStart(0, "tr", 62);
279
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_39_For_27_Template_tr_click_0_listener() { const line_r13 = i0.ɵɵrestoreView(_r12).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.Open(line_r13)); });
280
- i0.ɵɵelementStart(1, "td", 63);
281
- i0.ɵɵtext(2);
282
- i0.ɵɵelementEnd();
283
- i0.ɵɵelementStart(3, "td")(4, "div", 64)(5, "span", 65);
284
- i0.ɵɵtext(6);
285
- i0.ɵɵelementEnd();
286
- i0.ɵɵelementStart(7, "span", 66);
287
- i0.ɵɵtext(8);
288
- i0.ɵɵelementEnd()();
289
- i0.ɵɵelementStart(9, "div", 67);
290
- i0.ɵɵconditionalCreate(10, MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_10_Template, 2, 2);
291
- i0.ɵɵelementEnd()();
292
- i0.ɵɵelementStart(11, "td")(12, "span", 68);
293
- i0.ɵɵtext(13);
294
- i0.ɵɵelementEnd()();
295
- i0.ɵɵelementStart(14, "td", 69);
296
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_39_For_27_Template_td_click_14_listener($event) { i0.ɵɵrestoreView(_r12); return i0.ɵɵresetView($event.stopPropagation()); });
297
- i0.ɵɵelementStart(15, "input", 70);
298
- i0.ɵɵlistener("change", function MJOOrderEditorPageComponent_Conditional_39_For_27_Template_input_change_15_listener($event) { const line_r13 = i0.ɵɵrestoreView(_r12).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SetQuantity(line_r13, $event.target.value)); });
299
- i0.ɵɵelementEnd()();
300
- i0.ɵɵelementStart(16, "td", 69);
301
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_39_For_27_Template_td_click_16_listener($event) { i0.ɵɵrestoreView(_r12); return i0.ɵɵresetView($event.stopPropagation()); });
302
- i0.ɵɵelementStart(17, "input", 71);
303
- i0.ɵɵlistener("change", function MJOOrderEditorPageComponent_Conditional_39_For_27_Template_input_change_17_listener($event) { const line_r13 = i0.ɵɵrestoreView(_r12).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SetUnitPrice(line_r13, $event.target.value)); });
304
- i0.ɵɵelementEnd();
305
- i0.ɵɵelement(18, "mjo-price-source-badge", 72);
306
- i0.ɵɵconditionalCreate(19, MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_19_Template, 2, 1, "div", 73);
307
- i0.ɵɵelementEnd();
308
- i0.ɵɵelementStart(20, "td", 61);
309
- i0.ɵɵconditionalCreate(21, MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_21_Template, 3, 5, "span", 74)(22, MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_22_Template, 2, 0, "span", 63);
310
- i0.ɵɵelementEnd();
311
- i0.ɵɵelementStart(23, "td", 75);
312
- i0.ɵɵtext(24);
313
- i0.ɵɵpipe(25, "mjoMoney");
314
- i0.ɵɵelementEnd();
315
- i0.ɵɵelementStart(26, "td", 76);
316
- i0.ɵɵtext(27, "\u2014");
317
- i0.ɵɵelementEnd();
318
- i0.ɵɵelementStart(28, "td", 76);
319
- i0.ɵɵtext(29, "\u2014");
320
- i0.ɵɵelementEnd();
321
- i0.ɵɵelementStart(30, "td", 77);
322
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_39_For_27_Template_td_click_30_listener($event) { i0.ɵɵrestoreView(_r12); return i0.ɵɵresetView($event.stopPropagation()); });
323
- i0.ɵɵconditionalCreate(31, MJOOrderEditorPageComponent_Conditional_39_For_27_Conditional_31_Template, 2, 0, "button", 78);
324
- i0.ɵɵelementEnd()();
325
- } if (rf & 2) {
326
- let tmp_13_0;
327
- let tmp_14_0;
328
- let tmp_15_0;
329
- let tmp_16_0;
330
- let tmp_19_0;
331
- let tmp_21_0;
332
- let tmp_24_0;
333
- let tmp_25_0;
334
- let tmp_26_0;
335
- const line_r13 = ctx.$implicit;
336
- const ɵ$index_181_r16 = ctx.$index;
337
- const ctx_r1 = i0.ɵɵnextContext(2);
338
- i0.ɵɵadvance(2);
339
- i0.ɵɵtextInterpolate(ɵ$index_181_r16 + 1);
340
- i0.ɵɵadvance(4);
341
- i0.ɵɵtextInterpolate(((tmp_13_0 = ctx_r1.ProductFor(line_r13)) == null ? null : tmp_13_0.Name) ?? "Product");
342
- i0.ɵɵadvance(2);
343
- i0.ɵɵtextInterpolate((tmp_14_0 = ctx_r1.ProductFor(line_r13)) == null ? null : tmp_14_0.SKU);
344
- i0.ɵɵadvance(2);
345
- i0.ɵɵconditional((tmp_15_0 = ctx_r1.ProductFor(line_r13)) ? 10 : -1, tmp_15_0);
346
- i0.ɵɵadvance(3);
347
- i0.ɵɵtextInterpolate(((tmp_16_0 = ctx_r1.ProductFor(line_r13)) == null ? null : tmp_16_0.CompanyName) ?? "\u2014");
348
- i0.ɵɵadvance(2);
349
- i0.ɵɵproperty("value", line_r13.Quantity)("disabled", !ctx_r1.IsEditable);
350
- i0.ɵɵadvance(2);
351
- i0.ɵɵproperty("value", ctx_r1.PriceStated(line_r13) ? line_r13.UnitPrice : ((tmp_19_0 = ctx_r1.PricedLine(line_r13)) == null ? null : tmp_19_0.UnitPrice) ?? "")("disabled", !ctx_r1.IsEditable);
352
- i0.ɵɵadvance();
353
- i0.ɵɵproperty("Source", ((tmp_21_0 = ctx_r1.PricedLine(line_r13)) == null ? null : tmp_21_0.PriceSource) ?? null)("Settled", ctx_r1.PricingSettled)("Overridden", ctx_r1.PriceStated(line_r13));
354
- i0.ɵɵadvance();
355
- i0.ɵɵconditional((tmp_24_0 = (tmp_24_0 = ctx_r1.PricedLine(line_r13)) == null ? null : tmp_24_0.Error) ? 19 : -1, tmp_24_0);
356
- i0.ɵɵadvance(2);
357
- i0.ɵɵconditional((tmp_25_0 = ctx_r1.DiscountAmount(line_r13)) ? 21 : 22, tmp_25_0);
358
- i0.ɵɵadvance(3);
359
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(25, 16, (tmp_26_0 = ctx_r1.PricedLine(line_r13)) == null ? null : tmp_26_0.NetAmount));
360
- i0.ɵɵadvance(7);
361
- i0.ɵɵconditional(ctx_r1.IsEditable ? 31 : -1);
362
- } }
363
- function MJOOrderEditorPageComponent_Conditional_39_ForEmpty_28_Template(rf, ctx) { if (rf & 1) {
364
- i0.ɵɵelementStart(0, "tr")(1, "td", 83)(2, "div", 84);
365
- i0.ɵɵelement(3, "i", 85);
366
- i0.ɵɵelementStart(4, "div", 86);
367
- i0.ɵɵtext(5, "No lines yet");
368
- i0.ɵɵelementEnd();
369
- i0.ɵɵelementStart(6, "div", 87);
370
- i0.ɵɵtext(7, "Search the catalogue above to add the first one.");
371
- i0.ɵɵelementEnd()()()();
372
- } }
373
- function MJOOrderEditorPageComponent_Conditional_39_Conditional_29_Conditional_4_Template(rf, ctx) { if (rf & 1) {
374
- i0.ɵɵelementStart(0, "span", 73);
375
- i0.ɵɵtext(1, "\u2014 some lines have no price, so this is short");
376
- i0.ɵɵelementEnd();
377
- } }
378
- function MJOOrderEditorPageComponent_Conditional_39_Conditional_29_Template(rf, ctx) { if (rf & 1) {
379
- i0.ɵɵelementStart(0, "tfoot")(1, "tr", 88)(2, "td", 89);
380
- i0.ɵɵtext(3, " Net before tax & charges ");
381
- i0.ɵɵconditionalCreate(4, MJOOrderEditorPageComponent_Conditional_39_Conditional_29_Conditional_4_Template, 2, 0, "span", 73);
382
- i0.ɵɵelementEnd();
383
- i0.ɵɵelementStart(5, "td", 61);
384
- i0.ɵɵtext(6);
385
- i0.ɵɵpipe(7, "mjoMoney");
386
- i0.ɵɵelementEnd();
387
- i0.ɵɵelementStart(8, "td", 90);
388
- i0.ɵɵtext(9, "\u2014");
389
- i0.ɵɵelementEnd();
390
- i0.ɵɵelementStart(10, "td", 90);
391
- i0.ɵɵtext(11, "\u2014");
392
- i0.ɵɵelementEnd();
393
- i0.ɵɵelement(12, "td");
394
- i0.ɵɵelementEnd()();
395
- } if (rf & 2) {
396
- const ctx_r1 = i0.ɵɵnextContext(2);
397
- i0.ɵɵadvance(4);
398
- i0.ɵɵconditional(ctx_r1.HasUnpricedLines ? 4 : -1);
399
- i0.ɵɵadvance(2);
400
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(7, 2, ctx_r1.Totals.NetTotal));
401
- } }
402
- function MJOOrderEditorPageComponent_Conditional_39_For_38_Template(rf, ctx) { if (rf & 1) {
403
- i0.ɵɵelementStart(0, "div", 50);
404
- i0.ɵɵelement(1, "i", 91);
405
- i0.ɵɵelementStart(2, "div", 92)(3, "div")(4, "b", 93);
406
- i0.ɵɵtext(5);
407
- i0.ɵɵelementEnd()();
408
- i0.ɵɵelementStart(6, "div", 87);
409
- i0.ɵɵtext(7, "Checked when the order is confirmed.");
410
- i0.ɵɵelementEnd()();
411
- i0.ɵɵelementStart(8, "span", 94);
412
- i0.ɵɵtext(9, "\u2014");
413
- i0.ɵɵelementEnd()();
414
- } if (rf & 2) {
415
- const code_r17 = ctx.$implicit;
416
- i0.ɵɵadvance(5);
417
- i0.ɵɵtextInterpolate(code_r17);
418
- } }
419
- function MJOOrderEditorPageComponent_Conditional_39_ForEmpty_39_Template(rf, ctx) { if (rf & 1) {
420
- i0.ɵɵelementStart(0, "div", 51);
421
- i0.ɵɵtext(1, "No promotion codes on this order.");
422
- i0.ɵɵelementEnd();
423
- } }
424
- function MJOOrderEditorPageComponent_Conditional_39_Template(rf, ctx) { if (rf & 1) {
425
- i0.ɵɵelementStart(0, "div", 18);
426
- i0.ɵɵconditionalCreate(1, MJOOrderEditorPageComponent_Conditional_39_Conditional_1_Template, 6, 2, "div", 32);
427
- i0.ɵɵelementStart(2, "div", 33)(3, "table", 34)(4, "thead")(5, "tr")(6, "th", 35);
428
- i0.ɵɵtext(7, "#");
429
- i0.ɵɵelementEnd();
430
- i0.ɵɵelementStart(8, "th");
431
- i0.ɵɵtext(9, "Product");
432
- i0.ɵɵelementEnd();
433
- i0.ɵɵelementStart(10, "th", 36);
434
- i0.ɵɵtext(11, "Co.");
435
- i0.ɵɵelementEnd();
436
- i0.ɵɵelementStart(12, "th", 37);
437
- i0.ɵɵtext(13, "Qty");
438
- i0.ɵɵelementEnd();
439
- i0.ɵɵelementStart(14, "th", 38);
440
- i0.ɵɵtext(15, "Unit price");
441
- i0.ɵɵelementEnd();
442
- i0.ɵɵelementStart(16, "th", 39);
443
- i0.ɵɵtext(17, "Discount");
444
- i0.ɵɵelementEnd();
445
- i0.ɵɵelementStart(18, "th", 40);
446
- i0.ɵɵtext(19, "Line net");
447
- i0.ɵɵelementEnd();
448
- i0.ɵɵelementStart(20, "th", 41);
449
- i0.ɵɵtext(21, "Tax");
450
- i0.ɵɵelementEnd();
451
- i0.ɵɵelementStart(22, "th", 42);
452
- i0.ɵɵtext(23, "Line total");
453
- i0.ɵɵelementEnd();
454
- i0.ɵɵelement(24, "th", 43);
455
- i0.ɵɵelementEnd()();
456
- i0.ɵɵelementStart(25, "tbody");
457
- i0.ɵɵrepeaterCreate(26, MJOOrderEditorPageComponent_Conditional_39_For_27_Template, 32, 18, "tr", 44, _forTrack1, false, MJOOrderEditorPageComponent_Conditional_39_ForEmpty_28_Template, 8, 0, "tr");
458
- i0.ɵɵelementEnd();
459
- i0.ɵɵconditionalCreate(29, MJOOrderEditorPageComponent_Conditional_39_Conditional_29_Template, 13, 4, "tfoot");
460
- i0.ɵɵelementEnd()();
461
- i0.ɵɵelementStart(30, "div", 45)(31, "div", 46)(32, "div", 47);
462
- i0.ɵɵelement(33, "i", 48);
463
- i0.ɵɵelementStart(34, "h3");
464
- i0.ɵɵtext(35, "Promotions");
465
- i0.ɵɵelementEnd()();
466
- i0.ɵɵelementStart(36, "div", 49);
467
- i0.ɵɵrepeaterCreate(37, MJOOrderEditorPageComponent_Conditional_39_For_38_Template, 10, 1, "div", 50, i0.ɵɵrepeaterTrackByIdentity, false, MJOOrderEditorPageComponent_Conditional_39_ForEmpty_39_Template, 2, 0, "div", 51);
468
- i0.ɵɵelementEnd()();
469
- i0.ɵɵelementStart(40, "div", 46)(41, "div", 47);
470
- i0.ɵɵelement(42, "i", 52);
471
- i0.ɵɵelementStart(43, "h3");
472
- i0.ɵɵtext(44, "Totals");
473
- i0.ɵɵelementEnd()();
474
- i0.ɵɵelementStart(45, "div", 49);
475
- i0.ɵɵelement(46, "mjo-decomposition-ladder", 53);
476
- i0.ɵɵelementEnd()()()();
477
- } if (rf & 2) {
478
- const ctx_r1 = i0.ɵɵnextContext();
479
- i0.ɵɵadvance();
480
- i0.ɵɵconditional(ctx_r1.IsEditable ? 1 : -1);
481
- i0.ɵɵadvance(25);
482
- i0.ɵɵrepeater(ctx_r1.Lines);
483
- i0.ɵɵadvance(3);
484
- i0.ɵɵconditional(ctx_r1.Totals ? 29 : -1);
485
- i0.ɵɵadvance(8);
486
- i0.ɵɵrepeater(ctx_r1.PromotionCodes);
487
- i0.ɵɵadvance(9);
488
- i0.ɵɵproperty("Rows", ctx_r1.LadderRows)("Stale", ctx_r1.Pricing.Loading);
489
- } }
490
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_14_Conditional_3_Template(rf, ctx) { if (rf & 1) {
491
- const _r18 = i0.ɵɵgetCurrentView();
492
- i0.ɵɵelementStart(0, "button", 107);
493
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_40_Conditional_14_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ClearParty("bill")); });
494
- i0.ɵɵelement(1, "i", 108);
495
- i0.ɵɵelementEnd();
496
- } }
497
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_14_Template(rf, ctx) { if (rf & 1) {
498
- i0.ɵɵelementStart(0, "div", 100)(1, "span", 105);
499
- i0.ɵɵtext(2);
500
- i0.ɵɵelementEnd();
501
- i0.ɵɵconditionalCreate(3, MJOOrderEditorPageComponent_Conditional_40_Conditional_14_Conditional_3_Template, 2, 0, "button", 106);
502
- i0.ɵɵelementEnd();
503
- } if (rf & 2) {
504
- const ctx_r1 = i0.ɵɵnextContext(2);
505
- i0.ɵɵadvance(2);
506
- i0.ɵɵtextInterpolate(ctx_r1.PartyLabels.bill ?? ctx);
507
- i0.ɵɵadvance();
508
- i0.ɵɵconditional(ctx_r1.IsEditable ? 3 : -1);
509
- } }
510
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Conditional_3_Template(rf, ctx) { if (rf & 1) {
511
- i0.ɵɵelementStart(0, "div", 51);
512
- i0.ɵɵtext(1, "Searching\u2026");
513
- i0.ɵɵelementEnd();
514
- } }
515
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Conditional_4_For_2_Conditional_5_Template(rf, ctx) { if (rf & 1) {
516
- i0.ɵɵelementStart(0, "span", 51);
517
- i0.ɵɵtext(1);
518
- i0.ɵɵelementEnd();
519
- } if (rf & 2) {
520
- const m_r21 = i0.ɵɵnextContext().$implicit;
521
- i0.ɵɵadvance();
522
- i0.ɵɵtextInterpolate(m_r21.Email);
523
- } }
524
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
525
- const _r20 = i0.ɵɵgetCurrentView();
526
- i0.ɵɵelementStart(0, "li")(1, "button", 112);
527
- i0.ɵɵlistener("mousedown", function MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Conditional_4_For_2_Template_button_mousedown_1_listener() { const m_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.ChooseParty("bill", m_r21)); });
528
- i0.ɵɵelement(2, "i", 113);
529
- i0.ɵɵelementStart(3, "span", 60);
530
- i0.ɵɵtext(4);
531
- i0.ɵɵelementEnd();
532
- i0.ɵɵconditionalCreate(5, MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Conditional_4_For_2_Conditional_5_Template, 2, 1, "span", 51);
533
- i0.ɵɵelementEnd()();
534
- } if (rf & 2) {
535
- const m_r21 = ctx.$implicit;
536
- i0.ɵɵadvance(2);
537
- i0.ɵɵclassMap(m_r21.IsOrganization ? "fa-solid fa-building" : "fa-solid fa-user");
538
- i0.ɵɵadvance(2);
539
- i0.ɵɵtextInterpolate(m_r21.Name);
540
- i0.ɵɵadvance();
541
- i0.ɵɵconditional(m_r21.Email ? 5 : -1);
542
- } }
543
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Conditional_4_Template(rf, ctx) { if (rf & 1) {
544
- i0.ɵɵelementStart(0, "ul", 111);
545
- i0.ɵɵrepeaterCreate(1, MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Conditional_4_For_2_Template, 6, 4, "li", null, _forTrack1);
546
- i0.ɵɵelementEnd();
547
- } if (rf & 2) {
548
- const ctx_r1 = i0.ɵɵnextContext(3);
549
- i0.ɵɵadvance();
550
- i0.ɵɵrepeater(ctx_r1.PartyMatches.bill);
551
- } }
552
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Template(rf, ctx) { if (rf & 1) {
553
- const _r19 = i0.ɵɵgetCurrentView();
554
- i0.ɵɵelementStart(0, "label", 109);
555
- i0.ɵɵelement(1, "i", 55);
556
- i0.ɵɵelementStart(2, "input", 110);
557
- i0.ɵɵtwoWayListener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Template_input_ngModelChange_2_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.PartyQuery.bill, $event) || (ctx_r1.PartyQuery.bill = $event); return i0.ɵɵresetView($event); });
558
- i0.ɵɵlistener("focus", function MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Template_input_focus_2_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnPartyFocus("bill")); })("ngModelChange", function MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Template_input_ngModelChange_2_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SearchParty("bill")); });
559
- i0.ɵɵelementEnd()();
560
- i0.ɵɵconditionalCreate(3, MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Conditional_3_Template, 2, 0, "div", 51)(4, MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Conditional_4_Template, 3, 0, "ul", 111);
561
- } if (rf & 2) {
562
- const ctx_r1 = i0.ɵɵnextContext(2);
563
- i0.ɵɵadvance(2);
564
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.PartyQuery.bill);
565
- i0.ɵɵadvance();
566
- i0.ɵɵconditional(ctx_r1.PartySearching === "bill" ? 3 : ctx_r1.PartyMatches.bill.length ? 4 : -1);
567
- } }
568
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_16_Template(rf, ctx) { if (rf & 1) {
569
- i0.ɵɵelementStart(0, "div", 51);
570
- i0.ɵɵtext(1, "\u2014 none \u2014");
571
- i0.ɵɵelementEnd();
572
- } }
573
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_33_Conditional_3_Template(rf, ctx) { if (rf & 1) {
574
- const _r22 = i0.ɵɵgetCurrentView();
575
- i0.ɵɵelementStart(0, "button", 115);
576
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_40_Conditional_33_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r22); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ClearParty("ship")); });
577
- i0.ɵɵelement(1, "i", 108);
578
- i0.ɵɵelementEnd();
579
- } }
580
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_33_Template(rf, ctx) { if (rf & 1) {
581
- i0.ɵɵelementStart(0, "div", 100)(1, "span", 105);
582
- i0.ɵɵtext(2);
583
- i0.ɵɵelementEnd();
584
- i0.ɵɵconditionalCreate(3, MJOOrderEditorPageComponent_Conditional_40_Conditional_33_Conditional_3_Template, 2, 0, "button", 114);
585
- i0.ɵɵelementEnd();
586
- } if (rf & 2) {
587
- const ctx_r1 = i0.ɵɵnextContext(2);
588
- i0.ɵɵadvance(2);
589
- i0.ɵɵtextInterpolate(ctx_r1.PartyLabels.ship ?? ctx);
590
- i0.ɵɵadvance();
591
- i0.ɵɵconditional(ctx_r1.IsEditable ? 3 : -1);
592
- } }
593
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Conditional_3_Template(rf, ctx) { if (rf & 1) {
594
- i0.ɵɵelementStart(0, "div", 51);
595
- i0.ɵɵtext(1, "Searching\u2026");
596
- i0.ɵɵelementEnd();
597
- } }
598
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Conditional_4_For_2_Conditional_5_Template(rf, ctx) { if (rf & 1) {
599
- i0.ɵɵelementStart(0, "span", 51);
600
- i0.ɵɵtext(1);
601
- i0.ɵɵelementEnd();
602
- } if (rf & 2) {
603
- const m_r25 = i0.ɵɵnextContext().$implicit;
604
- i0.ɵɵadvance();
605
- i0.ɵɵtextInterpolate(m_r25.Email);
606
- } }
607
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
608
- const _r24 = i0.ɵɵgetCurrentView();
609
- i0.ɵɵelementStart(0, "li")(1, "button", 112);
610
- i0.ɵɵlistener("mousedown", function MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Conditional_4_For_2_Template_button_mousedown_1_listener() { const m_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.ChooseParty("ship", m_r25)); });
611
- i0.ɵɵelement(2, "i", 113);
612
- i0.ɵɵelementStart(3, "span", 60);
613
- i0.ɵɵtext(4);
614
- i0.ɵɵelementEnd();
615
- i0.ɵɵconditionalCreate(5, MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Conditional_4_For_2_Conditional_5_Template, 2, 1, "span", 51);
616
- i0.ɵɵelementEnd()();
617
- } if (rf & 2) {
618
- const m_r25 = ctx.$implicit;
619
- i0.ɵɵadvance(2);
620
- i0.ɵɵclassMap(m_r25.IsOrganization ? "fa-solid fa-building" : "fa-solid fa-user");
621
- i0.ɵɵadvance(2);
622
- i0.ɵɵtextInterpolate(m_r25.Name);
623
- i0.ɵɵadvance();
624
- i0.ɵɵconditional(m_r25.Email ? 5 : -1);
625
- } }
626
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Conditional_4_Template(rf, ctx) { if (rf & 1) {
627
- i0.ɵɵelementStart(0, "ul", 111);
628
- i0.ɵɵrepeaterCreate(1, MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Conditional_4_For_2_Template, 6, 4, "li", null, _forTrack1);
629
- i0.ɵɵelementEnd();
630
- } if (rf & 2) {
631
- const ctx_r1 = i0.ɵɵnextContext(3);
632
- i0.ɵɵadvance();
633
- i0.ɵɵrepeater(ctx_r1.PartyMatches.ship);
634
- } }
635
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Template(rf, ctx) { if (rf & 1) {
636
- const _r23 = i0.ɵɵgetCurrentView();
637
- i0.ɵɵelementStart(0, "label", 109);
638
- i0.ɵɵelement(1, "i", 55);
639
- i0.ɵɵelementStart(2, "input", 116);
640
- i0.ɵɵtwoWayListener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Template_input_ngModelChange_2_listener($event) { i0.ɵɵrestoreView(_r23); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.PartyQuery.ship, $event) || (ctx_r1.PartyQuery.ship = $event); return i0.ɵɵresetView($event); });
641
- i0.ɵɵlistener("focus", function MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Template_input_focus_2_listener() { i0.ɵɵrestoreView(_r23); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnPartyFocus("ship")); })("ngModelChange", function MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Template_input_ngModelChange_2_listener() { i0.ɵɵrestoreView(_r23); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SearchParty("ship")); });
642
- i0.ɵɵelementEnd()();
643
- i0.ɵɵconditionalCreate(3, MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Conditional_3_Template, 2, 0, "div", 51)(4, MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Conditional_4_Template, 3, 0, "ul", 111);
644
- } if (rf & 2) {
645
- const ctx_r1 = i0.ɵɵnextContext(2);
646
- i0.ɵɵadvance(2);
647
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.PartyQuery.ship);
648
- i0.ɵɵadvance();
649
- i0.ɵɵconditional(ctx_r1.PartySearching === "ship" ? 3 : ctx_r1.PartyMatches.ship.length ? 4 : -1);
650
- } }
651
- function MJOOrderEditorPageComponent_Conditional_40_Conditional_35_Template(rf, ctx) { if (rf & 1) {
652
- i0.ɵɵelementStart(0, "div", 51);
653
- i0.ɵɵtext(1, "\u2014 none \u2014");
654
- i0.ɵɵelementEnd();
655
- } }
656
- function MJOOrderEditorPageComponent_Conditional_40_Template(rf, ctx) { if (rf & 1) {
657
- i0.ɵɵelementStart(0, "div", 18)(1, "div", 95)(2, "div", 46)(3, "div", 47);
658
- i0.ɵɵelement(4, "i", 96);
659
- i0.ɵɵelementStart(5, "h3");
660
- i0.ɵɵtext(6, "Bill to \u2014 who pays");
661
- i0.ɵɵelementEnd();
662
- i0.ɵɵelementStart(7, "span", 97)(8, "span", 68);
663
- i0.ɵɵtext(9, "header only");
664
- i0.ɵɵelementEnd()()();
665
- i0.ɵɵelementStart(10, "div", 49)(11, "div", 98)(12, "div", 99);
666
- i0.ɵɵtext(13, "Customer");
667
- i0.ɵɵelementEnd();
668
- i0.ɵɵconditionalCreate(14, MJOOrderEditorPageComponent_Conditional_40_Conditional_14_Template, 4, 2, "div", 100)(15, MJOOrderEditorPageComponent_Conditional_40_Conditional_15_Template, 5, 2)(16, MJOOrderEditorPageComponent_Conditional_40_Conditional_16_Template, 2, 0, "div", 51);
669
- i0.ɵɵelementEnd();
670
- i0.ɵɵelementStart(17, "mjo-stated-value", 101);
671
- i0.ɵɵtext(18);
672
- i0.ɵɵelementEnd();
673
- i0.ɵɵelementStart(19, "div", 102);
674
- i0.ɵɵtext(20, " Bill-to is header-only: one order, one payer, one bill. That is why there is no line-level counterpart to it. ");
675
- i0.ɵɵelementEnd()()();
676
- i0.ɵɵelementStart(21, "div", 46)(22, "div", 47);
677
- i0.ɵɵelement(23, "i", 103);
678
- i0.ɵɵelementStart(24, "h3");
679
- i0.ɵɵtext(25, "Ship to \u2014 who receives");
680
- i0.ɵɵelementEnd();
681
- i0.ɵɵelementStart(26, "span", 97)(27, "span", 68);
682
- i0.ɵɵtext(28, "line default");
683
- i0.ɵɵelementEnd()()();
684
- i0.ɵɵelementStart(29, "div", 49)(30, "div", 98)(31, "div", 99);
685
- i0.ɵɵtext(32, "Recipient");
686
- i0.ɵɵelementEnd();
687
- i0.ɵɵconditionalCreate(33, MJOOrderEditorPageComponent_Conditional_40_Conditional_33_Template, 4, 2, "div", 100)(34, MJOOrderEditorPageComponent_Conditional_40_Conditional_34_Template, 5, 2)(35, MJOOrderEditorPageComponent_Conditional_40_Conditional_35_Template, 2, 0, "div", 51);
688
- i0.ɵɵelementEnd();
689
- i0.ɵɵelementStart(36, "mjo-stated-value", 104);
690
- i0.ɵɵtext(37);
691
- i0.ɵɵelementEnd();
692
- i0.ɵɵelementStart(38, "div", 102);
693
- i0.ɵɵtext(39, " Each side falls back ");
694
- i0.ɵɵelementStart(40, "b");
695
- i0.ɵɵtext(41, "independently");
696
- i0.ɵɵelementEnd();
697
- i0.ɵɵtext(42, ", so a line naming only a person keeps the header's organization. For an intangible there is nothing to ship, and the same fields say who the line is ");
698
- i0.ɵɵelementStart(43, "i");
699
- i0.ɵɵtext(44, "for");
700
- i0.ɵɵelementEnd();
701
- i0.ɵɵtext(45, ". ");
702
- i0.ɵɵelementEnd()()()()();
703
- } if (rf & 2) {
704
- let tmp_1_0;
705
- let tmp_3_0;
706
- const ctx_r1 = i0.ɵɵnextContext();
707
- i0.ɵɵadvance(14);
708
- i0.ɵɵconditional((tmp_1_0 = ctx_r1.PartyIdFor("bill")) ? 14 : ctx_r1.IsEditable ? 15 : 16, tmp_1_0);
709
- i0.ɵɵadvance(4);
710
- i0.ɵɵtextInterpolate1(" ", ctx_r1.Order.PaymentTermsTypeID ?? "\u2014 default \u2014", " ");
711
- i0.ɵɵadvance(15);
712
- i0.ɵɵconditional((tmp_3_0 = ctx_r1.PartyIdFor("ship")) ? 33 : ctx_r1.IsEditable ? 34 : 35, tmp_3_0);
713
- i0.ɵɵadvance(4);
714
- i0.ɵɵtextInterpolate1(" ", ctx_r1.Order.ShipToAddressID ?? "\u2014 none \u2014", " ");
715
- } }
716
- function MJOOrderEditorPageComponent_Conditional_41_Conditional_7_Template(rf, ctx) { if (rf & 1) {
717
- i0.ɵɵelementStart(0, "div", 102);
718
- i0.ɵɵtext(1, " This order is confirmed \u2014 its charges and tax are on the entries under ");
719
- i0.ɵɵelementStart(2, "b");
720
- i0.ɵɵtext(3, "Accounting");
721
- i0.ɵɵelementEnd();
722
- i0.ɵɵtext(4, ". ");
723
- i0.ɵɵelementEnd();
724
- } }
725
- function MJOOrderEditorPageComponent_Conditional_41_Template(rf, ctx) { if (rf & 1) {
726
- i0.ɵɵelementStart(0, "div", 18)(1, "div", 117);
727
- i0.ɵɵelement(2, "i", 118);
728
- i0.ɵɵelementStart(3, "div", 86);
729
- i0.ɵɵtext(4, "Not available yet");
730
- i0.ɵɵelementEnd();
731
- i0.ɵɵelementStart(5, "div", 87);
732
- i0.ɵɵtext(6, " Charges and tax are decided when the order is confirmed. The Lines tab shows the net subtotal before them. ");
733
- i0.ɵɵelementEnd()();
734
- i0.ɵɵconditionalCreate(7, MJOOrderEditorPageComponent_Conditional_41_Conditional_7_Template, 5, 0, "div", 102);
735
- i0.ɵɵelementEnd();
736
- } if (rf & 2) {
737
- const ctx_r1 = i0.ɵɵnextContext();
738
- i0.ɵɵadvance(7);
739
- i0.ɵɵconditional(ctx_r1.JournalEntries.length ? 7 : -1);
740
- } }
741
- function MJOOrderEditorPageComponent_Conditional_42_Conditional_10_Conditional_4_Template(rf, ctx) { if (rf & 1) {
742
- const _r27 = i0.ɵɵgetCurrentView();
743
- i0.ɵɵelementStart(0, "div", 132)(1, "label", 133);
744
- i0.ɵɵtext(2);
745
- i0.ɵɵelementStart(3, "span", 134);
746
- i0.ɵɵtext(4, "required");
747
- i0.ɵɵelementEnd()();
748
- i0.ɵɵelementStart(5, "input", 135);
749
- i0.ɵɵlistener("input", function MJOOrderEditorPageComponent_Conditional_42_Conditional_10_Conditional_4_Template_input_input_5_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.SetReference($event.target.value)); });
750
- i0.ɵɵelementEnd();
751
- i0.ɵɵelementStart(6, "div", 136);
752
- i0.ɵɵtext(7, " Recorded on the payment so it can be matched to the bank statement. ");
753
- i0.ɵɵelementEnd()();
754
- } if (rf & 2) {
755
- const ctx_r1 = i0.ɵɵnextContext(3);
756
- i0.ɵɵadvance(2);
757
- i0.ɵɵtextInterpolate1(" ", ctx_r1.SelectedTenderType == null ? null : ctx_r1.SelectedTenderType.Name, " number ");
758
- i0.ɵɵadvance(3);
759
- i0.ɵɵproperty("value", ctx_r1.Reference)("placeholder", (ctx_r1.SelectedTenderType == null ? null : ctx_r1.SelectedTenderType.Code) === "Check" ? "e.g. 10428" : "confirmation or transfer id");
760
- i0.ɵɵattribute("aria-invalid", !ctx_r1.Reference.trim());
761
- } }
762
- function MJOOrderEditorPageComponent_Conditional_42_Conditional_10_Conditional_5_Template(rf, ctx) { if (rf & 1) {
763
- const _r28 = i0.ɵɵgetCurrentView();
764
- i0.ɵɵelementStart(0, "div", 129)(1, "label", 137);
765
- i0.ɵɵtext(2, "Amount");
766
- i0.ɵɵelementEnd();
767
- i0.ɵɵelementStart(3, "div", 138)(4, "input", 139);
768
- i0.ɵɵlistener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_42_Conditional_10_Conditional_5_Template_input_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.SetInitialAmount($event)); });
769
- i0.ɵɵelementEnd();
770
- i0.ɵɵelementStart(5, "button", 140);
771
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_42_Conditional_10_Conditional_5_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.PayInFull()); });
772
- i0.ɵɵtext(6, " Pay in full ");
773
- i0.ɵɵelementEnd()()();
774
- } if (rf & 2) {
775
- const ctx_r1 = i0.ɵɵnextContext(3);
776
- i0.ɵɵadvance(4);
777
- i0.ɵɵproperty("ngModel", ctx_r1.Order.InitialPaymentAmount);
778
- } }
779
- function MJOOrderEditorPageComponent_Conditional_42_Conditional_10_Template(rf, ctx) { if (rf & 1) {
780
- const _r26 = i0.ɵɵgetCurrentView();
781
- i0.ɵɵelementStart(0, "div", 129)(1, "label", 130);
782
- i0.ɵɵtext(2, "Tender");
783
- i0.ɵɵelementEnd();
784
- i0.ɵɵelementStart(3, "mj-dropdown", 131);
785
- i0.ɵɵlistener("ngModelChange", function MJOOrderEditorPageComponent_Conditional_42_Conditional_10_Template_mj_dropdown_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SetTender($event)); });
786
- i0.ɵɵelementEnd();
787
- i0.ɵɵconditionalCreate(4, MJOOrderEditorPageComponent_Conditional_42_Conditional_10_Conditional_4_Template, 8, 4, "div", 132);
788
- i0.ɵɵelementEnd();
789
- i0.ɵɵconditionalCreate(5, MJOOrderEditorPageComponent_Conditional_42_Conditional_10_Conditional_5_Template, 7, 1, "div", 129);
790
- } if (rf & 2) {
791
- const ctx_r1 = i0.ɵɵnextContext(2);
792
- i0.ɵɵadvance(3);
793
- i0.ɵɵproperty("Data", ctx_r1.Tenders)("ValuePrimitive", true)("DefaultItem", ctx_r1.TenderNone)("ngModel", ctx_r1.Order.InitialPaymentTypeID ?? "");
794
- i0.ɵɵadvance();
795
- i0.ɵɵconditional(ctx_r1.RequiresReference ? 4 : -1);
796
- i0.ɵɵadvance();
797
- i0.ɵɵconditional(ctx_r1.Order.InitialPaymentTypeID ? 5 : -1);
798
- } }
799
- function MJOOrderEditorPageComponent_Conditional_42_Conditional_11_Template(rf, ctx) { if (rf & 1) {
800
- i0.ɵɵelementStart(0, "mjo-stated-value", 141);
801
- i0.ɵɵtext(1);
802
- i0.ɵɵelementEnd();
803
- i0.ɵɵelementStart(2, "mjo-stated-value", 142);
804
- i0.ɵɵtext(3);
805
- i0.ɵɵpipe(4, "mjoMoney");
806
- i0.ɵɵelementEnd();
807
- } if (rf & 2) {
808
- const ctx_r1 = i0.ɵɵnextContext(2);
809
- i0.ɵɵadvance();
810
- i0.ɵɵtextInterpolate1(" ", (ctx_r1.SelectedTenderType == null ? null : ctx_r1.SelectedTenderType.Name) ?? "\u2014 invoice on terms \u2014", " ");
811
- i0.ɵɵadvance(2);
812
- i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind2(4, 2, ctx_r1.Order.InitialPaymentAmount, i0.ɵɵpureFunction0(5, _c1)), " ");
813
- } }
814
- function MJOOrderEditorPageComponent_Conditional_42_For_41_Template(rf, ctx) { if (rf & 1) {
815
- i0.ɵɵelementStart(0, "tr")(1, "td", 143);
816
- i0.ɵɵtext(2);
817
- i0.ɵɵelementEnd();
818
- i0.ɵɵelementStart(3, "td", 51);
819
- i0.ɵɵtext(4);
820
- i0.ɵɵelementEnd();
821
- i0.ɵɵelementStart(5, "td", 61);
822
- i0.ɵɵtext(6);
823
- i0.ɵɵelementEnd()();
824
- } if (rf & 2) {
825
- const line_r29 = ctx.$implicit;
826
- const ctx_r1 = i0.ɵɵnextContext(2);
827
- i0.ɵɵadvance(2);
828
- i0.ɵɵtextInterpolate(ctx_r1.PaymentNumberOf(line_r29));
829
- i0.ɵɵadvance(2);
830
- i0.ɵɵtextInterpolate(ctx_r1.dateOf(line_r29.AllocatedAt));
831
- i0.ɵɵadvance(2);
832
- i0.ɵɵtextInterpolate(ctx_r1.moneyOf(line_r29.Amount));
833
- } }
834
- function MJOOrderEditorPageComponent_Conditional_42_ForEmpty_42_Template(rf, ctx) { if (rf & 1) {
835
- i0.ɵɵelementStart(0, "tr")(1, "td", 144);
836
- i0.ɵɵtext(2, "Nothing applied yet.");
837
- i0.ɵɵelementEnd()();
838
- } }
839
- function MJOOrderEditorPageComponent_Conditional_42_Template(rf, ctx) { if (rf & 1) {
840
- i0.ɵɵelementStart(0, "div", 18)(1, "div", 46)(2, "div", 47);
841
- i0.ɵɵelement(3, "i", 119);
842
- i0.ɵɵelementStart(4, "h3");
843
- i0.ɵɵtext(5, "Initial payment \u2014 intent");
844
- i0.ɵɵelementEnd();
845
- i0.ɵɵelementStart(6, "span", 97)(7, "span", 120);
846
- i0.ɵɵtext(8, "not yet a payment");
847
- i0.ɵɵelementEnd()()();
848
- i0.ɵɵelementStart(9, "div", 49);
849
- i0.ɵɵconditionalCreate(10, MJOOrderEditorPageComponent_Conditional_42_Conditional_10_Template, 6, 6)(11, MJOOrderEditorPageComponent_Conditional_42_Conditional_11_Template, 5, 6);
850
- i0.ɵɵelementStart(12, "div", 102);
851
- i0.ɵɵtext(13, " What is recorded here is ");
852
- i0.ɵɵelementStart(14, "b");
853
- i0.ɵɵtext(15, "intent");
854
- i0.ɵɵelementEnd();
855
- i0.ɵɵtext(16, ". On confirm it becomes a real PaymentHeader and PaymentLine in the same transaction as the booking; from then on the payment record is the truth and these fields are never updated again. A wallet entry is ");
856
- i0.ɵɵelementStart(17, "b");
857
- i0.ɵɵtext(18, "copied");
858
- i0.ɵɵelementEnd();
859
- i0.ɵɵtext(19, ", never shared, so the snapshot cannot drift if the saved card is later edited. ");
860
- i0.ɵɵelementEnd()()();
861
- i0.ɵɵelementStart(20, "div", 121)(21, "div", 47);
862
- i0.ɵɵelement(22, "i", 122);
863
- i0.ɵɵelementStart(23, "h3");
864
- i0.ɵɵtext(24, "Payments applied");
865
- i0.ɵɵelementEnd();
866
- i0.ɵɵelementStart(25, "span", 123);
867
- i0.ɵɵtext(26);
868
- i0.ɵɵpipe(27, "mjoMoney");
869
- i0.ɵɵpipe(28, "mjoMoney");
870
- i0.ɵɵelementEnd()();
871
- i0.ɵɵelementStart(29, "div", 33)(30, "table", 124)(31, "thead")(32, "tr")(33, "th");
872
- i0.ɵɵtext(34, "Payment");
873
- i0.ɵɵelementEnd();
874
- i0.ɵɵelementStart(35, "th");
875
- i0.ɵɵtext(36, "Applied");
876
- i0.ɵɵelementEnd();
877
- i0.ɵɵelementStart(37, "th", 61);
878
- i0.ɵɵtext(38, "Amount");
879
- i0.ɵɵelementEnd()()();
880
- i0.ɵɵelementStart(39, "tbody");
881
- i0.ɵɵrepeaterCreate(40, MJOOrderEditorPageComponent_Conditional_42_For_41_Template, 7, 3, "tr", null, _forTrack1, false, MJOOrderEditorPageComponent_Conditional_42_ForEmpty_42_Template, 3, 0, "tr");
882
- i0.ɵɵelementEnd()()();
883
- i0.ɵɵelementStart(43, "div", 125);
884
- i0.ɵɵtext(44, " These are allocation LINES, not payments. One payment can settle several orders, so what matters here is the amount that reached THIS order \u2014 not what the customer handed over. ");
885
- i0.ɵɵelementEnd()();
886
- i0.ɵɵelementStart(45, "div", 121)(46, "div", 47);
887
- i0.ɵɵelement(47, "i", 126);
888
- i0.ɵɵelementStart(48, "h3");
889
- i0.ɵɵtext(49, "Terms");
890
- i0.ɵɵelementEnd()();
891
- i0.ɵɵelementStart(50, "div", 49)(51, "mjo-stated-value", 127);
892
- i0.ɵɵtext(52);
893
- i0.ɵɵelementEnd();
894
- i0.ɵɵelementStart(53, "mjo-stated-value", 128);
895
- i0.ɵɵtext(54);
896
- i0.ɵɵpipe(55, "mjoMoney");
897
- i0.ɵɵelementEnd();
898
- i0.ɵɵelementStart(56, "div", 102);
899
- i0.ɵɵtext(57, " Terms decide the due date, and the due date is what makes an order overdue. Nothing here is a stored \"overdue\" flag \u2014 that is a question about today's date, so it is asked rather than remembered. ");
900
- i0.ɵɵelementEnd()()()();
901
- } if (rf & 2) {
902
- const ctx_r1 = i0.ɵɵnextContext();
903
- i0.ɵɵadvance(10);
904
- i0.ɵɵconditional(ctx_r1.IsEditable ? 10 : 11);
905
- i0.ɵɵadvance(16);
906
- i0.ɵɵtextInterpolate2("", i0.ɵɵpipeBind1(27, 6, ctx_r1.AppliedTotal), " of ", i0.ɵɵpipeBind1(28, 8, ctx_r1.EstimatedTotal));
907
- i0.ɵɵadvance(14);
908
- i0.ɵɵrepeater(ctx_r1.AppliedPayments);
909
- i0.ɵɵadvance(12);
910
- i0.ɵɵtextInterpolate1(" ", ctx_r1.dateOf(ctx_r1.Order.DueDate), " ");
911
- i0.ɵɵadvance(2);
912
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(55, 10, ctx_r1.BalanceDue));
913
- } }
914
- function MJOOrderEditorPageComponent_Conditional_43_For_16_Template(rf, ctx) { if (rf & 1) {
915
- i0.ɵɵelementStart(0, "div", 147)(1, "span", 68);
916
- i0.ɵɵtext(2);
917
- i0.ɵɵelementEnd();
918
- i0.ɵɵelementStart(3, "span", 87);
919
- i0.ɵɵtext(4);
920
- i0.ɵɵelementEnd()();
921
- } if (rf & 2) {
922
- const dim_r31 = ctx.$implicit;
923
- i0.ɵɵadvance(2);
924
- i0.ɵɵtextInterpolate(dim_r31["Dimension"]);
925
- i0.ɵɵadvance(2);
926
- i0.ɵɵtextInterpolate(dim_r31["DimensionValue"]);
927
- } }
928
- function MJOOrderEditorPageComponent_Conditional_43_ForEmpty_17_Template(rf, ctx) { if (rf & 1) {
929
- i0.ɵɵelementStart(0, "div", 51);
930
- i0.ɵɵtext(1, " No tags. Dimensions are the axes a line is filed under for analysis \u2014 department, campaign, region \u2014 and an untagged line still books correctly; it is simply harder to group later. ");
931
- i0.ɵɵelementEnd();
932
- } }
933
- function MJOOrderEditorPageComponent_Conditional_43_Template(rf, ctx) { if (rf & 1) {
934
- const _r30 = i0.ɵɵgetCurrentView();
935
- i0.ɵɵelementStart(0, "div", 18)(1, "mjo-journal-entry-preview", 145);
936
- i0.ɵɵlistener("OpenInAccounting", function MJOOrderEditorPageComponent_Conditional_43_Template_mjo_journal_entry_preview_OpenInAccounting_1_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OpenInAccounting.emit($event)); });
937
- i0.ɵɵelementEnd();
938
- i0.ɵɵelementStart(2, "div", 102);
939
- i0.ɵɵtext(3, " Read-only, and never duplicated. Orders creates ");
940
- i0.ɵɵelementStart(4, "b");
941
- i0.ɵɵtext(5, "Pending");
942
- i0.ɵɵelementEnd();
943
- i0.ɵɵtext(6, " entries and owns nothing in the ledger, so every account links out to Accounting rather than being editable here. ");
944
- i0.ɵɵelementEnd();
945
- i0.ɵɵelementStart(7, "div", 121)(8, "div", 47);
946
- i0.ɵɵelement(9, "i", 146);
947
- i0.ɵɵelementStart(10, "h3");
948
- i0.ɵɵtext(11, "Dimension tags");
949
- i0.ɵɵelementEnd();
950
- i0.ɵɵelementStart(12, "span", 123);
951
- i0.ɵɵtext(13);
952
- i0.ɵɵelementEnd()();
953
- i0.ɵɵelementStart(14, "div", 49);
954
- i0.ɵɵrepeaterCreate(15, MJOOrderEditorPageComponent_Conditional_43_For_16_Template, 5, 2, "div", 147, _forTrack2, false, MJOOrderEditorPageComponent_Conditional_43_ForEmpty_17_Template, 2, 0, "div", 51);
955
- i0.ɵɵelementEnd()();
956
- i0.ɵɵelementStart(18, "div", 121)(19, "div", 47);
957
- i0.ɵɵelement(20, "i", 148);
958
- i0.ɵɵelementStart(21, "h3");
959
- i0.ɵɵtext(22, "Record changes");
960
- i0.ɵɵelementEnd()();
961
- i0.ɵɵelementStart(23, "div", 125);
962
- i0.ɵɵtext(24, " Every field change on this order is recorded by the platform, not by this app \u2014 which is why there is no \"edit history\" table of our own to keep in step. Open the record in Explorer's entity viewer to read it. ");
963
- i0.ɵɵelementEnd()()();
964
- } if (rf & 2) {
965
- const ctx_r1 = i0.ɵɵnextContext();
966
- i0.ɵɵadvance();
967
- i0.ɵɵproperty("Entries", ctx_r1.JournalEntries)("Pending", ctx_r1.Status === "Draft" || ctx_r1.Status === "Quoted");
968
- i0.ɵɵadvance(12);
969
- i0.ɵɵtextInterpolate(ctx_r1.Dimensions.length);
970
- i0.ɵɵadvance(2);
971
- i0.ɵɵrepeater(ctx_r1.Dimensions);
972
- } }
973
- function MJOOrderEditorPageComponent_Conditional_44_Conditional_1_Template(rf, ctx) { if (rf & 1) {
974
- i0.ɵɵelement(0, "mj-entity-data-grid", 149);
975
- } if (rf & 2) {
976
- const ctx_r1 = i0.ɵɵnextContext(2);
977
- i0.ɵɵproperty("Params", ctx_r1.JournalEntryParams)("Height", 360)("EditMode", "none")("ShowNewButton", false)("ShowDeleteButton", false)("AllowDelete", false)("ShowPager", true);
978
- } }
979
- function MJOOrderEditorPageComponent_Conditional_44_Conditional_2_Template(rf, ctx) { if (rf & 1) {
980
- i0.ɵɵelementStart(0, "div", 102);
981
- i0.ɵɵtext(1, " Nothing booked yet \u2014 an order books one journal entry per line when it is confirmed. ");
982
- i0.ɵɵelementEnd();
983
- } }
984
- function MJOOrderEditorPageComponent_Conditional_44_Template(rf, ctx) { if (rf & 1) {
985
- i0.ɵɵelementStart(0, "div", 18);
986
- i0.ɵɵconditionalCreate(1, MJOOrderEditorPageComponent_Conditional_44_Conditional_1_Template, 1, 7, "mj-entity-data-grid", 149)(2, MJOOrderEditorPageComponent_Conditional_44_Conditional_2_Template, 2, 0, "div", 102);
987
- i0.ɵɵelementEnd();
988
- } if (rf & 2) {
989
- const ctx_r1 = i0.ɵɵnextContext();
990
- i0.ɵɵadvance();
991
- i0.ɵɵconditional(ctx_r1.JournalEntryParams ? 1 : 2);
992
- } }
993
- function MJOOrderEditorPageComponent_Conditional_45_Conditional_1_Template(rf, ctx) { if (rf & 1) {
994
- i0.ɵɵelement(0, "mj-entity-data-grid", 149);
995
- } if (rf & 2) {
996
- const ctx_r1 = i0.ɵɵnextContext(2);
997
- i0.ɵɵproperty("Params", ctx_r1.SubscriptionParams)("Height", 360)("EditMode", "none")("ShowNewButton", false)("ShowDeleteButton", false)("AllowDelete", false)("ShowPager", true);
998
- } }
999
- function MJOOrderEditorPageComponent_Conditional_45_Conditional_2_Template(rf, ctx) { if (rf & 1) {
1000
- i0.ɵɵelementStart(0, "div", 102);
1001
- i0.ɵɵtext(1, " No subscriptions \u2014 they are created on confirm, from lines whose product carries a subscription type. ");
1002
- i0.ɵɵelementEnd();
1003
- } }
1004
- function MJOOrderEditorPageComponent_Conditional_45_Template(rf, ctx) { if (rf & 1) {
1005
- i0.ɵɵelementStart(0, "div", 18);
1006
- i0.ɵɵconditionalCreate(1, MJOOrderEditorPageComponent_Conditional_45_Conditional_1_Template, 1, 7, "mj-entity-data-grid", 149)(2, MJOOrderEditorPageComponent_Conditional_45_Conditional_2_Template, 2, 0, "div", 102);
1007
- i0.ɵɵelementEnd();
1008
- } if (rf & 2) {
1009
- const ctx_r1 = i0.ɵɵnextContext();
1010
- i0.ɵɵadvance();
1011
- i0.ɵɵconditional(ctx_r1.SubscriptionParams ? 1 : 2);
1012
- } }
1013
- function MJOOrderEditorPageComponent_Conditional_46_Template(rf, ctx) { if (rf & 1) {
1014
- const _r32 = i0.ɵɵgetCurrentView();
1015
- i0.ɵɵelementStart(0, "aside", 19)(1, "div", 150)(2, "div")(3, "h2");
1016
- i0.ɵɵtext(4);
1017
- i0.ɵɵelementEnd();
1018
- i0.ɵɵelementStart(5, "div", 51);
1019
- i0.ɵɵtext(6);
1020
- i0.ɵɵelementEnd()();
1021
- i0.ɵɵelementStart(7, "span", 97)(8, "button", 151);
1022
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_46_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r32); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CloseDrawer()); });
1023
- i0.ɵɵelement(9, "i", 108);
1024
- i0.ɵɵelementEnd()()();
1025
- i0.ɵɵelementStart(10, "div", 152)(11, "div", 153);
1026
- i0.ɵɵtext(12, "Who this line is for");
1027
- i0.ɵɵelementEnd();
1028
- i0.ɵɵelementStart(13, "mjo-stated-value", 154);
1029
- i0.ɵɵtext(14);
1030
- i0.ɵɵelementEnd();
1031
- i0.ɵɵelementStart(15, "mjo-stated-value", 155);
1032
- i0.ɵɵtext(16);
1033
- i0.ɵɵelementEnd();
1034
- i0.ɵɵelementStart(17, "mjo-stated-value", 156);
1035
- i0.ɵɵtext(18);
1036
- i0.ɵɵelementEnd();
1037
- i0.ɵɵelementStart(19, "div", 157);
1038
- i0.ɵɵtext(20, "Timing");
1039
- i0.ɵɵelementEnd();
1040
- i0.ɵɵelementStart(21, "mjo-stated-value", 158);
1041
- i0.ɵɵtext(22);
1042
- i0.ɵɵelementEnd();
1043
- i0.ɵɵelementStart(23, "div", 157);
1044
- i0.ɵɵtext(24, "Reversal");
1045
- i0.ɵɵelementEnd();
1046
- i0.ɵɵelementStart(25, "mjo-stated-value", 159);
1047
- i0.ɵɵtext(26);
1048
- i0.ɵɵelementEnd();
1049
- i0.ɵɵelementStart(27, "div", 51);
1050
- i0.ɵɵtext(28, " A line that reverses another inherits its price and is capped at the quantity still returnable there. ");
1051
- i0.ɵɵelementEnd();
1052
- i0.ɵɵelementStart(29, "div", 157);
1053
- i0.ɵɵtext(30, "Subscription");
1054
- i0.ɵɵelementEnd();
1055
- i0.ɵɵelementStart(31, "mjo-stated-value", 160);
1056
- i0.ɵɵtext(32);
1057
- i0.ɵɵelementEnd();
1058
- i0.ɵɵelementStart(33, "div", 51);
1059
- i0.ɵɵtext(34, " Naming a renewal target ");
1060
- i0.ɵɵelementStart(35, "i");
1061
- i0.ɵɵtext(36, "is");
1062
- i0.ɵɵelementEnd();
1063
- i0.ɵɵtext(37, " the statement of who the subscriber is, so the target's holder wins over the line's ship-to. ");
1064
- i0.ɵɵelementEnd()();
1065
- i0.ɵɵelementStart(38, "div", 161)(39, "button", 162);
1066
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_46_Template_button_click_39_listener() { i0.ɵɵrestoreView(_r32); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CloseDrawer()); });
1067
- i0.ɵɵtext(40, "Done");
1068
- i0.ɵɵelementEnd();
1069
- i0.ɵɵelementStart(41, "span", 163);
1070
- i0.ɵɵtext(42, "Every field here defaults from something. Nothing is required.");
1071
- i0.ɵɵelementEnd()()();
1072
- } if (rf & 2) {
1073
- let tmp_1_0;
1074
- let tmp_2_0;
1075
- const ctx_r1 = i0.ɵɵnextContext();
1076
- i0.ɵɵadvance(4);
1077
- i0.ɵɵtextInterpolate(((tmp_1_0 = ctx_r1.ProductFor(ctx_r1.OpenLine)) == null ? null : tmp_1_0.Name) ?? "Line");
1078
- i0.ɵɵadvance(2);
1079
- i0.ɵɵtextInterpolate2(" ", (tmp_2_0 = ctx_r1.ProductFor(ctx_r1.OpenLine)) == null ? null : tmp_2_0.SKU, " \u00B7 revenue to ", (tmp_2_0 = ctx_r1.ProductFor(ctx_r1.OpenLine)) == null ? null : tmp_2_0.CompanyName, " ");
1080
- i0.ɵɵadvance(8);
1081
- i0.ɵɵtextInterpolate1(" ", ctx_r1.OpenLine.ShipToAddressID ?? "\u2014 header default \u2014", " ");
1082
- i0.ɵɵadvance(2);
1083
- i0.ɵɵtextInterpolate1(" ", ctx_r1.OpenLine.ShipToPersonID ?? "\u2014 header default \u2014", " ");
1084
- i0.ɵɵadvance(2);
1085
- i0.ɵɵtextInterpolate1(" ", ctx_r1.OpenLine.ShipToOrganizationID ?? "\u2014 header default \u2014", " ");
1086
- i0.ɵɵadvance(4);
1087
- i0.ɵɵtextInterpolate2(" ", ctx_r1.OpenLine.ServicePeriodStart ?? "\u2014", " \u2013 ", ctx_r1.OpenLine.ServicePeriodEnd ?? "\u2014", " ");
1088
- i0.ɵɵadvance(4);
1089
- i0.ɵɵtextInterpolate1(" ", ctx_r1.OpenLine.ReversesOrderLineID ?? "\u2014 nothing \u2014", " ");
1090
- i0.ɵɵadvance(6);
1091
- i0.ɵɵtextInterpolate1(" ", ctx_r1.OpenLine.RenewsSubscriptionID ?? "\u2014 none \u2014", " ");
1092
- } }
1093
- function MJOOrderEditorPageComponent_Conditional_47_Conditional_1_Template(rf, ctx) { if (rf & 1) {
1094
- const _r33 = i0.ɵɵgetCurrentView();
1095
- i0.ɵɵelementStart(0, "button", 164);
1096
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_47_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r33); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SaveDraft()); });
1097
- i0.ɵɵelement(1, "i", 165);
1098
- i0.ɵɵtext(2, " Save draft ");
1099
- i0.ɵɵelementEnd();
1100
- i0.ɵɵelementStart(3, "button", 166);
1101
- i0.ɵɵlistener("click", function MJOOrderEditorPageComponent_Conditional_47_Conditional_1_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r33); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.RequestConfirm()); });
1102
- i0.ɵɵelement(4, "i", 167);
1103
- i0.ɵɵtext(5, " Confirm order ");
1104
- i0.ɵɵelementEnd();
1105
- } if (rf & 2) {
1106
- const ctx_r1 = i0.ɵɵnextContext(2);
1107
- i0.ɵɵadvance(3);
1108
- i0.ɵɵproperty("disabled", !ctx_r1.CanConfirm);
1109
- } }
1110
- function MJOOrderEditorPageComponent_Conditional_47_Conditional_2_Template(rf, ctx) { if (rf & 1) {
1111
- i0.ɵɵelementStart(0, "button", 168);
1112
- i0.ɵɵelement(1, "i", 169);
1113
- i0.ɵɵtext(2, " Create reversal\u2026 ");
1114
- i0.ɵɵelementEnd();
1115
- i0.ɵɵelementStart(3, "button", 168);
1116
- i0.ɵɵelement(4, "i", 170);
1117
- i0.ɵɵtext(5, " Take payment ");
1118
- i0.ɵɵelementEnd();
1119
- i0.ɵɵelementStart(6, "span", 51);
1120
- i0.ɵɵtext(7, " This order has booked. Corrections are reversing orders \u2014 locked history is never edited. ");
1121
- i0.ɵɵelementEnd();
1122
- } }
1123
- function MJOOrderEditorPageComponent_Conditional_47_Template(rf, ctx) { if (rf & 1) {
1124
- i0.ɵɵelementStart(0, "div", 20);
1125
- i0.ɵɵconditionalCreate(1, MJOOrderEditorPageComponent_Conditional_47_Conditional_1_Template, 6, 1)(2, MJOOrderEditorPageComponent_Conditional_47_Conditional_2_Template, 8, 0);
1126
- i0.ɵɵelementEnd();
1127
- } if (rf & 2) {
1128
- const ctx_r1 = i0.ɵɵnextContext();
1129
- i0.ɵɵadvance();
1130
- i0.ɵɵconditional(ctx_r1.IsEditable ? 1 : 2);
1131
- } }
1132
- export class MJOOrderEditorPageComponent {
1133
- orders = inject(MJOPricingScheduler);
1134
- // Required: this page is created imperatively and runs zoneless, so every assignment that
1135
- // lands after an await or from a preview callback has to tick explicitly.
1136
- cdr = inject(ChangeDetectorRef);
1137
- /**
1138
- * The order being edited. Supplied by the host — often the SAME instance fast
1139
- * entry was working on, which is what makes escalation lossless.
1140
- */
1141
- /**
1142
- * The order being edited — a real entity, not a parallel model of one.
1143
- *
1144
- * Bound directly: the object the screen mutates is the object that gets saved, so there is no
1145
- * mapping layer to drift and no second definition of what an order is.
1146
- */
1147
- Order;
1148
- /** True when the chosen tender needs a reference number — read from the PaymentType, not stored. */
1149
- RequiresPaymentReference = false;
1150
- /**
1151
- * The reference the user typed for the initial payment — a check number, wire confirmation, or
1152
- * transfer id.
1153
- *
1154
- * Backed by `Order.InitialPaymentReference` (companion). There is no column — confirm
1155
- * turns it into a `PaymentDetail` — but it has to ride the save, so it cannot stay page-only.
1156
- */
1157
- /** Catalog for the product column and the add-line picker. */
1158
- Catalog = [];
1159
- /**
1160
- * The companies this order could be raised under.
1161
- *
1162
- * The OWNING company decides which chart of accounts the order books into and who can see it,
1163
- * and it was previously taken silently from the first product in the catalog and never shown.
1164
- * A default nobody can see is a decision made on the user's behalf in secret — and with more
1165
- * than one company it is a decision they may well want to make differently.
1166
- */
1167
- Companies = [];
1168
- /** Where the order is. Drives the stepper and which verbs are offered. */
1169
- Status = 'Draft';
1170
- /** Document number, once the order has one. Drafts have none. */
1171
- OrderNumber = null;
1172
- /**
1173
- * Show this page's own Save/Confirm bar.
1174
- *
1175
- * The order workspace hosts this editor inside `mj-workspace-card`, which already provides
1176
- * Confirm / Keep as draft / Discard for the active tab. Left on, the screen shows two action
1177
- * bars that appear to do different things and do not.
1178
- */
1179
- ShowActions = true;
1180
- /**
1181
- * Tenders the instance accepts, for the initial-payment picker. Supplied by the host — the
1182
- * section already loads and caches them.
1183
- */
1184
- Tenders = [];
1185
- /** Journal entries — populated on the Accounting tab from a preview. */
1186
- JournalEntries = [];
1187
- /** The user asked to confirm. The host runs the pre-flight. */
1188
- ConfirmRequested = new EventEmitter();
1189
- /** The draft was saved. */
1190
- Saved = new EventEmitter();
1191
- /** A line was opened. The host may show it in a slide-in instead of the built-in drawer. */
1192
- LineOpened = new EventEmitter();
1193
- /** An entry's Accounting link was followed. */
1194
- OpenInAccounting = new EventEmitter();
1195
- /** Allocation lines that have landed on this order. */
1196
- AppliedPayments = [];
1197
- /** Dimension tags across this order's lines. */
1198
- Dimensions = [];
1199
- /** PaymentHeaderID (lower-cased) → its number, for the applied-payments table. */
1200
- PaymentNumbers = new Map();
1201
- /** What to show in the Payment column of an allocation row. */
1202
- PaymentNumberOf(line) {
1203
- return this.PaymentNumbers.get(String(line.PaymentHeaderID ?? '').toLowerCase()) ?? '—';
1204
- }
1205
- /** Active tab. */
1206
- ActiveTab = 'lines';
1207
- /**
1208
- * What the consequence grids ask for, or null when this order has no saved lines.
1209
- *
1210
- * Set in `loadPersistedDetail`, which only runs for a persisted order — a draft that has never
1211
- * been saved has booked nothing and started nothing, and the panes say so rather than
1212
- * rendering an empty grid that looks like a failed query.
1213
- */
1214
- get JournalEntryParams() {
1215
- return this.consequences.get(this.currentOrderID ?? '')?.Journal ?? null;
1216
- }
1217
- get SubscriptionParams() {
1218
- return this.consequences.get(this.currentOrderID ?? '')?.Subscriptions ?? null;
1219
- }
1220
- /**
1221
- * Params PER ORDER, not per editor instance.
1222
- *
1223
- * The workspace holds one tab per order but renders ONE editor for whichever is active, so
1224
- * anything stored as a plain field on this component belongs to "the last order that loaded"
1225
- * rather than to the order on screen — which is exactly how the journal tab came to show the
1226
- * previous tab's entries. Keyed by order id, a tab switch is a different map lookup and cannot
1227
- * be stale; the query runs once per order and only when someone opens one of the two tabs.
1228
- *
1229
- * A null result is NOT cached: an order with no saved lines yet has nothing to ask for, and
1230
- * caching that would keep answering "nothing" after its lines are saved.
1231
- */
1232
- consequences = new Map();
1233
- /** The order on screen, or null for a draft that has never been saved. */
1234
- get currentOrderID() {
1235
- return this.Order?.ID ?? null;
1236
- }
1237
- /**
1238
- * Latest line pricing.
1239
- *
1240
- * LINE PRICES ONLY, and the name says so. It is what `Orders.PreviewPrice`
1241
- * resolved per line — the same `ResolvePrice` the engine's own pricing walk
1242
- * calls — summed to a net subtotal. Charges, tax and promotions are decided
1243
- * inside the confirm transaction and are NOT here; the screen says so rather
1244
- * than showing them as zero.
1245
- */
1246
- Pricing = { Result: null, Loading: false, Error: null };
1247
- /** The line whose drawer is open, or null. */
1248
- OpenLine = null;
1249
- stopWatching = null;
1250
- async ngOnInit() {
1251
- // Tolerate a host that forgot to supply one rather than throwing: a blank
1252
- // editor is recoverable, a crashed tab is not.
1253
- if (!this.Order) {
1254
- const md = new Metadata();
1255
- this.Order = await md.GetEntityObject(MJO_ENTITIES.OrderHeader);
1256
- this.Order.NewRecord();
1257
- }
1258
- // Both callbacks MUST tick — they land from a debounced timer and an awaited network
1259
- // round-trip, outside anything Angular is watching on an imperatively-created, zoneless
1260
- // page. Assigning alone repaints nothing, so the decomposition stays on "— resolving…"
1261
- // and CanConfirm never turns true. Same defect as fast-entry.page.ts.
1262
- // NO SUBSCRIBE. The draft raised a change event this page listened to in order to re-price —
1263
- // a loop through an observable to learn something the page already knew, because every edit
1264
- // arrives through a setter the page owns. `onEdited()` is called from those setters instead:
1265
- // simpler, and an edit path that forgets to call it fails review rather than silently
1266
- // ceasing to re-price.
1267
- void this.orders.PriceNow(this.Order, (state) => {
1268
- this.Pricing = state;
1269
- this.cdr.detectChanges();
1270
- });
1271
- // Payments and dimension tags exist only against a SAVED order, so this
1272
- // resolves to empty for a fresh draft rather than querying for nothing.
1273
- void this.loadPersistedDetail();
1274
- }
1275
- /**
1276
- * The workspace swaps `[Draft]` when you change order tabs — the component is never remounted,
1277
- * so this is the only signal that the order on screen has changed.
1278
- */
1279
- ngOnChanges(changes) {
1280
- if (changes['Draft'])
1281
- void this.loadConsequences();
1282
- // STATUS IS THE CONFIRM SIGNAL. The workspace confirms in place and never remounts this
1283
- // component — it just flips `[Status]` to 'Confirmed'. Without re-reading here, the money
1284
- // on screen stays whatever the DRAFT implied, so an order that is Paid in the database went
1285
- // on saying "BALANCE $560.00 · Unpaid" to the person who had just paid it.
1286
- //
1287
- // Also covers `Draft`, because a tab switch swaps the draft and its persisted money with it.
1288
- if (changes['Status'] || changes['Draft'])
1289
- void this.loadPersistedDetail();
1290
- }
1291
- ngOnDestroy() {
1292
- if (this.partyTimer)
1293
- clearTimeout(this.partyTimer);
1294
- this.stopWatching?.();
1295
- this.orders.CancelPending();
1296
- }
1297
- /* ── Chrome ─────────────────────────────────────────────────────────── */
1298
- get Stages() {
1299
- return BuildOrderStages(this.Status, this.RequiresFulfillment);
1300
- }
1301
- /**
1302
- * Whether any line must ship — changes what the stepper says about Fulfilled.
1303
- *
1304
- * Read from the CATALOGUE, not from a priced line. It used to come off the
1305
- * preview's projection, which meant the stepper could not say whether an order
1306
- * shipped until a whole rolled-back booking had run. Whether a product is
1307
- * physical is a property of the product; the order does not decide it.
1308
- */
1309
- get RequiresFulfillment() {
1310
- return this.Lines.some((line) => this.ProductFor(line)?.TypeName === 'Goods');
1311
- }
1312
- /** The line subtotal, BEFORE tax and charges. Null until the first pass returns. */
1313
- get Totals() {
1314
- return this.Pricing.Result?.Totals ?? null;
1315
- }
1316
- /** True when at least one line has no resolvable price, so the subtotal is short. */
1317
- get HasUnpricedLines() {
1318
- return this.Pricing.Result?.HasUnpricedLines === true;
1319
- }
1320
- /** The five tabs, with counts and the red-dot state. */
1321
- get Tabs() {
1322
- // Same rule as `Issues`: a confirmed order carries no "still missing" state, so the red
1323
- // dots come off with the banner rather than leaving Parties flagged on a booked order.
1324
- const sections = this.IsEditable ? (this.Order?.SectionsWithErrors() ?? []) : [];
1325
- // Charges are decided inside the confirm transaction, so a draft has no count to show.
1326
- const chargeCount = 0;
1327
- return [
1328
- { Key: 'lines', Label: 'Lines', Count: this.Order?.Lines.Count ?? 0, HasError: sections.includes('lines') },
1329
- { Key: 'parties', Label: 'Parties', HasError: sections.includes('parties') },
1330
- { Key: 'charges', Label: 'Charges & tax', Count: chargeCount || null, HasError: sections.includes('charges') },
1331
- { Key: 'payment', Label: 'Payment', HasError: sections.includes('payment') },
1332
- { Key: 'accounting', Label: 'Accounting' },
1333
- // AFTER Accounting, in the order the consequences happen: the entries are written
1334
- // inside the confirm, the subscription is decided from the line that caused it.
1335
- { Key: 'journal', Label: 'Journal entries' },
1336
- { Key: 'subscriptions', Label: 'Subscriptions' },
1337
- ];
1338
- }
1339
- /**
1340
- * The same five tabs, shaped for MJ's own tab component.
1341
- *
1342
- * WHY mj-tab-nav AND NOT accounting's mj-workspace-card. The workspace card
1343
- * models OPEN DOCUMENTS — its strip closes, reorders and adds tabs, and it
1344
- * carries a New button. These five are PANES OF ONE ORDER: you cannot close
1345
- * Parties or add a sixth, so those affordances would be lies. It also lives in
1346
- * accounting's transfer-pending/ folder, which is explicitly parked code owed
1347
- * to another home, so depending on it now would buy a migration later.
1348
- * mj-tab-nav is the shared, shipped component whose semantics actually match.
1349
- *
1350
- * The red dot becomes an error-variant badge. A bare dot is a signifier with
1351
- * no meaning attached — only the aria-label said what it meant, so a sighted
1352
- * user saw a dot and had to guess. "!" in the same badge slot the count uses
1353
- * reads as attention-needed on sight, and severity is carried by colour rather
1354
- * than by a second element competing with the count.
1355
- */
1356
- get TabNav() {
1357
- return this.Tabs.map((tab) => ({
1358
- key: tab.Key,
1359
- label: tab.Label,
1360
- // A tab can need attention without having a count (Parties has no
1361
- // number), so the badge falls back to "!" rather than rendering
1362
- // nothing and losing the signal entirely.
1363
- // A tab nobody can act on yet gets a muted marker rather than looking like a place
1364
- // the user forgot to visit. MJ's TabConfig has no `disabled`, so this is the closest
1365
- // honest signal available — the pane itself explains why (see the Accounting tab).
1366
- badge: tab.Count ?? (tab.HasError ? '!' : this.IsTabInert(tab.Key) ? '—' : null),
1367
- badgeVariant: tab.HasError ? 'error' : 'default',
1368
- }));
1369
- }
1370
- /**
1371
- * Load what only a SAVED order can have.
1372
- *
1373
- * Payments and dimension tags exist against persisted rows, so a draft that
1374
- * has never been saved has neither — and asking for them with no id would be a
1375
- * query guaranteed to return nothing. Both awaits settle before either is
1376
- * assigned.
1377
- */
1378
- async loadPersistedDetail() {
1379
- const orderID = this.Order?.ID ?? null;
1380
- if (!orderID) {
1381
- this.AppliedPayments = [];
1382
- this.Dimensions = [];
1383
- return;
1384
- }
1385
- // A draft line carries a CLIENT key, and the preview's projection carries
1386
- // one too — neither is a database id, because a line has no id until it is
1387
- // saved. Dimensions hang off the SAVED lines, so those are read first and
1388
- // their ids are what the dimension query is given.
1389
- const [payments, savedLines, rows] = await Promise.all([
1390
- GetPaymentLinesForOrder(orderID),
1391
- GetOrderLines(orderID),
1392
- // THE ORDER'S OWN MONEY, READ BACK. Once an order is saved its total, amount paid,
1393
- // balance and payment status are FACTS the engine computed and triggers maintain —
1394
- // not something to re-derive here from client-side line pricing, which knows nothing
1395
- // about charges or tax and would disagree the moment either exists.
1396
- GetOrders({ OrderHeaderID: orderID, MaxRows: 1 }),
1397
- ]);
1398
- const dimensions = await GetLineDimensionsForOrder(savedLines.map((line) => String(line['ID'])));
1399
- this.AppliedPayments = payments;
1400
- // The allocation line knows WHICH payment but not what it is called — `PaymentLine` carries
1401
- // no number, so the table's Payment column needs one lookup rather than a field that does
1402
- // not exist.
1403
- this.PaymentNumbers = await GetPaymentNumbers(payments.map((line) => String(line.PaymentHeaderID ?? '')));
1404
- this.Dimensions = dimensions;
1405
- this.Persisted = rows[0] ?? null;
1406
- this.cdr.detectChanges();
1407
- }
1408
- /**
1409
- * The saved order row, or null while this is a draft that has never been saved.
1410
- *
1411
- * The DIVIDING LINE of this screen. Before a save there is no order, so the only money
1412
- * available is what `Orders.PreviewPrice` resolved per line — an estimate that excludes
1413
- * charges and tax and says so. After a save the engine's own figures exist, and they are
1414
- * authoritative; nothing here should be recomputing them.
1415
- */
1416
- Persisted = null;
1417
- /** True once this order exists in the database, so its own money can be shown. */
1418
- get IsPersisted() {
1419
- return this.Persisted !== null;
1420
- }
1421
- /**
1422
- * The money strip's four values, persisted-first.
1423
- *
1424
- * These exist because the strip used to be bound to `[Paid]="0"` and
1425
- * `[PaymentStatus]="Status === 'Draft' ? null : 'Unpaid'"` — LITERALS, not stale reads. So a
1426
- * confirmed, fully-paid order reported "PAID — · BALANCE $560.00 · Unpaid" for ever, and no
1427
- * amount of refreshing would have changed it. Verified against ORD-000122, which the database
1428
- * had as Paid / AmountPaid 560 / Balance 0 while the screen said otherwise.
1429
- *
1430
- * A draft still shows the estimate — it has nothing else to show — but it is labelled as one
1431
- * and, being a Draft, the strip hides Paid entirely.
1432
- */
1433
- get DisplayTotal() {
1434
- return this.Persisted ? Number(this.Persisted.TotalGross ?? 0) : (this.Totals?.NetTotal ?? null);
1435
- }
1436
- get DisplayPaid() {
1437
- // The header's rollup when it exists; otherwise the allocations, which is the same figure
1438
- // reached the long way and is what a not-yet-rolled-up read can still answer.
1439
- return this.Persisted ? Number(this.Persisted.AmountPaid ?? 0) : this.AppliedTotal;
1440
- }
1441
- get DisplayBalance() {
1442
- return this.Persisted ? Number(this.Persisted.Balance ?? 0) : (this.Totals?.NetTotal ?? null);
1443
- }
1444
- /**
1445
- * Null while the order is a draft — an unsaved order has no payment state to report.
1446
- *
1447
- * Narrowed rather than cast. `mjBizAppsOrdersOrderHeaderEntity.PaymentStatus` is a plain `string` off the view,
1448
- * and the strip takes the union; a cast would compile and then render an unstyled chip for
1449
- * any value the column grows later. Checking against the union means an unrecognised value
1450
- * shows nothing at all, which is the honest outcome.
1451
- */
1452
- get DisplayPaymentStatus() {
1453
- const status = this.Persisted?.PaymentStatus;
1454
- const known = ['Unpaid', 'PartiallyPaid', 'Paid', 'Overdue', 'WrittenOff'];
1455
- return known.find((s) => s === status) ?? null;
1456
- }
1457
- /** What has actually reached this order, summed from its allocations. */
1458
- get AppliedTotal() {
1459
- return Math.round(this.AppliedPayments.reduce((sum, line) => sum + Number(line['Amount'] ?? 0), 0) * 100) / 100;
1460
- }
1461
- /**
1462
- * The line subtotal. NOT the order's gross — tax and charges are not known here.
1463
- * Named for what it is so no caller mistakes it for the amount that will book.
1464
- */
1465
- get EstimatedTotal() {
1466
- return this.Pricing.Result?.Totals.NetTotal ?? 0;
1467
- }
1468
- get BalanceDue() {
1469
- return Math.round((this.EstimatedTotal - this.AppliedTotal) * 100) / 100;
1470
- }
1471
- dateOf(value) {
1472
- return value ? FormatDate(String(value), { Short: true }) : '—';
1473
- }
1474
- moneyOf(value) {
1475
- return FormatMoney(Number(value ?? 0));
1476
- }
1477
- /**
1478
- * True when a tab has nothing to show and nothing to edit for this order yet.
1479
- *
1480
- * Accounting is derived entirely from a confirm: an unbooked order has no journal entries and
1481
- * no dimensions to read, and nothing on that tab is authored by hand at any point.
1482
- */
1483
- IsTabInert(key) {
1484
- return key === 'accounting' && !this.JournalEntries.length;
1485
- }
1486
- /** Human name for a draft section, used in the to-do strip's tooltips. */
1487
- SectionLabel(section) {
1488
- return this.Tabs.find((t) => t.Key === section)?.Label ?? 'this order';
1489
- }
1490
- /**
1491
- * Jump to whichever tab owns an outstanding item.
1492
- *
1493
- * `OrderEditorSection` includes `header`, which has no tab — those fields live in the identity
1494
- * strip, which is always on screen. Navigating somewhere arbitrary for them would be worse
1495
- * than staying put, so a header issue simply does not move you.
1496
- */
1497
- GoToIssue(section) {
1498
- if (section === 'header')
1499
- return;
1500
- if (this.Tabs.some((t) => t.Key === section))
1501
- this.SelectTab(section);
1502
- }
1503
- SelectTab(tab) {
1504
- this.ActiveTab = tab;
1505
- // LOAD ON OPEN, not just on mount. `loadPersistedDetail` used to run only in `ngOnInit`,
1506
- // and this editor is mounted ONCE and re-fed through `[Draft]` — opening an existing order
1507
- // swaps the input without re-running the hook, so the consequence params stayed null and
1508
- // both tabs claimed nothing was booked for orders that plainly had entries.
1509
- //
1510
- // Keyed on the ORDER, so it re-reads when you switch to a different one, and after a
1511
- // confirm (which is when the entries first exist) rather than serving the pre-confirm
1512
- // answer for the rest of the session.
1513
- void this.loadConsequences();
1514
- }
1515
- /**
1516
- * Read the current order's consequence params, once, on demand.
1517
- *
1518
- * ON DEMAND is the point: nothing needs refreshing from the five places an order can change,
1519
- * because the answer is fetched the first time someone opens the tab for THAT order and is
1520
- * then keyed to it. Switching workspace tabs needs no notification — the getters read a
1521
- * different key.
1522
- */
1523
- async loadConsequences() {
1524
- if (this.ActiveTab !== 'journal' && this.ActiveTab !== 'subscriptions')
1525
- return;
1526
- const orderID = this.currentOrderID;
1527
- if (!orderID || this.consequences.has(orderID))
1528
- return;
1529
- const lineIDs = (await GetOrderLines(orderID)).map((line) => String(line['ID']));
1530
- const journal = JournalEntryViewParams(lineIDs);
1531
- const subscriptions = SubscriptionViewParams(lineIDs);
1532
- // Only a real answer is remembered — see `consequences`.
1533
- if (journal || subscriptions) {
1534
- this.consequences.set(orderID, { Journal: journal, Subscriptions: subscriptions });
1535
- }
1536
- this.cdr.detectChanges();
1537
- }
1538
- /**
1539
- * Narrowing entry point for MJ's tab component, whose (TabChange) is a plain
1540
- * string — it cannot know our union.
1541
- *
1542
- * Checked against the real tab list rather than cast. A cast would compile and
1543
- * then quietly set ActiveTab to a key that matches no pane, leaving the editor
1544
- * showing nothing with no error to explain it; this simply ignores a key that
1545
- * is not ours, and the current tab stays put.
1546
- */
1547
- SelectTabKey(key) {
1548
- const match = this.Tabs.find((tab) => tab.Key === key);
1549
- if (match)
1550
- this.SelectTab(match.Key);
1551
- }
1552
- /**
1553
- * Always cancels a move to Confirmed and routes through the confirm action instead.
1554
- * Booking is not undoable, and a stepper click is too easy a way to trigger it.
1555
- */
1556
- OnBeforeStageChange(event) {
1557
- if (event.To === 'Confirmed') {
1558
- event.Cancel = true;
1559
- event.CancelReason = 'Use Confirm — booking is not undoable.';
1560
- this.ConfirmRequested.emit(this.Order);
1561
- }
1562
- }
1563
- /* ── Lines ──────────────────────────────────────────────────────────── */
1564
- get Lines() {
1565
- return [...(this.Order?.Lines.Items ?? [])];
1566
- }
1567
- ProductFor(line) {
1568
- return this.Catalog.find((p) => p.ID === line.ProductID);
1569
- }
1570
- PricedLine(line) {
1571
- return this.Pricing.Result?.Lines?.find((l) => l.ClientKey === line.ID);
1572
- }
1573
- /** What one line's discount comes to, derived rather than reported. */
1574
- DiscountAmount(line) {
1575
- const priced = this.PricedLine(line);
1576
- if (!priced || priced.ExtendedAmount === null || priced.NetAmount === null)
1577
- return null;
1578
- const discount = Math.round((priced.ExtendedAmount - priced.NetAmount) * 100) / 100;
1579
- return discount > 0 ? discount : null;
1580
- }
1581
- SetQuantity(line, raw) {
1582
- const n = Number.parseFloat(raw);
1583
- line.Quantity = !Number.isFinite(n) || n === 0 ? 1 : n;
1584
- this.onEdited();
1585
- }
1586
- /**
1587
- * Typing a price is DIRECT ENTRY and wins over any resolved one. Clearing the
1588
- * field restores resolution, which is why an empty string maps to `undefined`
1589
- * rather than to zero.
1590
- */
1591
- SetUnitPrice(line, raw) {
1592
- const trimmed = raw.trim();
1593
- if (!trimmed) {
1594
- // Clearing a stated price hands the line back to the engine to resolve.
1595
- line.Set('UnitPrice', null);
1596
- this.onEdited();
1597
- return;
1598
- }
1599
- const n = Number.parseFloat(trimmed.replace(/[^0-9.\-]/g, ''));
1600
- if (Number.isFinite(n) && n >= 0) {
1601
- line.UnitPrice = n;
1602
- this.onEdited();
1603
- }
1604
- }
1605
- Remove(line) {
1606
- if (this.OpenLine?.ID === line.ID)
1607
- this.OpenLine = null;
1608
- // Remove() tracks the removal so a persisted line is DELETED rather than orphaned, and
1609
- // renumbers the survivors gap-free.
1610
- this.Order.Lines.Remove(line);
1611
- this.onEdited();
1612
- }
1613
- /* ── Adding a line ──────────────────────────────────────────────────────
1614
- *
1615
- * This screen could REMOVE a line and never ADD one, so the empty state
1616
- * ("No lines yet. An order needs at least one line before it can confirm.")
1617
- * was a dead end — it named the requirement and gave you no way to meet it.
1618
- * Fast entry was the only way to put a line on an order, which is why the
1619
- * full editor read as a viewer.
1620
- *
1621
- * The catalogue is already an `@Input`, so this is a local filter rather
1622
- * than a query — no round trip, and it works the same for a new order and
1623
- * an existing one.
1624
- */
1625
- /** What the user has typed into the add-product box. */
1626
- ProductQuery = '';
1627
- /** True once the box has focus — the list opens on click, not on the second keystroke. */
1628
- ProductPickerOpen = false;
1629
- /**
1630
- * What the product list shows.
1631
- *
1632
- * OPENS ON FOCUS, showing the catalogue, and narrows as you type. Requiring two characters
1633
- * first meant clicking the box did nothing at all, so there was no way to see what was for
1634
- * sale without already knowing its name — fine for a desk that has the catalogue memorised,
1635
- * useless for everyone else.
1636
- *
1637
- * ONE search over BOTH name and SKU, deliberately: an order taker reading off a purchase order
1638
- * has a code, one working from a conversation has a name, and asking them to pick the right box
1639
- * first is the kind of thing that makes people use the wrong one.
1640
- *
1641
- * `SKU ?? ''` is not defensive noise. Products in a freshly-migrated instance have a NULL SKU
1642
- * (the code ends up in the name instead), and `null.toLowerCase()` throws — which would take
1643
- * the whole picker down on the first keystroke rather than simply matching nothing.
1644
- *
1645
- * The cap is generous rather than tight because the list SCROLLS: it exists to stop a
1646
- * pathological catalogue rendering thousands of DOM nodes, not to make the user type.
1647
- */
1648
- get ProductMatches() {
1649
- if (!this.ProductPickerOpen)
1650
- return [];
1651
- const q = this.ProductQuery.trim().toLowerCase();
1652
- const pool = q
1653
- ? this.Catalog.filter((p) => (p.Name ?? '').toLowerCase().includes(q) || (p.SKU ?? '').toLowerCase().includes(q))
1654
- : this.Catalog;
1655
- return pool.slice(0, 50);
1656
- }
1657
- OnProductFocus() {
1658
- this.ProductPickerOpen = true;
1659
- }
1660
- /**
1661
- * Typing reopens the picker.
1662
- *
1663
- * Escape closes the list but does NOT blur the box — so without this, carrying on typing
1664
- * produced nothing and the field looked broken until you clicked away and back. Focus alone is
1665
- * not enough of a trigger, because the element already had it.
1666
- */
1667
- OnProductQueryChange() {
1668
- this.ProductPickerOpen = true;
1669
- }
1670
- /**
1671
- * True when the catalogue this picker filters was itself capped at the fetch.
1672
- *
1673
- * The section loads products with `MaxRows` (200 by default) and caches the result, so this
1674
- * picker filters a SUBSET and cannot see past it. Saying so is the difference between "no such
1675
- * product" and "not in the first 200" — the second is the one that wastes an afternoon.
1676
- */
1677
- get CatalogTruncated() {
1678
- return WasTruncated(MJO_ENTITIES.Product);
1679
- }
1680
- /**
1681
- * Add the product as a line.
1682
- *
1683
- * Quantity 1 and NO unit price: leaving `UnitPrice` undefined is what lets the
1684
- * pricing walk resolve it (`SetUnitPrice` documents the same rule from the
1685
- * other direction). Seeding it with the catalogue's list price would look
1686
- * helpful and would silently turn every line into a direct-entry price that
1687
- * ignores the customer's price list.
1688
- */
1689
- async AddProduct(option) {
1690
- const line = await this.Order.Lines.Create();
1691
- line.ProductID = option.ID;
1692
- line.Quantity = 1;
1693
- this.onEdited();
1694
- this.ProductQuery = '';
1695
- this.ProductPickerOpen = false;
1696
- // The new line, the cleared box and the closed picker were all assigned AFTER an await, so
1697
- // nothing repaints them on its own. Without this the product just typed appears to vanish.
1698
- this.cdr.detectChanges();
1699
- }
1700
- /* ── Dismissing the pickers ─────────────────────────────────────────────
1701
- *
1702
- * A typeahead that only closes when you pick something is a trap: the list stays over the
1703
- * table, and the only way out is to choose a product you did not want or to clear the box by
1704
- * hand. Clicking away is what everyone tries first.
1705
- */
1706
- /**
1707
- * Close any open picker when the click lands outside all of them.
1708
- *
1709
- * `pointerdown`, not `click`: the list is inside the same subtree, so a pointerdown that
1710
- * started on an option is excluded by the `closest()` test below and the option's own click
1711
- * still fires. Using blur instead would race the click and swallow the selection.
1712
- */
1713
- OnDocumentPointerDown(event) {
1714
- const target = event.target;
1715
- if (target?.closest('.ed-addline, .ed-party'))
1716
- return;
1717
- this.ClosePickers();
1718
- }
1719
- /** Escape closes the open picker without touching what is already on the order. */
1720
- OnEscape() {
1721
- this.ClosePickers();
1722
- }
1723
- /**
1724
- * Clears the SEARCH state only — never a chosen product or party. Guarded so an ordinary click
1725
- * anywhere on the page does not schedule a change-detection pass for nothing.
1726
- */
1727
- ClosePickers() {
1728
- const open = this.ProductQuery !== '' ||
1729
- this.ProductPickerOpen ||
1730
- this.PartyQuery.bill !== '' ||
1731
- this.PartyQuery.ship !== '' ||
1732
- this.PartyMatches.bill.length > 0 ||
1733
- this.PartyMatches.ship.length > 0;
1734
- if (!open)
1735
- return;
1736
- this.ProductQuery = '';
1737
- this.ProductPickerOpen = false;
1738
- this.PartyQuery = { bill: '', ship: '' };
1739
- this.PartyMatches = { bill: [], ship: [] };
1740
- this.cdr.detectChanges();
1741
- }
1742
- /* ── Parties ────────────────────────────────────────────────────────────
1743
- *
1744
- * The parties tab printed raw GUIDs through `mjo-stated-value` and had no
1745
- * inputs at all, so an order's payer could not be set here — the one field
1746
- * `OrderHeaderEntity.Validate()` requires before a confirm.
1747
- */
1748
- /** Search text per role, so bill-to and ship-to can be edited independently. */
1749
- PartyQuery = { bill: '', ship: '' };
1750
- PartyMatches = { bill: [], ship: [] };
1751
- PartySearching = null;
1752
- /**
1753
- * Focusing a party box shows who we have billed most recently, before anything is typed.
1754
- *
1755
- * A desk bills the same handful of accounts over and over, so the last few orders predict the
1756
- * next one better than an empty box does. `RecentCustomers` returns the same shape as
1757
- * `SearchCustomers`, so one template renders both and selection behaves identically.
1758
- */
1759
- async OnPartyFocus(role) {
1760
- if (this.PartyQuery[role].trim())
1761
- return; // already searching — do not overwrite the results
1762
- this.PartySearching = role;
1763
- try {
1764
- this.PartyMatches[role] = await RecentCustomers();
1765
- }
1766
- finally {
1767
- this.PartySearching = null;
1768
- this.cdr.detectChanges();
1769
- }
1770
- }
1771
- partyTimer = null;
1772
- /**
1773
- * Search as they type, DEBOUNCED.
1774
- *
1775
- * This is bound to `ngModelChange`, so without the timer every keystroke is a server
1776
- * round-trip — eight requests to spell "Northgate", each a LIKE scan, arriving out of order so
1777
- * a slow early one can overwrite a fast late one. Fast entry already solved this the same way;
1778
- * this had simply not learned it.
1779
- */
1780
- SearchParty(role) {
1781
- if (this.partyTimer)
1782
- clearTimeout(this.partyTimer);
1783
- const q = this.PartyQuery[role].trim();
1784
- if (q.length < 2) {
1785
- // Falling back to recents rather than to nothing: clearing the box should return you
1786
- // to where focusing it started, not to an empty list.
1787
- void this.OnPartyFocus(role);
1788
- return;
1789
- }
1790
- this.partyTimer = setTimeout(async () => {
1791
- this.PartySearching = role;
1792
- try {
1793
- this.PartyMatches[role] = await SearchCustomers(q);
1794
- }
1795
- finally {
1796
- this.PartySearching = null;
1797
- // Lands from a timer AND an awaited request, so nothing is watching this — it has
1798
- // to tick explicitly or the results never paint.
1799
- this.cdr.detectChanges();
1800
- }
1801
- }, 250);
1802
- }
1803
- /**
1804
- * A customer is an organization OR a person, never both — the database says so
1805
- * (`CK_*_Party`), so the picker sets one and clears the other rather than
1806
- * leaving whichever was chosen first behind.
1807
- */
1808
- ChooseParty(role, match) {
1809
- const party = match.IsOrganization
1810
- ? { OrganizationID: match.ID, PersonID: null }
1811
- : { PersonID: match.ID, OrganizationID: null };
1812
- this.applyParty(role, party);
1813
- this.onEdited();
1814
- this.PartyLabels[role] = match.Name;
1815
- this.PartyQuery[role] = '';
1816
- this.PartyMatches[role] = [];
1817
- }
1818
- ClearParty(role) {
1819
- const empty = { OrganizationID: null, PersonID: null };
1820
- this.applyParty(role, null);
1821
- this.onEdited();
1822
- this.PartyLabels[role] = null;
1823
- }
1824
- /**
1825
- * Display names for the chosen parties.
1826
- *
1827
- * Held here rather than read back from the draft because the draft stores IDs
1828
- * only — showing a GUID is what the old read-only tab did, and it told the
1829
- * user nothing.
1830
- */
1831
- PartyLabels = { bill: null, ship: null };
1832
- PartyIdFor(role) {
1833
- const h = this.Order;
1834
- if (!h)
1835
- return null;
1836
- return role === 'bill' ? (h.BillToOrganizationID ?? h.BillToPersonID ?? null) : (h.ShipToOrganizationID ?? h.ShipToPersonID ?? null);
1837
- }
1838
- /* ── Initial payment ────────────────────────────────────────────────────
1839
- *
1840
- * INTENT, not a payment. On confirm this becomes a real PaymentHeader in the same
1841
- * transaction as the booking; until then it is two fields on the draft. The tab said as much
1842
- * and then showed both of them read-only, so an order taken over the counter could not record
1843
- * that it had been paid for.
1844
- */
1845
- /** True when there is a real choice to make — one company needs no picker. */
1846
- get HasCompanyChoice() {
1847
- return this.IsEditable && this.Companies.length > 1;
1848
- }
1849
- /** The owning company's name, for the read-only case. */
1850
- get OwningCompanyName() {
1851
- const id = this.Order?.CompanyID;
1852
- return this.Companies.find((c) => c.ID === id)?.Name ?? '—';
1853
- }
1854
- /**
1855
- * Change which company owns the order.
1856
- *
1857
- * Only meaningful while the order is a draft: the owning company anchors the document and the
1858
- * ledger it books into, so moving it after confirm would rewrite history rather than edit a form.
1859
- * `IsEditable` already gates the control.
1860
- */
1861
- SetOwningCompany(companyID) {
1862
- if (!companyID)
1863
- return;
1864
- this.Order.CompanyID = companyID;
1865
- this.onEdited();
1866
- }
1867
- /** The `PaymentType` row behind the chosen tender, or null for invoice-on-terms. */
1868
- get SelectedTenderType() {
1869
- const id = this.Order?.InitialPaymentTypeID;
1870
- if (!id)
1871
- return null;
1872
- return this.Tenders.find((t) => t.ID === id) ?? null;
1873
- }
1874
- /** True when this tender cannot be captured without a check/wire/transfer number. */
1875
- get RequiresReference() {
1876
- return this.SelectedTenderType?.RequiresReference === true;
1877
- }
1878
- /** The reference as typed. Read from the DRAFT, so it survives a tab switch or a remount. */
1879
- get Reference() {
1880
- return this.Order?.InitialPaymentReference ?? '';
1881
- }
1882
- SetReference(value) {
1883
- this.restateIntent({ Reference: value });
1884
- }
1885
- SetTender(paymentTypeID) {
1886
- if (!paymentTypeID) {
1887
- // Choosing the blank option means "invoice on terms" — clear the intent rather than
1888
- // leaving an amount attached to no tender, which the server would reject.
1889
- this.Order.InitialPaymentTypeID = null;
1890
- this.Order.InitialPaymentAmount = 0;
1891
- this.Order.InitialPaymentReference = null;
1892
- this.onEdited();
1893
- return;
1894
- }
1895
- // Switching tender drops a reference typed for the previous one: a check number is not a
1896
- // wire confirmation, and carrying it across would put the wrong id on the payment.
1897
- this.restateIntent({ PaymentTypeID: paymentTypeID, Reference: '' });
1898
- }
1899
- /**
1900
- * Re-state the WHOLE initial-payment intent with one part changed.
1901
- *
1902
- * `SetInitialPayment` deliberately takes the complete intent, so patching one field means
1903
- * restating the others — and the two setters here used to omit the reference entirely, which
1904
- * would have wiped a typed check number the moment the amount changed.
1905
- */
1906
- restateIntent(patch) {
1907
- const paymentTypeID = patch.PaymentTypeID !== undefined ? patch.PaymentTypeID : (this.Order.InitialPaymentTypeID ?? null);
1908
- const requiresReference = this.Tenders.find((t) => t.ID === paymentTypeID)?.RequiresReference === true;
1909
- this.Order.InitialPaymentTypeID = paymentTypeID;
1910
- this.Order.InitialPaymentAmount =
1911
- patch.Amount !== undefined ? patch.Amount : (this.Order.InitialPaymentAmount ?? 0);
1912
- this.Order.InitialPaymentReference =
1913
- patch.Reference !== undefined ? patch.Reference : (this.Order.InitialPaymentReference ?? null);
1914
- // Whether this tender needs a reference is a property of the TENDER, not of the order, so it
1915
- // is not stored — it is looked up when the rule is evaluated. The draft carried a copy of it
1916
- // that could go stale against the PaymentType row.
1917
- this.RequiresPaymentReference = requiresReference;
1918
- this.onEdited();
1919
- }
1920
- SetInitialAmount(raw) {
1921
- const n = Number.parseFloat(raw.replace(/[^0-9.\-]/g, ''));
1922
- this.restateIntent({ Amount: Number.isFinite(n) && n >= 0 ? n : 0 });
1923
- }
1924
- /**
1925
- * Offer the balance as the obvious amount — the common case is paying in full.
1926
- *
1927
- * ⚠ It offers the NET subtotal, not the gross. See the same note in
1928
- * `fast-entry.page.ts` (`applyTenderIntent`): `createInitialPayment` takes the
1929
- * stated amount at face value and has no pay-in-full intent to settle against the
1930
- * total it computes, and the client can no longer know that total. Harmless while
1931
- * no charge or tax rule is configured; it UNDER-PAYS the moment one is. The fix is
1932
- * an engine-side intent, and it is backlogged rather than guessed at here.
1933
- */
1934
- PayInFull() {
1935
- this.restateIntent({ Amount: this.Totals?.NetTotal ?? 0 });
1936
- }
1937
- /**
1938
- * Order types, from the draft's own union rather than a list typed here — CodeGen widens that
1939
- * union when the CHECK constraint gains a value, and a hand-copied list would not follow.
1940
- */
1941
- OrderTypes = [
1942
- 'Sale',
1943
- 'Return',
1944
- 'Cancellation',
1945
- 'Amendment',
1946
- 'AccountCredit',
1947
- ];
1948
- /** The "no tender" row. A real option meaning invoice on terms, not a placeholder. */
1949
- TenderNone = { ID: '', Name: '— invoice on terms —' };
1950
- SetOrderType(value) {
1951
- this.Order.OrderType = value;
1952
- this.onEdited();
1953
- }
1954
- /**
1955
- * `<input type="date">` will only accept `yyyy-MM-dd`. The draft stores whatever it was given —
1956
- * often a full ISO timestamp from a loaded order — and handing that to the input makes the field
1957
- * render EMPTY with no error, which reads as "this order has no date".
1958
- */
1959
- /**
1960
- * True once pricing has RETURNED, so an empty price source means "there is no rule" rather
1961
- * than "not yet". Drives the price badge's missing-rule state.
1962
- *
1963
- * Deliberately NOT `!!Pricing.Result` alone: a stale result from the previous keystroke is
1964
- * present while the next pass is in flight, and treating that as settled would flash
1965
- * "no price rule" at a line that is simply being recomputed.
1966
- */
1967
- get PricingSettled() {
1968
- return !this.Pricing.Loading && !!this.Pricing.Result;
1969
- }
1970
- DateValue(raw) {
1971
- if (!raw)
1972
- return '';
1973
- // `<input type="date">` accepts only yyyy-MM-dd. The entity hands back a real Date now
1974
- // rather than whatever string the draft was given, so this normalises both: a Date is
1975
- // formatted in LOCAL time, because toISOString() would shift a date-only value across the
1976
- // day boundary for anyone west of UTC and silently show yesterday.
1977
- if (raw instanceof Date) {
1978
- const y = raw.getFullYear();
1979
- const m = String(raw.getMonth() + 1).padStart(2, '0');
1980
- const d = String(raw.getDate()).padStart(2, '0');
1981
- return `${y}-${m}-${d}`;
1982
- }
1983
- return raw.length >= 10 ? raw.slice(0, 10) : raw;
1984
- }
1985
- /**
1986
- * True when this header field is showing a DEFAULT the user has not confirmed — drives the
1987
- * muted styling and the explanatory tooltip on the identity strip.
1988
- *
1989
- * Guarded on `Draft` because the editor renders before a draft is bound in the imperative path.
1990
- */
1991
- IsDefault(field) {
1992
- // A field the user has not touched. BaseEntity tracks this per field, so the draft's
1993
- // parallel bookkeeping is unnecessary.
1994
- return this.Order?.GetFieldByName(field)?.Dirty === false;
1995
- }
1996
- /** Free-text and date header fields, written straight through to the draft. */
1997
- SetHeaderField(field, raw) {
1998
- const value = raw.trim();
1999
- this.Order.Set(field, value || null);
2000
- this.onEdited();
2001
- }
2002
- /*
2003
- * No re-pricing call here on purpose. `ngOnInit` subscribes to the draft, and every mutator
2004
- * above calls `onEdited()`, which reprices — so an explicit
2005
- * SchedulePricing in each mutator would be a second debounce for the same change and would
2006
- * quietly suggest the subscription is not doing its job.
2007
- */
2008
- Open(line) {
2009
- this.OpenLine = line;
2010
- this.LineOpened.emit(line);
2011
- }
2012
- CloseDrawer() {
2013
- this.OpenLine = null;
2014
- }
2015
- /* ── Totals ladder (Lines tab) ──────────────────────────────────────── */
2016
- /**
2017
- * The decomposition ladder, as far as the browser can honestly go.
2018
- *
2019
- * It stops at the net subtotal, and SAYS it stops there. Charges and tax used to
2020
- * appear here because the rolled-back preview had run the engine's whole walk;
2021
- * without that run they are unknown, and an unknown rendered as `$0.00` on the
2022
- * screen that tells someone what they are committing to is the exact defect this
2023
- * ladder was built to prevent. A missing row is honest; a zero is not.
2024
- */
2025
- get LadderRows() {
2026
- const t = this.Totals;
2027
- if (!t)
2028
- return [];
2029
- const rows = [{ Label: 'Subtotal at list', Amount: t.ListSubtotal }];
2030
- if (t.DiscountTotal > 0) {
2031
- rows.push({ Label: 'Discounts', Amount: t.DiscountTotal, IsSub: true, IsCredit: true });
2032
- }
2033
- rows.push({
2034
- Label: 'Net before tax & charges',
2035
- Amount: t.NetTotal,
2036
- IsTotal: true,
2037
- Why: 'Charges, tax and promotions are decided when the order is confirmed, inside the same ' +
2038
- 'transaction that books it. They are not shown here because they are not known here — ' +
2039
- 'the confirmed order is what states the final amount.',
2040
- });
2041
- return rows;
2042
- }
2043
- /* ── Actions ────────────────────────────────────────────────────────── */
2044
- get IsEditable() {
2045
- // Edit gating rides the status. After confirming, corrections are reversing
2046
- // orders — so the fields lock and the verbs change rather than a Save
2047
- // sitting there greyed out with no explanation.
2048
- return this.Status === 'Draft' || this.Status === 'Quoted';
2049
- }
2050
- /**
2051
- * NOT GATED ON A PRICE. It used to require a returned preview, so a failed or
2052
- * still-running preview left a completed order permanently unconfirmable with a
2053
- * dead button and no reason on it. The engine decides whether an order can be
2054
- * confirmed; this checks only what the client can know for itself.
2055
- */
2056
- get CanConfirm() {
2057
- return this.IsEditable && this.Order?.Validate().Success === true;
2058
- }
2059
- /** Errors worth surfacing above the tabs, so a red dot is never the only clue. */
2060
- get Issues() {
2061
- // ONLY WHILE THE ORDER CAN STILL BE CONFIRMED. `Validate()` answers "could this be
2062
- // confirmed as it stands", which is a question with no meaning once it HAS been — a
2063
- // confirmed order was showing "1 thing to sort out before this can confirm", and a red dot
2064
- // on Parties, for an order already booked to the ledger. That reads as "something is wrong
2065
- // with this order" when nothing is.
2066
- if (!this.IsEditable)
2067
- return [];
2068
- return (this.Order?.Validate().Errors ?? []).map((e) => ({
2069
- Code: e.Source ?? 'INVALID',
2070
- Section: OrderHeaderEntity.SectionForField(e.Source),
2071
- Severity: 'error',
2072
- Message: e.Message,
2073
- }));
2074
- }
2075
- async SaveDraft() {
2076
- await this.Order.SaveOrThrow();
2077
- this.Saved.emit(this.Order);
2078
- }
2079
- RequestConfirm() {
2080
- if (!this.CanConfirm)
2081
- return;
2082
- this.ConfirmRequested.emit(this.Order);
2083
- }
2084
- /**
2085
- * Called by every setter on this page after it mutates the order.
2086
- *
2087
- * Reprices (debounced) and repaints. Both matter on a zoneless, imperatively-created page: the
2088
- * pricing callback lands from a timer and an awaited round trip, so assigning alone paints
2089
- * nothing and the strip stays on "— resolving…" while CanConfirm never turns true.
2090
- */
2091
- onEdited() {
2092
- this.orders.SchedulePricing(this.Order, (state) => {
2093
- this.Pricing = state;
2094
- this.cdr.detectChanges();
2095
- });
2096
- this.cdr.detectChanges();
2097
- }
2098
- /** Apply a chosen party to the bill-to or ship-to side. Null clears it. */
2099
- applyParty(role, party) {
2100
- if (role === 'bill') {
2101
- this.Order.BillToPersonID = party?.PersonID ?? null;
2102
- this.Order.BillToOrganizationID = party?.OrganizationID ?? null;
2103
- }
2104
- else {
2105
- this.Order.ShipToPersonID = party?.PersonID ?? null;
2106
- this.Order.ShipToOrganizationID = party?.OrganizationID ?? null;
2107
- this.Order.ShipToAddressID = party?.AddressID ?? null;
2108
- }
2109
- }
2110
- /** Whether the user typed this line's price rather than the engine resolving one. */
2111
- PriceStated(line) {
2112
- return line.GetFieldByName('UnitPrice')?.Dirty === true;
2113
- }
2114
- /** Promotion codes presented but not yet saved — screen state, held by the entry service. */
2115
- get PromotionCodes() {
2116
- return this.Order.PromotionCodes.Codes;
2117
- }
2118
- static ɵfac = function MJOOrderEditorPageComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJOOrderEditorPageComponent)(); };
2119
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJOOrderEditorPageComponent, selectors: [["mjo-order-editor-page"]], hostBindings: function MJOOrderEditorPageComponent_HostBindings(rf, ctx) { if (rf & 1) {
2120
- i0.ɵɵlistener("pointerdown", function MJOOrderEditorPageComponent_pointerdown_HostBindingHandler($event) { return ctx.OnDocumentPointerDown($event); }, i0.ɵɵresolveDocument)("keydown.escape", function MJOOrderEditorPageComponent_keydown_escape_HostBindingHandler() { return ctx.OnEscape(); }, i0.ɵɵresolveDocument);
2121
- } }, inputs: { Order: "Order", Catalog: "Catalog", Companies: "Companies", Status: "Status", OrderNumber: "OrderNumber", ShowActions: "ShowActions", Tenders: "Tenders", JournalEntries: "JournalEntries" }, outputs: { ConfirmRequested: "ConfirmRequested", Saved: "Saved", LineOpened: "LineOpened", OpenInAccounting: "OpenInAccounting" }, features: [i0.ɵɵNgOnChangesFeature], decls: 48, vars: 26, consts: [[1, "ed-scroll"], [1, "ed-sticky"], [1, "ed-identity"], [1, "l"], [1, "v", "mono"], ["aria-label", "Order type", 1, "ed-identity__input", 3, "ed-identity__input--default", "title", "Data", "ValuePrimitive", "ngModel"], [1, "v"], [1, "ed-identity__cell--wide"], ["aria-label", "Selling company", "TextField", "Name", "ValueField", "ID", 1, "ed-identity__input", 3, "title", "Data", "ValuePrimitive", "ngModel"], ["type", "date", "aria-label", "Order date", 1, "mj-input", "ed-identity__input", 3, "ed-identity__input--default", "title", "ngModel"], ["type", "date", "aria-label", "Due date", 1, "mj-input", "ed-identity__input", 3, "ngModel"], ["type", "text", "aria-label", "Their PO number", "placeholder", "\u2014", 1, "mj-input", "ed-identity__input", "mono", 3, "ngModel"], [1, "row", "wrap", "ed-stage-row"], [3, "BeforeStageChange", "Current", "Stages", "ReadOnly"], [1, "ed-money", 3, "Total", "Paid", "Balance", "ShowPaid", "PaymentStatus"], ["role", "status", 1, "ed-todo"], [1, "ed-tabs", 3, "TabChange", "Tabs", "ActiveKey"], [1, "ed-panes"], [1, "ed-pane"], ["role", "dialog", "aria-label", "Line detail", 1, "mj-slide-in", "is-open", "ed-drawer"], [1, "ed-footer"], ["aria-label", "Order type", 1, "ed-identity__input", 3, "ngModelChange", "title", "Data", "ValuePrimitive", "ngModel"], ["aria-label", "Selling company", "TextField", "Name", "ValueField", "ID", 1, "ed-identity__input", 3, "ngModelChange", "title", "Data", "ValuePrimitive", "ngModel"], ["type", "date", "aria-label", "Order date", 1, "mj-input", "ed-identity__input", 3, "ngModelChange", "title", "ngModel"], ["type", "date", "aria-label", "Due date", 1, "mj-input", "ed-identity__input", 3, "ngModelChange", "ngModel"], ["type", "text", "aria-label", "Their PO number", "placeholder", "\u2014", 1, "mj-input", "ed-identity__input", "mono", 3, "ngModelChange", "ngModel"], ["aria-hidden", "true", 1, "fa-solid", "fa-circle-exclamation", "ed-todo__icon"], [1, "ed-todo__count"], [1, "ed-todo__lead"], [1, "ed-todo__items"], ["type", "button", 1, "ed-todo__item", 3, "title"], ["type", "button", 1, "ed-todo__item", 3, "click", "title"], [1, "ed-addline"], [1, "mj-table-wrap"], [1, "mj-table", "mj-table--lines"], [1, "ed-col-n"], [1, "ed-col-co"], [1, "num", "ed-col-qty"], [1, "num", "ed-col-price"], [1, "num", "ed-col-disc"], [1, "num", "ed-col-net"], ["title", "Decided when the order is confirmed", 1, "num", "ed-col-tax", "muted"], ["title", "Decided when the order is confirmed", 1, "num", "ed-col-total", "muted"], [1, "ed-col-act"], [1, "is-clickable"], [1, "grid-2", "ed-below"], [1, "mj-card"], [1, "mj-card-head"], ["aria-hidden", "true", 1, "fa-solid", "fa-percent"], [1, "mj-card-pad"], [1, "ed-promo", "muted"], [1, "small", "muted"], ["aria-hidden", "true", 1, "fa-solid", "fa-calculator"], [3, "Rows", "Stale"], [1, "ed-addline__field"], ["aria-hidden", "true", 1, "fa-solid", "fa-magnifying-glass"], ["type", "text", "placeholder", "Add a product \u2014 name or SKU", "aria-label", "Add a product to this order", 1, "mj-input", 3, "focus", "ngModelChange", "ngModel"], ["role", "listbox", "aria-label", "Matching products", 1, "ed-addline__matches"], [1, "small", "muted", "ed-addline__none"], ["type", "button", 1, "ed-addline__match", 3, "mousedown"], [1, "nm"], [1, "num"], [1, "is-clickable", 3, "click"], [1, "muted"], [1, "ed-line-nm"], [1, "primary"], [1, "secondary"], [1, "ed-line-conseq"], [1, "mj-chip", "mj-chip--outline"], [1, "num", 3, "click"], ["aria-label", "Quantity", 1, "mj-input", "is-num", "ed-input-qty", 3, "change", "value", "disabled"], ["placeholder", "resolve", "aria-label", "Unit price", 1, "mj-input", "is-num", "ed-input-price", 3, "change", "value", "disabled"], [3, "Source", "Settled", "Overridden"], [1, "secondary", "mj-money--credit"], [1, "mj-money--credit"], [1, "num", "strong"], ["title", "Decided when the order is confirmed", 1, "num", "muted"], [3, "click"], ["type", "button", "aria-label", "Remove line", 1, "mj-iconbtn"], ["Kind", "fulfillment"], ["Kind", "untaxable"], ["type", "button", "aria-label", "Remove line", 1, "mj-iconbtn", 3, "click"], ["aria-hidden", "true", 1, "fa-regular", "fa-trash-can"], ["colspan", "10"], [1, "mj-empty", "ed-empty"], ["aria-hidden", "true", 1, "fa-solid", "fa-cart-plus"], [1, "t"], [1, "small"], [1, "is-total"], ["colspan", "6"], [1, "num", "muted"], ["aria-hidden", "true", 1, "fa-solid", "fa-circle-minus", 2, "color", "var(--mj-text-disabled)"], [1, "ed-promo__body"], [1, "mono"], [1, "mj-num"], [1, "grid-2"], ["aria-hidden", "true", 1, "fa-solid", "fa-file-invoice-dollar"], [1, "right"], [1, "ed-party"], [1, "ed-party__label"], [1, "ed-party__chosen"], ["Label", "Terms", "From", "organization default"], [1, "small", "muted", "ed-note"], ["aria-hidden", "true", 1, "fa-solid", "fa-truck-fast"], ["Label", "Address"], [1, "mj-chip"], ["type", "button", "aria-label", "Clear customer", 1, "mj-iconbtn"], ["type", "button", "aria-label", "Clear customer", 1, "mj-iconbtn", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-xmark"], [1, "ed-party__field"], ["type", "text", "placeholder", "Search people and organizations", "aria-label", "Customer", 1, "mj-input", 3, "ngModelChange", "focus", "ngModel"], ["role", "listbox", "aria-label", "Matching customers", 1, "ed-party__matches"], ["type", "button", 1, "ed-party__match", 3, "mousedown"], ["aria-hidden", "true"], ["type", "button", "aria-label", "Clear recipient", 1, "mj-iconbtn"], ["type", "button", "aria-label", "Clear recipient", 1, "mj-iconbtn", 3, "click"], ["type", "text", "placeholder", "Leave empty to use the customer", "aria-label", "Recipient", 1, "mj-input", 3, "ngModelChange", "focus", "ngModel"], [1, "mj-empty", "ed-empty", "muted"], ["aria-hidden", "true", 1, "fa-solid", "fa-receipt"], ["aria-hidden", "true", 1, "fa-solid", "fa-credit-card"], [1, "mj-chip", "mj-chip--info"], [1, "mj-card", "ed-block"], ["aria-hidden", "true", 1, "fa-solid", "fa-list-check"], [1, "right", "small", "muted"], [1, "mj-table", "mj-table--compact"], [1, "mj-card-pad", "small", "muted"], ["aria-hidden", "true", 1, "fa-solid", "fa-calendar-day"], ["Label", "Due", "From", "set when the order confirms"], ["Label", "Balance"], [1, "ed-field"], ["for", "ed-tender", 1, "ed-field__label"], ["id", "ed-tender", "TextField", "Name", "ValueField", "ID", 3, "ngModelChange", "Data", "ValuePrimitive", "DefaultItem", "ngModel"], [1, "ed-tender-ref"], ["for", "ed-tender-ref", 1, "ed-field__label"], ["aria-hidden", "true", 1, "ed-tender-ref__req"], ["id", "ed-tender-ref", "autocomplete", "off", 1, "mj-input", 3, "input", "value", "placeholder"], [1, "ed-tender-ref__hint", "small", "muted"], ["for", "ed-payamt", 1, "ed-field__label"], [1, "ed-field__row"], ["id", "ed-payamt", "type", "text", "inputmode", "decimal", 1, "mj-input", "is-num", 3, "ngModelChange", "ngModel"], ["type", "button", "mjButton", "", "variant", "outline", "title", "Use the order total", 3, "click"], ["Label", "Tender"], ["Label", "Amount"], [1, "mono", "small"], ["colspan", "3", 1, "small", "muted"], ["EmptyText", "Nothing booked yet \u2014 confirm the order to create its entries.", 3, "OpenInAccounting", "Entries", "Pending"], ["aria-hidden", "true", 1, "fa-solid", "fa-tags"], [1, "ed-dim"], ["aria-hidden", "true", 1, "fa-solid", "fa-clock-rotate-left"], [3, "Params", "Height", "EditMode", "ShowNewButton", "ShowDeleteButton", "AllowDelete", "ShowPager"], [1, "mj-slide-in-head"], ["type", "button", "aria-label", "Close", 1, "mj-iconbtn", 3, "click"], [1, "mj-slide-in-body"], [1, "sec-label"], ["Label", "Ship-to address", "From", "falls back to the header"], ["Label", "Ship-to person", "From", "falls back independently"], ["Label", "Ship-to organization", "From", "falls back independently"], [1, "sec-label", "ed-drawer__section"], ["Label", "Service period", "From", "as entered"], ["Label", "Reverses"], ["Label", "Renews"], [1, "mj-slide-in-foot"], ["type", "button", "mjButton", "", "variant", "primary", "size", "sm", 3, "click"], [1, "small", "muted", "spacer"], ["type", "button", "mjButton", "", "variant", "outline", 3, "click"], ["aria-hidden", "true", 1, "fa-regular", "fa-floppy-disk"], ["type", "button", "mjButton", "", "variant", "primary", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-check"], ["type", "button", "mjButton", "", "variant", "outline"], ["aria-hidden", "true", 1, "fa-solid", "fa-rotate-left"], ["aria-hidden", "true", 1, "fa-solid", "fa-hand-holding-dollar"]], template: function MJOOrderEditorPageComponent_Template(rf, ctx) { if (rf & 1) {
2122
- i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "div")(4, "span", 3);
2123
- i0.ɵɵtext(5, "Order");
2124
- i0.ɵɵelementEnd();
2125
- i0.ɵɵelementStart(6, "span", 4);
2126
- i0.ɵɵtext(7);
2127
- i0.ɵɵelementEnd()();
2128
- i0.ɵɵelementStart(8, "div")(9, "span", 3);
2129
- i0.ɵɵtext(10, "Type");
2130
- i0.ɵɵelementEnd();
2131
- i0.ɵɵconditionalCreate(11, MJOOrderEditorPageComponent_Conditional_11_Template, 1, 6, "mj-dropdown", 5)(12, MJOOrderEditorPageComponent_Conditional_12_Template, 2, 1, "span", 6);
2132
- i0.ɵɵelementEnd();
2133
- i0.ɵɵelementStart(13, "div", 7)(14, "span", 3);
2134
- i0.ɵɵtext(15, "Selling as");
2135
- i0.ɵɵelementEnd();
2136
- i0.ɵɵconditionalCreate(16, MJOOrderEditorPageComponent_Conditional_16_Template, 1, 4, "mj-dropdown", 8)(17, MJOOrderEditorPageComponent_Conditional_17_Template, 2, 1, "span", 6);
2137
- i0.ɵɵelementEnd();
2138
- i0.ɵɵelementStart(18, "div")(19, "span", 3);
2139
- i0.ɵɵtext(20, "Order date");
2140
- i0.ɵɵelementEnd();
2141
- i0.ɵɵconditionalCreate(21, MJOOrderEditorPageComponent_Conditional_21_Template, 1, 4, "input", 9)(22, MJOOrderEditorPageComponent_Conditional_22_Template, 2, 1, "span", 6);
2142
- i0.ɵɵelementEnd();
2143
- i0.ɵɵelementStart(23, "div")(24, "span", 3);
2144
- i0.ɵɵtext(25, "Due");
2145
- i0.ɵɵelementEnd();
2146
- i0.ɵɵconditionalCreate(26, MJOOrderEditorPageComponent_Conditional_26_Template, 1, 1, "input", 10)(27, MJOOrderEditorPageComponent_Conditional_27_Template, 2, 1, "span", 6);
2147
- i0.ɵɵelementEnd();
2148
- i0.ɵɵelementStart(28, "div")(29, "span", 3);
2149
- i0.ɵɵtext(30, "Their PO");
2150
- i0.ɵɵelementEnd();
2151
- i0.ɵɵconditionalCreate(31, MJOOrderEditorPageComponent_Conditional_31_Template, 1, 1, "input", 11)(32, MJOOrderEditorPageComponent_Conditional_32_Template, 2, 1, "span", 4);
2152
- i0.ɵɵelementEnd()();
2153
- i0.ɵɵelementStart(33, "div", 12)(34, "mjo-status-stepper", 13);
2154
- i0.ɵɵlistener("BeforeStageChange", function MJOOrderEditorPageComponent_Template_mjo_status_stepper_BeforeStageChange_34_listener($event) { return ctx.OnBeforeStageChange($event); });
2155
- i0.ɵɵelementEnd()();
2156
- i0.ɵɵelement(35, "mjo-money-strip", 14);
2157
- i0.ɵɵconditionalCreate(36, MJOOrderEditorPageComponent_Conditional_36_Template, 9, 1, "div", 15);
2158
- i0.ɵɵelementStart(37, "mj-tab-nav", 16);
2159
- i0.ɵɵlistener("TabChange", function MJOOrderEditorPageComponent_Template_mj_tab_nav_TabChange_37_listener($event) { return ctx.SelectTabKey($event); });
2160
- i0.ɵɵelementEnd()();
2161
- i0.ɵɵelementStart(38, "div", 17);
2162
- i0.ɵɵconditionalCreate(39, MJOOrderEditorPageComponent_Conditional_39_Template, 47, 6, "div", 18);
2163
- i0.ɵɵconditionalCreate(40, MJOOrderEditorPageComponent_Conditional_40_Template, 46, 4, "div", 18);
2164
- i0.ɵɵconditionalCreate(41, MJOOrderEditorPageComponent_Conditional_41_Template, 8, 1, "div", 18);
2165
- i0.ɵɵconditionalCreate(42, MJOOrderEditorPageComponent_Conditional_42_Template, 58, 12, "div", 18);
2166
- i0.ɵɵconditionalCreate(43, MJOOrderEditorPageComponent_Conditional_43_Template, 25, 4, "div", 18);
2167
- i0.ɵɵconditionalCreate(44, MJOOrderEditorPageComponent_Conditional_44_Template, 3, 1, "div", 18);
2168
- i0.ɵɵconditionalCreate(45, MJOOrderEditorPageComponent_Conditional_45_Template, 3, 1, "div", 18);
2169
- i0.ɵɵelementEnd()();
2170
- i0.ɵɵconditionalCreate(46, MJOOrderEditorPageComponent_Conditional_46_Template, 43, 10, "aside", 19);
2171
- i0.ɵɵconditionalCreate(47, MJOOrderEditorPageComponent_Conditional_47_Template, 3, 1, "div", 20);
2172
- } if (rf & 2) {
2173
- i0.ɵɵadvance(7);
2174
- i0.ɵɵtextInterpolate(ctx.OrderNumber ?? "New draft");
2175
- i0.ɵɵadvance(4);
2176
- i0.ɵɵconditional(ctx.IsEditable ? 11 : 12);
2177
- i0.ɵɵadvance(5);
2178
- i0.ɵɵconditional(ctx.HasCompanyChoice ? 16 : 17);
2179
- i0.ɵɵadvance(5);
2180
- i0.ɵɵconditional(ctx.IsEditable ? 21 : 22);
2181
- i0.ɵɵadvance(5);
2182
- i0.ɵɵconditional(ctx.IsEditable ? 26 : 27);
2183
- i0.ɵɵadvance(5);
2184
- i0.ɵɵconditional(ctx.IsEditable ? 31 : 32);
2185
- i0.ɵɵadvance(3);
2186
- i0.ɵɵproperty("Current", ctx.Status)("Stages", ctx.Stages)("ReadOnly", !ctx.IsEditable);
2187
- i0.ɵɵadvance();
2188
- i0.ɵɵproperty("Total", ctx.DisplayTotal)("Paid", ctx.DisplayPaid)("Balance", ctx.DisplayBalance)("ShowPaid", ctx.IsPersisted)("PaymentStatus", ctx.DisplayPaymentStatus);
2189
- i0.ɵɵadvance();
2190
- i0.ɵɵconditional(ctx.Issues.length ? 36 : -1);
2191
- i0.ɵɵadvance();
2192
- i0.ɵɵproperty("Tabs", ctx.TabNav)("ActiveKey", ctx.ActiveTab);
2193
- i0.ɵɵadvance(2);
2194
- i0.ɵɵconditional(ctx.ActiveTab === "lines" ? 39 : -1);
2195
- i0.ɵɵadvance();
2196
- i0.ɵɵconditional(ctx.ActiveTab === "parties" ? 40 : -1);
2197
- i0.ɵɵadvance();
2198
- i0.ɵɵconditional(ctx.ActiveTab === "charges" ? 41 : -1);
2199
- i0.ɵɵadvance();
2200
- i0.ɵɵconditional(ctx.ActiveTab === "payment" ? 42 : -1);
2201
- i0.ɵɵadvance();
2202
- i0.ɵɵconditional(ctx.ActiveTab === "accounting" ? 43 : -1);
2203
- i0.ɵɵadvance();
2204
- i0.ɵɵconditional(ctx.ActiveTab === "journal" ? 44 : -1);
2205
- i0.ɵɵadvance();
2206
- i0.ɵɵconditional(ctx.ActiveTab === "subscriptions" ? 45 : -1);
2207
- i0.ɵɵadvance();
2208
- i0.ɵɵconditional(ctx.OpenLine ? 46 : -1);
2209
- i0.ɵɵadvance();
2210
- i0.ɵɵconditional(ctx.ShowActions ? 47 : -1);
2211
- } }, dependencies: [MJButtonDirective, MJDropdownComponent, MJTabNavComponent,
2212
- EntityViewerModule, i1.EntityDataGridComponent, CommonModule,
2213
- FormsModule, i2.DefaultValueAccessor, i2.NgControlStatus, i2.NgModel, MJOMoneyStripComponent,
2214
- MJOStatusStepperComponent,
2215
- MJOJournalEntryPreviewComponent,
2216
- MJODecompositionLadderComponent,
2217
- MJOConsequenceChipComponent,
2218
- MJOPriceSourceBadgeComponent,
2219
- MJOStatedValueComponent,
2220
- MJOMoneyPipe], styles: ["\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n padding: 0;\n}\n\n\n\n\n\n.ed-scroll[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n padding: var(--mj-space-6);\n}\n\n\n\n\n.ed-panes[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n.ed-sticky[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n background: var(--mj-bg-surface);\n margin: calc(-1 * var(--mj-space-6)) calc(-1 * var(--mj-space-6)) 0;\n padding: var(--mj-space-6) var(--mj-space-6) 0;\n}\n\n.ed-identity[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface);\n overflow: hidden;\n margin-bottom: var(--mj-space-3);\n}\n\n.ed-identity[_ngcontent-%COMP%] > div[_ngcontent-%COMP%] {\n padding: var(--mj-space-3) var(--mj-space-4);\n border-right: 1px solid var(--mj-border-subtle);\n}\n\n.ed-identity[_ngcontent-%COMP%] > div[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n\n\n\n\n.ed-identity[_ngcontent-%COMP%] > div.ed-identity__cell--wide[_ngcontent-%COMP%] {\n grid-column: span 2;\n}\n\n.ed-identity[_ngcontent-%COMP%] .l[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: var(--mj-font-bold);\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--mj-text-muted);\n display: block;\n margin-bottom: 3px;\n}\n\n.ed-identity[_ngcontent-%COMP%] .v[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: var(--mj-font-medium);\n}\n\n.ed-stage-row[_ngcontent-%COMP%] {\n gap: var(--mj-space-4);\n}\n\n.ed-money[_ngcontent-%COMP%] {\n display: block;\n margin-top: var(--mj-space-3);\n}\n\n.ed-issues[_ngcontent-%COMP%] {\n margin-top: var(--mj-space-3);\n}\n\n.ed-issues__list[_ngcontent-%COMP%] {\n margin: var(--mj-space-2) 0 0;\n padding-left: var(--mj-space-4);\n}\n\n.ed-tabs[_ngcontent-%COMP%] {\n margin-top: var(--mj-space-4);\n}\n\n\n\n\n.ed-pane[_ngcontent-%COMP%] {\n padding-top: var(--mj-space-4);\n}\n\n.ed-below[_ngcontent-%COMP%] {\n margin-top: var(--mj-space-4);\n}\n\n.ed-note[_ngcontent-%COMP%] {\n margin-top: var(--mj-space-3);\n}\n\n.ed-pad[_ngcontent-%COMP%] {\n padding: var(--mj-space-4);\n}\n\n.ed-empty[_ngcontent-%COMP%] {\n padding: var(--mj-space-8);\n}\n\n\n\n\n.ed-col-n[_ngcontent-%COMP%] { width: 30px; }\n.ed-col-co[_ngcontent-%COMP%] { width: 84px; }\n.ed-col-qty[_ngcontent-%COMP%] { width: 80px; }\n.ed-col-price[_ngcontent-%COMP%] { width: 150px; }\n.ed-col-disc[_ngcontent-%COMP%] { width: 110px; }\n.ed-col-net[_ngcontent-%COMP%] { width: 120px; }\n.ed-col-tax[_ngcontent-%COMP%] { width: 110px; }\n.ed-col-total[_ngcontent-%COMP%] { width: 120px; }\n.ed-col-act[_ngcontent-%COMP%] { width: 36px; }\n.ed-col-seq[_ngcontent-%COMP%] { width: 60px; }\n\n.ed-line-nm[_ngcontent-%COMP%] {\n display: flex;\n align-items: baseline;\n gap: var(--mj-space-2);\n}\n\n.ed-line-conseq[_ngcontent-%COMP%] {\n display: flex;\n gap: 5px;\n flex-wrap: wrap;\n margin-top: 4px;\n}\n\n.ed-input-qty[_ngcontent-%COMP%] { width: 64px; }\n.ed-input-price[_ngcontent-%COMP%] { width: 100px; }\n\n\n\n\n.ed-base[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 4px var(--mj-space-4);\n font-size: 12.5px;\n padding: var(--mj-space-3) var(--mj-space-4);\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n}\n\n.ed-base[_ngcontent-%COMP%] .amt[_ngcontent-%COMP%] {\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n\n.ed-base[_ngcontent-%COMP%] .tot[_ngcontent-%COMP%] {\n border-top: 1px solid var(--mj-border-strong);\n padding-top: 5px;\n margin-top: 3px;\n font-weight: var(--mj-font-semibold);\n}\n\n.ed-taxwhy[_ngcontent-%COMP%] {\n padding: var(--mj-space-2) 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.ed-taxwhy[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n\n\n\n.ed-promo[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: var(--mj-space-2);\n padding: var(--mj-space-2) 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.ed-promo[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.ed-promo__body[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n\n\n\n.ed-drawer__section[_ngcontent-%COMP%] {\n margin-top: var(--mj-space-4);\n}\n\n\n\n\n.ed-footer[_ngcontent-%COMP%] {\n \n\n\n\n\n flex: none;\n box-shadow: var(--mj-shadow-md);\n margin: 0;\n padding: var(--mj-space-3) var(--mj-space-6);\n background: var(--mj-bg-surface);\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n flex-wrap: wrap;\n}\n\n\n\n\n@media (max-width: 760px) {\n \n\n .ed-scroll[_ngcontent-%COMP%] {\n padding: var(--mj-space-4);\n }\n\n .ed-sticky[_ngcontent-%COMP%] {\n margin: calc(-1 * var(--mj-space-4)) calc(-1 * var(--mj-space-4)) 0;\n padding: var(--mj-space-4) var(--mj-space-4) 0;\n \n\n position: static;\n }\n\n \n\n\n\n .ed-col-disc[_ngcontent-%COMP%], \n .ed-col-tax[_ngcontent-%COMP%], \n .ed-col-co[_ngcontent-%COMP%], \n [_nghost-%COMP%] .mj-table--lines td:nth-child(3), \n [_nghost-%COMP%] .mj-table--lines td:nth-child(6), \n [_nghost-%COMP%] .mj-table--lines td:nth-child(8) {\n display: none;\n }\n\n .ed-drawer[_ngcontent-%COMP%] {\n width: 100vw;\n }\n\n .ed-footer[_ngcontent-%COMP%] {\n \n\n padding: var(--mj-space-3) var(--mj-space-4);\n }\n}\n\n\n\n\n\n\n\n\n\n\n\n.ed-block[_ngcontent-%COMP%] {\n margin-top: var(--mj-space-4);\n}\n\n\n\n.ed-dim[_ngcontent-%COMP%] {\n display: flex;\n align-items: baseline;\n gap: var(--mj-space-2);\n padding: var(--mj-space-1) 0;\n}\n\n\n\n\n\n\n\n.ed-addline[_ngcontent-%COMP%] {\n position: relative;\n margin-block-end: var(--mj-space-3);\n}\n\n.ed-addline__field[_ngcontent-%COMP%], \n.ed-party__field[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n inline-size: 100%;\n}\n\n.ed-addline__field[_ngcontent-%COMP%] > i[_ngcontent-%COMP%], \n.ed-party__field[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n color: var(--mj-text-tertiary);\n}\n\n.ed-addline__field[_ngcontent-%COMP%] .mj-input[_ngcontent-%COMP%], \n.ed-party__field[_ngcontent-%COMP%] .mj-input[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-inline-size: 0;\n}\n\n\n\n\n.ed-addline__matches[_ngcontent-%COMP%], \n.ed-party__matches[_ngcontent-%COMP%] {\n position: absolute;\n z-index: 20;\n inset-inline: 0;\n margin: var(--mj-space-1) 0 0;\n padding: 0;\n list-style: none;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-md);\n max-block-size: 40cqh;\n overflow-y: auto;\n}\n\n.ed-addline__match[_ngcontent-%COMP%], \n.ed-party__match[_ngcontent-%COMP%] {\n display: flex;\n align-items: baseline;\n gap: var(--mj-space-2);\n inline-size: 100%;\n padding: var(--mj-space-2) var(--mj-space-3);\n background: none;\n border: 0;\n text-align: start;\n cursor: pointer;\n}\n\n.ed-addline__match[_ngcontent-%COMP%]:hover, \n.ed-party__match[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.ed-addline__match[_ngcontent-%COMP%] .nm[_ngcontent-%COMP%], \n.ed-party__match[_ngcontent-%COMP%] .nm[_ngcontent-%COMP%] {\n font-weight: var(--mj-font-medium);\n}\n\n.ed-addline__match[_ngcontent-%COMP%] .num[_ngcontent-%COMP%] {\n margin-inline-start: auto;\n font-variant-numeric: tabular-nums;\n}\n\n.ed-addline__none[_ngcontent-%COMP%] {\n padding: var(--mj-space-2) 0 0;\n}\n\n.ed-party[_ngcontent-%COMP%] {\n position: relative;\n margin-block-end: var(--mj-space-3);\n}\n\n.ed-party__label[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n margin-block-end: var(--mj-space-1);\n}\n\n.ed-party__chosen[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n}\n\n\n\n\n\n.ed-identity__input[_ngcontent-%COMP%] {\n inline-size: 100%;\n min-inline-size: 0;\n padding-block: var(--mj-space-1);\n font-size: var(--mj-text-sm);\n}\n\n\n\n\n\n\n\n\n\n\n.ed-identity__input--default[_ngcontent-%COMP%], \n.ed-identity__input--default[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n\n\n\n\n.ed-field[_ngcontent-%COMP%] {\n margin-block-end: var(--mj-space-3);\n}\n\n.ed-field__label[_ngcontent-%COMP%] {\n display: block;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n margin-block-end: var(--mj-space-1);\n}\n\n.ed-field__row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n}\n\n.ed-field__row[_ngcontent-%COMP%] .mj-input[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-inline-size: 0;\n}\n\n\n\n\n\n\n\n\n.ed-todo[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin-block-start: var(--mj-space-3);\n padding: var(--mj-space-1) var(--mj-space-3);\n \n\n\n background: color-mix(in srgb, var(--mj-color-warning-500) 8%, transparent);\n border-inline-start: 3px solid var(--mj-color-warning-500);\n border-radius: var(--mj-radius-sm);\n font-size: var(--mj-text-xs);\n}\n\n.ed-todo__icon[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-700);\n}\n\n\n\n.ed-todo__count[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-inline-size: 18px;\n block-size: 18px;\n padding-inline: 5px;\n border-radius: 9px;\n background: var(--mj-color-warning-700);\n color: var(--mj-text-inverse, #fff);\n font-weight: var(--mj-font-semibold);\n}\n\n.ed-todo__lead[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n\n.ed-todo__items[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n min-inline-size: 0;\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.ed-todo__item[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n padding: 0;\n background: none;\n border: 0;\n border-block-end: 1px dotted currentColor;\n color: var(--mj-color-warning-700);\n font: inherit;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.ed-todo__item[_ngcontent-%COMP%]:hover, \n.ed-todo__item[_ngcontent-%COMP%]:focus-visible {\n color: var(--mj-text-primary);\n}\n\n\n\n\n\n.ed-tender-ref[_ngcontent-%COMP%] {\n margin-block-start: var(--mj-space-3);\n max-inline-size: 22rem;\n}\n\n\n\n.ed-tender-ref__req[_ngcontent-%COMP%] {\n margin-inline-start: var(--mj-space-2);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-status-warning-text);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n}\n\n.ed-tender-ref__hint[_ngcontent-%COMP%] {\n margin-block-start: var(--mj-space-1);\n}"] });
2221
- }
2222
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJOOrderEditorPageComponent, [{
2223
- type: Component,
2224
- args: [{ selector: 'mjo-order-editor-page', standalone: true, imports: [MJButtonDirective, MJDropdownComponent, MJTabNavComponent,
2225
- EntityViewerModule,
2226
- CommonModule,
2227
- FormsModule,
2228
- MJOMoneyStripComponent,
2229
- MJOStatusStepperComponent,
2230
- MJOJournalEntryPreviewComponent,
2231
- MJODecompositionLadderComponent,
2232
- MJOConsequenceChipComponent,
2233
- MJOPriceSourceBadgeComponent,
2234
- MJOStatedValueComponent,
2235
- MJOMoneyPipe,
2236
- ], template: "<!--\n Order editor \u2014 the hard order in five tabs.\n\n Ported from mockups/orders/editor.html and using the same class names, which\n resolve through orders-kit.css.\n-->\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550 Persistent chrome: identity, stage, money \u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n<!-- Everything that scrolls. The host is a flex frame so the footer can be a\n real bottom row rather than a sticky element that only holds when the\n content happens to overflow \u2014 see order-editor.page.css. -->\n<div class=\"ed-scroll\">\n<div class=\"ed-sticky\">\n <div class=\"ed-identity\">\n <div>\n <span class=\"l\">Order</span>\n <span class=\"v mono\">{{ OrderNumber ?? 'New draft' }}</span>\n </div>\n <div>\n <span class=\"l\">Type</span>\n @if (IsEditable) {\n <mj-dropdown\n class=\"ed-identity__input\"\n [class.ed-identity__input--default]=\"IsDefault('OrderType')\"\n [title]=\"IsDefault('OrderType') ? 'Default \u2014 not chosen yet' : ''\"\n aria-label=\"Order type\"\n [Data]=\"OrderTypes\"\n [ValuePrimitive]=\"true\"\n [ngModel]=\"Order.OrderType\"\n (ngModelChange)=\"SetOrderType($event)\" />\n } @else {\n <span class=\"v\">{{ Order.OrderType }}</span>\n }\n </div>\n <div class=\"ed-identity__cell--wide\">\n <!-- WHICH COMPANY IS SELLING. High on the strip \u2014 straight after the order and its type \u2014\n because it decides the chart of accounts the order books into, and it used to be taken\n silently from the first product in the catalogue. Rendered as plain text when there is\n only one company, because a picker with one option is a decision that isn't.\n\n It spans two columns: a 150px cell truncates \"DEMO Publishing Co\" to \"DEMO Pu\u2026\", and a\n company picker that cannot show which company is picked has no reason to exist. -->\n <span class=\"l\">Selling as</span>\n @if (HasCompanyChoice) {\n <mj-dropdown\n class=\"ed-identity__input\"\n [title]=\"OwningCompanyName\"\n aria-label=\"Selling company\"\n [Data]=\"Companies\"\n TextField=\"Name\"\n ValueField=\"ID\"\n [ValuePrimitive]=\"true\"\n [ngModel]=\"Order.CompanyID\"\n (ngModelChange)=\"SetOwningCompany($event)\" />\n } @else {\n <span class=\"v\">{{ OwningCompanyName }}</span>\n }\n </div>\n <div>\n <span class=\"l\">Order date</span>\n @if (IsEditable) {\n <input type=\"date\" class=\"mj-input ed-identity__input\" aria-label=\"Order date\"\n [class.ed-identity__input--default]=\"IsDefault('OrderDate')\"\n [title]=\"IsDefault('OrderDate') ? 'Defaults to today \u2014 change it if the order was taken on another date' : ''\"\n [ngModel]=\"DateValue(Order.OrderDate)\"\n (ngModelChange)=\"SetHeaderField('OrderDate', $event)\" />\n } @else {\n <span class=\"v\">{{ DateValue(Order.OrderDate) }}</span>\n }\n </div>\n <div>\n <span class=\"l\">Due</span>\n @if (IsEditable) {\n <!-- Typing a due date is a STATED value and wins over the terms walk; clearing it hands\n resolution back. Same rule the unit price follows. -->\n <input type=\"date\" class=\"mj-input ed-identity__input\" aria-label=\"Due date\"\n [ngModel]=\"DateValue(Order.DueDate)\"\n (ngModelChange)=\"SetHeaderField('DueDate', $event)\" />\n } @else {\n <span class=\"v\">{{ Order.DueDate ?? '\u2014' }}</span>\n }\n </div>\n <div>\n <span class=\"l\">Their PO</span>\n @if (IsEditable) {\n <input type=\"text\" class=\"mj-input ed-identity__input mono\" aria-label=\"Their PO number\"\n placeholder=\"\u2014\"\n [ngModel]=\"Order.ExternalDocumentNumber ?? ''\"\n (ngModelChange)=\"SetHeaderField('ExternalDocumentNumber', $event)\" />\n } @else {\n <span class=\"v mono\">{{ Order.ExternalDocumentNumber ?? '\u2014' }}</span>\n }\n </div>\n </div>\n\n <div class=\"row wrap ed-stage-row\">\n <mjo-status-stepper\n [Current]=\"Status\"\n [Stages]=\"Stages\"\n [ReadOnly]=\"!IsEditable\"\n (BeforeStageChange)=\"OnBeforeStageChange($event)\" />\n </div>\n\n <!--\n PERSISTED MONEY WINS. Every value here was previously a LITERAL \u2014 `[Paid]=\"0\"` and a\n PaymentStatus of the string 'Unpaid' for any non-draft order \u2014 so a confirmed, fully-paid\n order reported \"PAID \u2014 \u00B7 BALANCE $560.00 \u00B7 Unpaid\" permanently, and nothing the user did\n could change it. See `DisplayTotal` / `DisplayPaid` / `DisplayBalance` for the reads.\n -->\n <mjo-money-strip\n class=\"ed-money\"\n [Total]=\"DisplayTotal\"\n [Paid]=\"DisplayPaid\"\n [Balance]=\"DisplayBalance\"\n [ShowPaid]=\"IsPersisted\"\n [PaymentStatus]=\"DisplayPaymentStatus\" />\n\n <!-- Issues above the tabs: a red dot alone leaves the user hunting. -->\n @if (Issues.length) {\n <!-- One line, and every item is a BUTTON that takes you to the tab that owns it. The old\n version was a full alert card restating what the tab dots already say, so it cost a\n card's worth of vertical space to tell you something twice and left you to find the\n tab yourself. -->\n <div class=\"ed-todo\" role=\"status\">\n <i class=\"fa-solid fa-circle-exclamation ed-todo__icon\" aria-hidden=\"true\"></i>\n <span class=\"ed-todo__count\">{{ Issues.length }}</span>\n <span class=\"ed-todo__lead\">before you can confirm</span>\n <span class=\"ed-todo__items\">\n @for (issue of Issues; track issue.Code) {\n <button\n type=\"button\"\n class=\"ed-todo__item\"\n [title]=\"'Go to ' + SectionLabel(issue.Section)\"\n (click)=\"GoToIssue(issue.Section)\">\n {{ issue.Message }}\n </button>\n }\n </span>\n </div>\n }\n\n <mj-tab-nav\n class=\"ed-tabs\"\n [Tabs]=\"TabNav\"\n [ActiveKey]=\"ActiveTab\"\n (TabChange)=\"SelectTabKey($event)\" />\n</div>\n<!-- Only the tab content scrolls. The identity strip, stage, totals and tab\n strip above stay put \u2014 scrolling the whole card meant the order you are\n editing could scroll off the top of its own editor. -->\n<div class=\"ed-panes\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550 LINES \u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (ActiveTab === 'lines') {\n <div class=\"ed-pane\">\n @if (IsEditable) {\n <!-- The editor could remove a line and never add one; this is the way in. -->\n <div class=\"ed-addline\">\n <label class=\"ed-addline__field\">\n <i class=\"fa-solid fa-magnifying-glass\" aria-hidden=\"true\"></i>\n <input\n type=\"text\"\n class=\"mj-input\"\n placeholder=\"Add a product \u2014 name or SKU\"\n aria-label=\"Add a product to this order\"\n (focus)=\"OnProductFocus()\"\n [(ngModel)]=\"ProductQuery\"\n (ngModelChange)=\"OnProductQueryChange()\" />\n </label>\n @if (ProductMatches.length) {\n <ul class=\"ed-addline__matches\" role=\"listbox\" aria-label=\"Matching products\">\n @for (option of ProductMatches; track option.ID) {\n <li>\n <!--\n MOUSEDOWN, NOT CLICK. A click is only delivered if the element survives from\n mousedown to mouseup, and these lists re-render on a debounced search landing \u2014\n so a result arriving mid-click unmounts the row under the cursor and the\n selection is silently lost. It presents as \"I clicked it and nothing happened\",\n intermittently, which reads as lag rather than as a bug. Fast entry's picker has\n always bound mousedown; this one had not.\n -->\n <button type=\"button\" class=\"ed-addline__match\" (mousedown)=\"AddProduct(option)\">\n <span class=\"nm\">{{ option.Name }}</span>\n <!-- The separator belongs to the SKU, not to the row: products can have a NULL\n SKU, and an unconditional \"\u00B7\" renders a dangling bullet before the company. -->\n <span class=\"small muted\">\n @if (option.SKU) { {{ option.SKU }} \u00B7 } {{ option.CompanyName }}\n </span>\n <span class=\"num\">{{ option.ListPrice | mjoMoney }}</span>\n </button>\n </li>\n }\n </ul>\n } @else if (ProductQuery.trim().length >= 2) {\n <div class=\"small muted ed-addline__none\">\n No catalogue match for &ldquo;{{ ProductQuery }}&rdquo;.\n @if (CatalogTruncated) {\n <!-- \"Not found\" and \"not in the loaded subset\" are different answers. -->\n <b>The catalogue list was capped, so this may exist beyond it.</b>\n }\n </div>\n }\n </div>\n }\n\n <div class=\"mj-table-wrap\">\n <table class=\"mj-table mj-table--lines\">\n <thead>\n <tr>\n <th class=\"ed-col-n\">#</th>\n <th>Product</th>\n <th class=\"ed-col-co\">Co.</th>\n <th class=\"num ed-col-qty\">Qty</th>\n <th class=\"num ed-col-price\">Unit price</th>\n <th class=\"num ed-col-disc\">Discount</th>\n <th class=\"num ed-col-net\">Line net</th>\n <!-- Marked pending, not removed: the columns keep the table's shape and say\n plainly that the figure is decided later, rather than implying zero. -->\n <th class=\"num ed-col-tax muted\" title=\"Decided when the order is confirmed\">Tax</th>\n <th class=\"num ed-col-total muted\" title=\"Decided when the order is confirmed\">Line total</th>\n <th class=\"ed-col-act\"></th>\n </tr>\n </thead>\n <tbody>\n @for (line of Lines; track line.ID; let i = $index) {\n <tr class=\"is-clickable\" (click)=\"Open(line)\">\n <td class=\"muted\">{{ i + 1 }}</td>\n\n <td>\n <div class=\"ed-line-nm\">\n <span class=\"primary\">{{ ProductFor(line)?.Name ?? 'Product' }}</span>\n <span class=\"secondary\">{{ ProductFor(line)?.SKU }}</span>\n </div>\n <!--\n Consequence chips read the CATALOGUE, not a priced line. They used to\n come off the rolled-back preview's projection, which meant a line could\n not say \"ships\" until a whole throwaway booking had run.\n -->\n <div class=\"ed-line-conseq\">\n @if (ProductFor(line); as product) {\n @if (product.TypeName === 'Goods') {\n <mjo-consequence-chip Kind=\"fulfillment\">Ships</mjo-consequence-chip>\n }\n @if (!product.Taxable) {\n <mjo-consequence-chip Kind=\"untaxable\">Untaxable</mjo-consequence-chip>\n }\n }\n </div>\n </td>\n\n <td>\n <span class=\"mj-chip mj-chip--outline\">{{ ProductFor(line)?.CompanyName ?? '\u2014' }}</span>\n </td>\n\n <td class=\"num\" (click)=\"$event.stopPropagation()\">\n <input\n class=\"mj-input is-num ed-input-qty\"\n [value]=\"line.Quantity\"\n [disabled]=\"!IsEditable\"\n (change)=\"SetQuantity(line, $any($event.target).value)\"\n aria-label=\"Quantity\">\n </td>\n\n <td class=\"num\" (click)=\"$event.stopPropagation()\">\n <input\n class=\"mj-input is-num ed-input-price\"\n [value]=\"PriceStated(line) ? line.UnitPrice : (PricedLine(line)?.UnitPrice ?? '')\"\n [disabled]=\"!IsEditable\"\n placeholder=\"resolve\"\n (change)=\"SetUnitPrice(line, $any($event.target).value)\"\n aria-label=\"Unit price\">\n <mjo-price-source-badge\n [Source]=\"PricedLine(line)?.PriceSource ?? null\"\n [Settled]=\"PricingSettled\"\n [Overridden]=\"PriceStated(line)\" />\n @if (PricedLine(line)?.Error; as why) {\n <!--\n A LINE WITH NO PRICE SAYS SO. Rendering nothing (or a $0.00) makes an\n unpriced line and a deliberately free one identical on screen, and only\n one of those is what anybody meant.\n -->\n <div class=\"secondary mj-money--credit\">{{ why }}</div>\n }\n </td>\n\n <td class=\"num\">\n @if (DiscountAmount(line); as discount) {\n <span class=\"mj-money--credit\">\u2212{{ discount | mjoMoney: { Sign: 'absolute' } }}</span>\n } @else {\n <span class=\"muted\">\u2014</span>\n }\n </td>\n\n <td class=\"num strong\">{{ PricedLine(line)?.NetAmount | mjoMoney }}</td>\n\n <!--\n BLANK, NOT ZERO. Tax and the tax-inclusive line total are decided inside the\n confirm transaction and are not knowable from the browser. A $0.00 here would\n read as \"this order is untaxed\" on the screen people trust for exactly that,\n so the cell says \"\u2014\" and the header says when the number arrives.\n -->\n <td class=\"num muted\" title=\"Decided when the order is confirmed\">\u2014</td>\n <td class=\"num muted\" title=\"Decided when the order is confirmed\">\u2014</td>\n\n <td (click)=\"$event.stopPropagation()\">\n @if (IsEditable) {\n <button type=\"button\" class=\"mj-iconbtn\" (click)=\"Remove(line)\" aria-label=\"Remove line\">\n <i class=\"fa-regular fa-trash-can\" aria-hidden=\"true\"></i>\n </button>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"10\">\n <div class=\"mj-empty ed-empty\">\n <i class=\"fa-solid fa-cart-plus\" aria-hidden=\"true\"></i>\n <div class=\"t\">No lines yet</div>\n <div class=\"small\">Search the catalogue above to add the first one.</div>\n </div>\n </td>\n </tr>\n }\n </tbody>\n\n @if (Totals) {\n <tfoot>\n <tr class=\"is-total\">\n <td colspan=\"6\">\n Net before tax &amp; charges\n @if (HasUnpricedLines) {\n <span class=\"secondary mj-money--credit\">\u2014 some lines have no price, so this is short</span>\n }\n </td>\n <td class=\"num\">{{ Totals.NetTotal | mjoMoney }}</td>\n <td class=\"num muted\">\u2014</td>\n <td class=\"num muted\">\u2014</td>\n <td></td>\n </tr>\n </tfoot>\n }\n </table>\n </div>\n\n <div class=\"grid-2 ed-below\">\n <div class=\"mj-card\">\n <div class=\"mj-card-head\">\n <i class=\"fa-solid fa-percent\" aria-hidden=\"true\"></i>\n <h3>Promotions</h3>\n </div>\n <!--\n Codes are LISTED, not adjudicated. Whether one qualifies is decided by the\n promotion engine inside the confirm transaction; the old outcome here came\n from a rolled-back booking run on every keystroke. Showing \"applied\" for a\n code the confirm might refuse is a promise the screen cannot keep.\n -->\n <div class=\"mj-card-pad\">\n @for (code of PromotionCodes; track code) {\n <div class=\"ed-promo muted\">\n <i class=\"fa-solid fa-circle-minus\" style=\"color: var(--mj-text-disabled)\" aria-hidden=\"true\"></i>\n <div class=\"ed-promo__body\">\n <div><b class=\"mono\">{{ code }}</b></div>\n <div class=\"small\">Checked when the order is confirmed.</div>\n </div>\n <span class=\"mj-num\">\u2014</span>\n </div>\n } @empty {\n <div class=\"small muted\">No promotion codes on this order.</div>\n }\n </div>\n </div>\n\n <div class=\"mj-card\">\n <div class=\"mj-card-head\">\n <i class=\"fa-solid fa-calculator\" aria-hidden=\"true\"></i>\n <h3>Totals</h3>\n </div>\n <div class=\"mj-card-pad\">\n <mjo-decomposition-ladder [Rows]=\"LadderRows\" [Stale]=\"Pricing.Loading\" />\n </div>\n </div>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550 PARTIES \u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (ActiveTab === 'parties') {\n <div class=\"ed-pane\">\n <div class=\"grid-2\">\n <div class=\"mj-card\">\n <div class=\"mj-card-head\">\n <i class=\"fa-solid fa-file-invoice-dollar\" aria-hidden=\"true\"></i>\n <h3>Bill to \u2014 who pays</h3>\n <span class=\"right\"><span class=\"mj-chip mj-chip--outline\">header only</span></span>\n </div>\n <div class=\"mj-card-pad\">\n <div class=\"ed-party\">\n <div class=\"ed-party__label\">Customer</div>\n @if (PartyIdFor('bill'); as chosen) {\n <div class=\"ed-party__chosen\">\n <span class=\"mj-chip\">{{ PartyLabels.bill ?? chosen }}</span>\n @if (IsEditable) {\n <button type=\"button\" class=\"mj-iconbtn\" (click)=\"ClearParty('bill')\" aria-label=\"Clear customer\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n } @else if (IsEditable) {\n <label class=\"ed-party__field\">\n <i class=\"fa-solid fa-magnifying-glass\" aria-hidden=\"true\"></i>\n <input\n type=\"text\"\n class=\"mj-input\"\n placeholder=\"Search people and organizations\"\n aria-label=\"Customer\"\n [(ngModel)]=\"PartyQuery.bill\"\n (focus)=\"OnPartyFocus('bill')\"\n (ngModelChange)=\"SearchParty('bill')\" />\n </label>\n @if (PartySearching === 'bill') {\n <div class=\"small muted\">Searching\u2026</div>\n } @else if (PartyMatches.bill.length) {\n <ul class=\"ed-party__matches\" role=\"listbox\" aria-label=\"Matching customers\">\n @for (m of PartyMatches.bill; track m.ID) {\n <li>\n <button type=\"button\" class=\"ed-party__match\" (mousedown)=\"ChooseParty('bill', m)\">\n <i [class]=\"m.IsOrganization ? 'fa-solid fa-building' : 'fa-solid fa-user'\" aria-hidden=\"true\"></i>\n <span class=\"nm\">{{ m.Name }}</span>\n @if (m.Email) { <span class=\"small muted\">{{ m.Email }}</span> }\n </button>\n </li>\n }\n </ul>\n }\n } @else {\n <div class=\"small muted\">\u2014 none \u2014</div>\n }\n </div>\n <mjo-stated-value Label=\"Terms\" From=\"organization default\">\n {{ Order.PaymentTermsTypeID ?? '\u2014 default \u2014' }}\n </mjo-stated-value>\n <div class=\"small muted ed-note\">\n Bill-to is header-only: one order, one payer, one bill. That is why there is no\n line-level counterpart to it.\n </div>\n </div>\n </div>\n\n <div class=\"mj-card\">\n <div class=\"mj-card-head\">\n <i class=\"fa-solid fa-truck-fast\" aria-hidden=\"true\"></i>\n <h3>Ship to \u2014 who receives</h3>\n <span class=\"right\"><span class=\"mj-chip mj-chip--outline\">line default</span></span>\n </div>\n <div class=\"mj-card-pad\">\n <div class=\"ed-party\">\n <div class=\"ed-party__label\">Recipient</div>\n @if (PartyIdFor('ship'); as chosen) {\n <div class=\"ed-party__chosen\">\n <span class=\"mj-chip\">{{ PartyLabels.ship ?? chosen }}</span>\n @if (IsEditable) {\n <button type=\"button\" class=\"mj-iconbtn\" (click)=\"ClearParty('ship')\" aria-label=\"Clear recipient\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n } @else if (IsEditable) {\n <label class=\"ed-party__field\">\n <i class=\"fa-solid fa-magnifying-glass\" aria-hidden=\"true\"></i>\n <input\n type=\"text\"\n class=\"mj-input\"\n placeholder=\"Leave empty to use the customer\"\n aria-label=\"Recipient\"\n [(ngModel)]=\"PartyQuery.ship\"\n (focus)=\"OnPartyFocus('ship')\"\n (ngModelChange)=\"SearchParty('ship')\" />\n </label>\n @if (PartySearching === 'ship') {\n <div class=\"small muted\">Searching\u2026</div>\n } @else if (PartyMatches.ship.length) {\n <ul class=\"ed-party__matches\" role=\"listbox\" aria-label=\"Matching customers\">\n @for (m of PartyMatches.ship; track m.ID) {\n <li>\n <button type=\"button\" class=\"ed-party__match\" (mousedown)=\"ChooseParty('ship', m)\">\n <i [class]=\"m.IsOrganization ? 'fa-solid fa-building' : 'fa-solid fa-user'\" aria-hidden=\"true\"></i>\n <span class=\"nm\">{{ m.Name }}</span>\n @if (m.Email) { <span class=\"small muted\">{{ m.Email }}</span> }\n </button>\n </li>\n }\n </ul>\n }\n } @else {\n <div class=\"small muted\">\u2014 none \u2014</div>\n }\n </div>\n <mjo-stated-value Label=\"Address\">\n {{ Order.ShipToAddressID ?? '\u2014 none \u2014' }}\n </mjo-stated-value>\n <div class=\"small muted ed-note\">\n Each side falls back <b>independently</b>, so a line naming only a person keeps the\n header's organization. For an intangible there is nothing to ship, and the same fields\n say who the line is <i>for</i>.\n </div>\n </div>\n </div>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550 CHARGES & TAX \u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (ActiveTab === 'charges') {\n <div class=\"ed-pane\">\n <!--\n THIS TAB IS EMPTY BEFORE THE CONFIRM, AND SAYS WHY.\n\n It used to render the engine's charge rows, the taxable-base build-up and the\n per-line \"why did this tax\" panel. All of it came from `Orders.PreviewOrder`,\n which produced those figures by running the REAL save inside a transaction that\n always rolled back \u2014 so every keystroke booked and unbooked the order to fill in\n this screen.\n\n Charges, tax and promotions are decided inside `OrderEntityServer.Save()` and\n have no read-only entry point yet. Line PRICING does (`Orders.PreviewPrice`\n calls the same `ResolvePrice` the engine calls), which is why the Lines tab\n still shows real prices and this one does not.\n\n Showing zeroes here would be worse than showing nothing: a $0.00 tax row on the\n order screen reads as \"this order is untaxed\", which is a statement, not a gap.\n When the decide phase is extracted the same way pricing was, this tab comes back\n reading from that \u2014 never from a save.\n -->\n <div class=\"mj-empty ed-empty muted\">\n <i class=\"fa-solid fa-receipt\" aria-hidden=\"true\"></i>\n <div class=\"t\">Not available yet</div>\n <div class=\"small\">\n Charges and tax are decided when the order is confirmed. The Lines tab shows the\n net subtotal before them.\n </div>\n </div>\n\n @if (JournalEntries.length) {\n <div class=\"small muted ed-note\">\n This order is confirmed \u2014 its charges and tax are on the entries under\n <b>Accounting</b>.\n </div>\n }\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550 PAYMENT \u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (ActiveTab === 'payment') {\n <div class=\"ed-pane\">\n <div class=\"mj-card\">\n <div class=\"mj-card-head\">\n <i class=\"fa-solid fa-credit-card\" aria-hidden=\"true\"></i>\n <h3>Initial payment \u2014 intent</h3>\n <span class=\"right\"><span class=\"mj-chip mj-chip--info\">not yet a payment</span></span>\n </div>\n <div class=\"mj-card-pad\">\n @if (IsEditable) {\n <div class=\"ed-field\">\n <label class=\"ed-field__label\" for=\"ed-tender\">Tender</label>\n <!-- The DefaultItem is a real choice, not a prompt: it means invoice on terms. -->\n <mj-dropdown\n id=\"ed-tender\"\n [Data]=\"Tenders\"\n TextField=\"Name\"\n ValueField=\"ID\"\n [ValuePrimitive]=\"true\"\n [DefaultItem]=\"TenderNone\"\n [ngModel]=\"Order.InitialPaymentTypeID ?? ''\"\n (ngModelChange)=\"SetTender($event)\" />\n\n <!--\n THE REFERENCE, ONLY WHEN THE TENDER DEMANDS ONE. Check, Wire and Internal Transfer\n carry RequiresReference: a captured payment with no check number cannot be reconciled\n against a bank statement, so the money is recorded and unfindable. The dropdown named\n the requirement; nothing let anyone satisfy it.\n -->\n @if (RequiresReference) {\n <div class=\"ed-tender-ref\">\n <label class=\"ed-field__label\" for=\"ed-tender-ref\">\n {{ SelectedTenderType?.Name }} number\n <span class=\"ed-tender-ref__req\" aria-hidden=\"true\">required</span>\n </label>\n <input\n id=\"ed-tender-ref\"\n class=\"mj-input\"\n [value]=\"Reference\"\n (input)=\"SetReference($any($event.target).value)\"\n [attr.aria-invalid]=\"!Reference.trim()\"\n [placeholder]=\"SelectedTenderType?.Code === 'Check' ? 'e.g. 10428' : 'confirmation or transfer id'\"\n autocomplete=\"off\" />\n <div class=\"ed-tender-ref__hint small muted\">\n Recorded on the payment so it can be matched to the bank statement.\n </div>\n </div>\n }\n </div>\n\n @if (Order.InitialPaymentTypeID) {\n <div class=\"ed-field\">\n <label class=\"ed-field__label\" for=\"ed-payamt\">Amount</label>\n <div class=\"ed-field__row\">\n <input id=\"ed-payamt\" type=\"text\" inputmode=\"decimal\" class=\"mj-input is-num\"\n [ngModel]=\"Order.InitialPaymentAmount\"\n (ngModelChange)=\"SetInitialAmount($event)\" />\n <button type=\"button\" mjButton variant=\"outline\" (click)=\"PayInFull()\"\n title=\"Use the order total\">\n Pay in full\n </button>\n </div>\n </div>\n }\n } @else {\n <!--\n The tender's NAME, not its id. This read-only branch printed\n `InitialPaymentTypeID` directly, so every confirmed order showed the user a raw\n GUID \u2014 \"2F1A6D30-0C41-4E7B-9E51-0A1B7C2D3E04\" \u2014 where the editable branch two\n lines up shows \"Check\". `SelectedTenderType` already resolves it against the\n same `Tenders` list the dropdown is bound to.\n -->\n <mjo-stated-value Label=\"Tender\">\n {{ SelectedTenderType?.Name ?? '\u2014 invoice on terms \u2014' }}\n </mjo-stated-value>\n <mjo-stated-value Label=\"Amount\">\n {{ Order.InitialPaymentAmount | mjoMoney: { Zero: '\u2014' } }}\n </mjo-stated-value>\n }\n\n <div class=\"small muted ed-note\">\n What is recorded here is <b>intent</b>. On confirm it becomes a real PaymentHeader and\n PaymentLine in the same transaction as the booking; from then on the payment record is the\n truth and these fields are never updated again. A wallet entry is <b>copied</b>, never\n shared, so the snapshot cannot drift if the saved card is later edited.\n </div>\n </div>\n </div>\n\n <div class=\"mj-card ed-block\">\n <div class=\"mj-card-head\">\n <i class=\"fa-solid fa-list-check\" aria-hidden=\"true\"></i>\n <h3>Payments applied</h3>\n <span class=\"right small muted\">{{ AppliedTotal | mjoMoney }} of {{ EstimatedTotal | mjoMoney }}</span>\n </div>\n <div class=\"mj-table-wrap\">\n <table class=\"mj-table mj-table--compact\">\n <thead>\n <tr><th>Payment</th><th>Applied</th><th class=\"num\">Amount</th></tr>\n </thead>\n <tbody>\n @for (line of AppliedPayments; track line.ID) {\n <tr>\n <td class=\"mono small\">{{ PaymentNumberOf(line) }}</td>\n <td class=\"small muted\">{{ dateOf(line.AllocatedAt) }}</td>\n <td class=\"num\">{{ moneyOf(line.Amount) }}</td>\n </tr>\n } @empty {\n <tr><td colspan=\"3\" class=\"small muted\">Nothing applied yet.</td></tr>\n }\n </tbody>\n </table>\n </div>\n <div class=\"mj-card-pad small muted\">\n These are allocation LINES, not payments. One payment can settle several orders, so what\n matters here is the amount that reached THIS order \u2014 not what the customer handed over.\n </div>\n </div>\n\n <div class=\"mj-card ed-block\">\n <div class=\"mj-card-head\">\n <i class=\"fa-solid fa-calendar-day\" aria-hidden=\"true\"></i>\n <h3>Terms</h3>\n </div>\n <div class=\"mj-card-pad\">\n <mjo-stated-value Label=\"Due\" From=\"set when the order confirms\">\n {{ dateOf(Order.DueDate) }}\n </mjo-stated-value>\n <mjo-stated-value Label=\"Balance\">{{ BalanceDue | mjoMoney }}</mjo-stated-value>\n <div class=\"small muted ed-note\">\n Terms decide the due date, and the due date is what makes an order overdue. Nothing here\n is a stored \"overdue\" flag \u2014 that is a question about today's date, so it is asked rather\n than remembered.\n </div>\n </div>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550 ACCOUNTING \u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (ActiveTab === 'accounting') {\n <div class=\"ed-pane\">\n <mjo-journal-entry-preview\n [Entries]=\"JournalEntries\"\n [Pending]=\"Status === 'Draft' || Status === 'Quoted'\"\n EmptyText=\"Nothing booked yet \u2014 confirm the order to create its entries.\"\n (OpenInAccounting)=\"OpenInAccounting.emit($event)\" />\n\n <div class=\"small muted ed-note\">\n Read-only, and never duplicated. Orders creates <b>Pending</b> entries and owns nothing in the\n ledger, so every account links out to Accounting rather than being editable here.\n </div>\n\n <div class=\"mj-card ed-block\">\n <div class=\"mj-card-head\">\n <i class=\"fa-solid fa-tags\" aria-hidden=\"true\"></i>\n <h3>Dimension tags</h3>\n <span class=\"right small muted\">{{ Dimensions.length }}</span>\n </div>\n <div class=\"mj-card-pad\">\n @for (dim of Dimensions; track dim['ID']) {\n <div class=\"ed-dim\">\n <span class=\"mj-chip mj-chip--outline\">{{ dim['Dimension'] }}</span>\n <span class=\"small\">{{ dim['DimensionValue'] }}</span>\n </div>\n } @empty {\n <div class=\"small muted\">\n No tags. Dimensions are the axes a line is filed under for analysis \u2014 department,\n campaign, region \u2014 and an untagged line still books correctly; it is simply harder to\n group later.\n </div>\n }\n </div>\n </div>\n\n <div class=\"mj-card ed-block\">\n <div class=\"mj-card-head\">\n <i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i>\n <h3>Record changes</h3>\n </div>\n <div class=\"mj-card-pad small muted\">\n Every field change on this order is recorded by the platform, not by this app \u2014 which is why\n there is no \"edit history\" table of our own to keep in step. Open the record in Explorer's\n entity viewer to read it.\n </div>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550 JOURNAL ENTRIES \u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n<!--\n THE LEDGER AS ACCOUNTING HOLDS IT, not a rendering of our own. `mj-entity-data-grid` reads the\n entity's metadata for its columns, so this stays correct when accounting adds a field \u2014 and the\n rows are the real records, reachable from here rather than re-described here.\n\n Read-only by construction: the UI role has CanRead on Journal Entries and neither CanCreate nor\n CanUpdate, which is the same rule the app has always stated in prose.\n-->\n@if (ActiveTab === 'journal') {\n <div class=\"ed-pane\">\n @if (JournalEntryParams) {\n <!-- READ-ONLY, and said so three ways: no New, no Delete, no cell editing. Orders creates\n Pending entries and owns nothing in the ledger, and the UI role could not write here\n anyway \u2014 a button that always fails is worse than no button.\n HEIGHT IS UNRESOLVED, and it is the editor's layout rather than the grid's fault. The\n sticky header (identity strip, stepper, money strip, tabs) leaves `.ed-panes` about 79px\n tall at 1280x700, so: a fixed height renders a grid taller than its container and you\n scroll into blank space, and `fit-content` collapses to nothing at all. 360 is the less\n wrong of the two \u2014 the rows exist and load correctly (verified: 4 for ORD-000122).\n The real fix is giving the pane real height, which belongs with the editor layout work,\n not here. -->\n <mj-entity-data-grid\n [Params]=\"JournalEntryParams\"\n [Height]=\"360\"\n [EditMode]=\"'none'\"\n [ShowNewButton]=\"false\"\n [ShowDeleteButton]=\"false\"\n [AllowDelete]=\"false\"\n [ShowPager]=\"true\" />\n } @else {\n <!-- Not an error: an order with no saved lines has booked nothing, and one journal entry is\n written per line. Saying so beats an empty grid, which reads as a failed query. -->\n <div class=\"small muted ed-note\">\n Nothing booked yet \u2014 an order books one journal entry per line when it is confirmed.\n </div>\n }\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550 SUBSCRIPTIONS \u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n<!--\n What the order STARTED. A subscription is keyed to the order line that brought it into existence\n (D39/D40) and then outlives the order, so this is a window onto a longer-lived record rather than\n part of the order document.\n-->\n@if (ActiveTab === 'subscriptions') {\n <div class=\"ed-pane\">\n @if (SubscriptionParams) {\n <mj-entity-data-grid\n [Params]=\"SubscriptionParams\"\n [Height]=\"360\"\n [EditMode]=\"'none'\"\n [ShowNewButton]=\"false\"\n [ShowDeleteButton]=\"false\"\n [AllowDelete]=\"false\"\n [ShowPager]=\"true\" />\n } @else {\n <div class=\"small muted ed-note\">\n No subscriptions \u2014 they are created on confirm, from lines whose product carries a\n subscription type.\n </div>\n }\n </div>\n}\n</div>\n</div>\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550 LINE DRAWER \u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (OpenLine) {\n <aside class=\"mj-slide-in is-open ed-drawer\" role=\"dialog\" aria-label=\"Line detail\">\n <div class=\"mj-slide-in-head\">\n <div>\n <h2>{{ ProductFor(OpenLine)?.Name ?? 'Line' }}</h2>\n <div class=\"small muted\">\n {{ ProductFor(OpenLine)?.SKU }} \u00B7 revenue to {{ ProductFor(OpenLine)?.CompanyName }}\n </div>\n </div>\n <span class=\"right\">\n <button type=\"button\" class=\"mj-iconbtn\" (click)=\"CloseDrawer()\" aria-label=\"Close\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </span>\n </div>\n\n <div class=\"mj-slide-in-body\">\n <div class=\"sec-label\">Who this line is for</div>\n <mjo-stated-value Label=\"Ship-to address\" From=\"falls back to the header\">\n {{ OpenLine.ShipToAddressID ?? '\u2014 header default \u2014' }}\n </mjo-stated-value>\n <mjo-stated-value Label=\"Ship-to person\" From=\"falls back independently\">\n {{ OpenLine.ShipToPersonID ?? '\u2014 header default \u2014' }}\n </mjo-stated-value>\n <mjo-stated-value Label=\"Ship-to organization\" From=\"falls back independently\">\n {{ OpenLine.ShipToOrganizationID ?? '\u2014 header default \u2014' }}\n </mjo-stated-value>\n\n <!--\n Reads the DRAFT's own dates. The engine may narrow a service period at confirm\n (an event's dates win over a stated one), and that decision happens inside the\n booking transaction \u2014 so what is shown here is what was ASKED for, not what was\n settled. The confirmed order states the settled window.\n -->\n <div class=\"sec-label ed-drawer__section\">Timing</div>\n <mjo-stated-value Label=\"Service period\" From=\"as entered\">\n {{ OpenLine.ServicePeriodStart ?? '\u2014' }} \u2013 {{ OpenLine.ServicePeriodEnd ?? '\u2014' }}\n </mjo-stated-value>\n\n <div class=\"sec-label ed-drawer__section\">Reversal</div>\n <mjo-stated-value Label=\"Reverses\">\n {{ OpenLine.ReversesOrderLineID ?? '\u2014 nothing \u2014' }}\n </mjo-stated-value>\n <div class=\"small muted\">\n A line that reverses another inherits its price and is capped at the quantity still\n returnable there.\n </div>\n\n <div class=\"sec-label ed-drawer__section\">Subscription</div>\n <mjo-stated-value Label=\"Renews\">\n {{ OpenLine.RenewsSubscriptionID ?? '\u2014 none \u2014' }}\n </mjo-stated-value>\n <div class=\"small muted\">\n Naming a renewal target <i>is</i> the statement of who the subscriber is, so the target's\n holder wins over the line's ship-to.\n </div>\n </div>\n\n <div class=\"mj-slide-in-foot\">\n <button type=\"button\" mjButton variant=\"primary\" size=\"sm\" (click)=\"CloseDrawer()\">Done</button>\n <span class=\"small muted spacer\">Every field here defaults from something. Nothing is required.</span>\n </div>\n </aside>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550 FOOTER \u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n<!-- Suppressed inside the order workspace: the card supplies Confirm / Keep as draft / Discard,\n and two action bars stacked on one screen is worse than either alone \u2014 the user has to work\n out whether they do the same thing. Standalone hosts keep this bar. -->\n@if (ShowActions) {\n<div class=\"ed-footer\">\n @if (IsEditable) {\n <button type=\"button\" mjButton variant=\"outline\" (click)=\"SaveDraft()\">\n <i class=\"fa-regular fa-floppy-disk\" aria-hidden=\"true\"></i> Save draft\n </button>\n <button type=\"button\" mjButton variant=\"primary\" [disabled]=\"!CanConfirm\" (click)=\"RequestConfirm()\">\n <i class=\"fa-solid fa-check\" aria-hidden=\"true\"></i> Confirm order\n </button>\n } @else {\n <!-- Edit gating shows the state's REAL verbs rather than a greyed-out Save. -->\n <button type=\"button\" mjButton variant=\"outline\">\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i> Create reversal\u2026\n </button>\n <button type=\"button\" mjButton variant=\"outline\">\n <i class=\"fa-solid fa-hand-holding-dollar\" aria-hidden=\"true\"></i> Take payment\n </button>\n <span class=\"small muted\">\n This order has booked. Corrections are reversing orders \u2014 locked history is never edited.\n </span>\n }\n</div>\n}\n", styles: ["/*\n Order editor \u2014 layout only. Colour, type and border come from orders-kit.css.\n\n RESPONSIVE INTENT (basic):\n \u22651000px identity strip in one row, two-column panels below the table\n <1000px panels stack; the identity strip wraps to two rows\n <760px the lines table drops its lowest-value columns rather than\n horizontally scrolling a nine-column grid on a phone\n*/\n\n/* FLEX FRAME. Same correction as fast entry, and for the same reason: a sticky\n footer is not pinned to the bottom, it is only prevented from scrolling out of\n view. This page read correctly at 900px tall purely because its content (856px)\n happened to exceed the 769px pane \u2014 on a taller screen the content fits, sticky\n has nothing to hold against, and the action bar floats up to sit under the last\n card. The host is the frame; .ed-scroll is the scroll region and carries the\n padding; the footer is always the bottom row. */\n:host {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n padding: 0;\n}\n\n/* THE FRAME NO LONGER SCROLLS \u2014 only .ed-panes does. Scrolling the whole interior pushed the\n identity strip, stage and totals off the top of the editor, so the order being edited lost its\n own header the moment the line table grew. */\n.ed-scroll {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n padding: var(--mj-space-6);\n}\n\n/* The only scroll region inside the card. `min-height: 0` is load-bearing: without it a flex item\n refuses to shrink below its content height, so the frame grows instead of this scrolling. */\n.ed-panes {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n}\n\n/* \u2500\u2500 Persistent chrome \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* Pinned by the flex frame now, not by `position: sticky` \u2014 it is a sibling of the scroll region\n rather than a passenger inside it.\n\n The background is the CARD's surface, not `--mj-bg-page`. This block was written when the editor\n was a full page sitting on the page background; inside the workspace card that token painted the\n top half of the card a different colour from the bottom half, so the card looked like two\n stacked panels. */\n.ed-sticky {\n flex: 0 0 auto;\n background: var(--mj-bg-surface);\n margin: calc(-1 * var(--mj-space-6)) calc(-1 * var(--mj-space-6)) 0;\n padding: var(--mj-space-6) var(--mj-space-6) 0;\n}\n\n.ed-identity {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface);\n overflow: hidden;\n margin-bottom: var(--mj-space-3);\n}\n\n.ed-identity > div {\n padding: var(--mj-space-3) var(--mj-space-4);\n border-right: 1px solid var(--mj-border-subtle);\n}\n\n.ed-identity > div:last-child {\n border-right: none;\n}\n\n/* A cell whose VALUE is a name rather than a code. Company names do not abbreviate \u2014 \"DEMO Pu\u2026\"\n identifies nothing \u2014 so this one takes two of the 150px tracks. It degrades safely: when the\n strip is already down to one or two columns the span is clamped to the columns that exist. */\n.ed-identity > div.ed-identity__cell--wide {\n grid-column: span 2;\n}\n\n.ed-identity .l {\n font-size: 10px;\n font-weight: var(--mj-font-bold);\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--mj-text-muted);\n display: block;\n margin-bottom: 3px;\n}\n\n.ed-identity .v {\n font-size: 13px;\n font-weight: var(--mj-font-medium);\n}\n\n.ed-stage-row {\n gap: var(--mj-space-4);\n}\n\n.ed-money {\n display: block;\n margin-top: var(--mj-space-3);\n}\n\n.ed-issues {\n margin-top: var(--mj-space-3);\n}\n\n.ed-issues__list {\n margin: var(--mj-space-2) 0 0;\n padding-left: var(--mj-space-4);\n}\n\n.ed-tabs {\n margin-top: var(--mj-space-4);\n}\n\n/* \u2500\u2500 Panes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.ed-pane {\n padding-top: var(--mj-space-4);\n}\n\n.ed-below {\n margin-top: var(--mj-space-4);\n}\n\n.ed-note {\n margin-top: var(--mj-space-3);\n}\n\n.ed-pad {\n padding: var(--mj-space-4);\n}\n\n.ed-empty {\n padding: var(--mj-space-8);\n}\n\n/* \u2500\u2500 Lines table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.ed-col-n { width: 30px; }\n.ed-col-co { width: 84px; }\n.ed-col-qty { width: 80px; }\n.ed-col-price { width: 150px; }\n.ed-col-disc { width: 110px; }\n.ed-col-net { width: 120px; }\n.ed-col-tax { width: 110px; }\n.ed-col-total { width: 120px; }\n.ed-col-act { width: 36px; }\n.ed-col-seq { width: 60px; }\n\n.ed-line-nm {\n display: flex;\n align-items: baseline;\n gap: var(--mj-space-2);\n}\n\n.ed-line-conseq {\n display: flex;\n gap: 5px;\n flex-wrap: wrap;\n margin-top: 4px;\n}\n\n.ed-input-qty { width: 64px; }\n.ed-input-price { width: 100px; }\n\n/* \u2500\u2500 Charges \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.ed-base {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 4px var(--mj-space-4);\n font-size: 12.5px;\n padding: var(--mj-space-3) var(--mj-space-4);\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n}\n\n.ed-base .amt {\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n\n.ed-base .tot {\n border-top: 1px solid var(--mj-border-strong);\n padding-top: 5px;\n margin-top: 3px;\n font-weight: var(--mj-font-semibold);\n}\n\n.ed-taxwhy {\n padding: var(--mj-space-2) 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.ed-taxwhy:last-child {\n border-bottom: none;\n}\n\n/* \u2500\u2500 Promotions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.ed-promo {\n display: flex;\n align-items: flex-start;\n gap: var(--mj-space-2);\n padding: var(--mj-space-2) 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.ed-promo:last-child {\n border-bottom: none;\n}\n\n.ed-promo__body {\n flex: 1;\n min-width: 0;\n}\n\n/* \u2500\u2500 Drawer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.ed-drawer__section {\n margin-top: var(--mj-space-4);\n}\n\n/* \u2500\u2500 Footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.ed-footer {\n /* A flex row on the frame, not sticky \u2014 see the :host note. It no longer\n overlays scrolling content, so it needs no z-index and no negative margins to\n bleed full width; it already spans the frame. The shadow stays, to separate\n the bar from the region that now scrolls beneath its top edge. */\n flex: none;\n box-shadow: var(--mj-shadow-md);\n margin: 0;\n padding: var(--mj-space-3) var(--mj-space-6);\n background: var(--mj-bg-surface);\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n flex-wrap: wrap;\n}\n\n/* \u2500\u2500 Responsive \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n@media (max-width: 760px) {\n /* The padding is on the scroll region now \u2014 the host is the frame and has none. */\n .ed-scroll {\n padding: var(--mj-space-4);\n }\n\n .ed-sticky {\n margin: calc(-1 * var(--mj-space-4)) calc(-1 * var(--mj-space-4)) 0;\n padding: var(--mj-space-4) var(--mj-space-4) 0;\n /* Sticky chrome eats too much of a short viewport once it wraps. */\n position: static;\n }\n\n /* Drop the columns a phone cannot use before it drops the ones it can. The\n line total and quantity survive; discount and per-line tax move to the\n drawer, which is where the detail already lives. */\n .ed-col-disc,\n .ed-col-tax,\n .ed-col-co,\n :host ::ng-deep .mj-table--lines td:nth-child(3),\n :host ::ng-deep .mj-table--lines td:nth-child(6),\n :host ::ng-deep .mj-table--lines td:nth-child(8) {\n display: none;\n }\n\n .ed-drawer {\n width: 100vw;\n }\n\n .ed-footer {\n /* No negative margins: as a flex row it already spans the frame. */\n padding: var(--mj-space-3) var(--mj-space-4);\n }\n}\n\n/* \u2500\u2500 Hooks that lived only in the .html template \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Both were referenced by order-editor.page.html and defined nowhere, so a\n card meant to sit apart from the one above it butted against it, and the\n dimension rows ran their chip and value together as one string. The\n kit-classes guard missed them because it scanned only .ts templates until\n the separate .html files were added to its sweep. */\n\n/* A standalone card below the tab pane, not part of the pane's own flow. */\n.ed-block {\n margin-top: var(--mj-space-4);\n}\n\n/* Dimension tag + its value, side by side rather than run together. */\n.ed-dim {\n display: flex;\n align-items: baseline;\n gap: var(--mj-space-2);\n padding: var(--mj-space-1) 0;\n}\n\n/* \u2500\u2500 Add a line, and choose the parties \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The editor previously had neither: lines could only be removed, and the\n parties tab printed GUIDs through a read-only control. Both are ordinary\n typeahead shapes, styled from tokens so they match fast entry's pickers. */\n\n.ed-addline {\n position: relative;\n margin-block-end: var(--mj-space-3);\n}\n\n.ed-addline__field,\n.ed-party__field {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n inline-size: 100%;\n}\n\n.ed-addline__field > i,\n.ed-party__field > i {\n color: var(--mj-text-tertiary);\n}\n\n.ed-addline__field .mj-input,\n.ed-party__field .mj-input {\n flex: 1 1 auto;\n min-inline-size: 0;\n}\n\n/* The match lists overlay rather than push the table down \u2014 a picker that\n reflows the whole pane on every keystroke is unusable at speed. */\n.ed-addline__matches,\n.ed-party__matches {\n position: absolute;\n z-index: 20;\n inset-inline: 0;\n margin: var(--mj-space-1) 0 0;\n padding: 0;\n list-style: none;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-md);\n max-block-size: 40cqh;\n overflow-y: auto;\n}\n\n.ed-addline__match,\n.ed-party__match {\n display: flex;\n align-items: baseline;\n gap: var(--mj-space-2);\n inline-size: 100%;\n padding: var(--mj-space-2) var(--mj-space-3);\n background: none;\n border: 0;\n text-align: start;\n cursor: pointer;\n}\n\n.ed-addline__match:hover,\n.ed-party__match:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.ed-addline__match .nm,\n.ed-party__match .nm {\n font-weight: var(--mj-font-medium);\n}\n\n.ed-addline__match .num {\n margin-inline-start: auto;\n font-variant-numeric: tabular-nums;\n}\n\n.ed-addline__none {\n padding: var(--mj-space-2) 0 0;\n}\n\n.ed-party {\n position: relative;\n margin-block-end: var(--mj-space-3);\n}\n\n.ed-party__label {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n margin-block-end: var(--mj-space-1);\n}\n\n.ed-party__chosen {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n}\n\n/* Editable identity fields. The strip is a compact label/value grid, so the input has to sit on\n the value line without changing the row height \u2014 a full-size control here would push the stage\n stepper and money strip down every time the order becomes editable. */\n.ed-identity__input {\n inline-size: 100%;\n min-inline-size: 0;\n padding-block: var(--mj-space-1);\n font-size: var(--mj-text-sm);\n}\n\n/* A VALUE NOBODY CHOSE, shown in the muted text colour so it reads as a suggestion rather than an\n entry. The order date is the case this exists for: it defaults to today, and the difference\n between \"today because nobody picked\" and \"today because I picked today\" has to stay visible \u2014\n otherwise the default is a decision made on the user's behalf, silently.\n\n Colour is not carrying this alone: each control also gets a `title` explaining the default, so\n the distinction survives for anyone who cannot separate the two greys. The style drops the moment\n the field is touched, because `SetHeader` clears the flag. */\n.ed-identity__input--default,\n.ed-identity__input--default input {\n color: var(--mj-text-muted);\n}\n\n/* A labelled field inside a card pane. `mjo-stated-value` covers the read-only case; this is its\n editable counterpart and deliberately matches its label typography so a tab does not visibly\n change shape when the order stops being editable. */\n.ed-field {\n margin-block-end: var(--mj-space-3);\n}\n\n.ed-field__label {\n display: block;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n margin-block-end: var(--mj-space-1);\n}\n\n.ed-field__row {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n}\n\n.ed-field__row .mj-input {\n flex: 1 1 auto;\n min-inline-size: 0;\n}\n\n/* \u2500\u2500 What is left to do, in one line \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n This replaced a full warning card. The card restated what the tab dots already say and\n cost ~90px of vertical space on the densest screen in the app to do it. The information\n is worth keeping \u2014 knowing what blocks a confirm is the point \u2014 so it stays, compressed\n to a single row where each item is a button that takes you to the tab that owns it. */\n\n.ed-todo {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin-block-start: var(--mj-space-3);\n padding: var(--mj-space-1) var(--mj-space-3);\n /* Tinted rather than filled: the row is a hint, not an error state, and a solid amber\n block at this width reads as an alarm. */\n background: color-mix(in srgb, var(--mj-color-warning-500) 8%, transparent);\n border-inline-start: 3px solid var(--mj-color-warning-500);\n border-radius: var(--mj-radius-sm);\n font-size: var(--mj-text-xs);\n}\n\n.ed-todo__icon {\n color: var(--mj-color-warning-700);\n}\n\n/* The count carries the \"how many\" so the sentence does not have to pluralise. */\n.ed-todo__count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-inline-size: 18px;\n block-size: 18px;\n padding-inline: 5px;\n border-radius: 9px;\n background: var(--mj-color-warning-700);\n color: var(--mj-text-inverse, #fff);\n font-weight: var(--mj-font-semibold);\n}\n\n.ed-todo__lead {\n color: var(--mj-text-secondary);\n}\n\n/* Items run inline and the row scrolls rather than wrapping \u2014 wrapping would let this grow\n back into the multi-line block it replaced. */\n.ed-todo__items {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n min-inline-size: 0;\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.ed-todo__item {\n flex: 0 0 auto;\n padding: 0;\n background: none;\n border: 0;\n border-block-end: 1px dotted currentColor;\n color: var(--mj-color-warning-700);\n font: inherit;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.ed-todo__item:hover,\n.ed-todo__item:focus-visible {\n color: var(--mj-text-primary);\n}\n\n/* \u2500\u2500 Tender reference \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Directly under the tender picker, so the requirement it announces has its\n answer in the same place rather than on another tab. */\n.ed-tender-ref {\n margin-block-start: var(--mj-space-3);\n max-inline-size: 22rem;\n}\n\n/* Amber, not red: nothing has gone wrong \u2014 there is something still to do. */\n.ed-tender-ref__req {\n margin-inline-start: var(--mj-space-2);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-status-warning-text);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n}\n\n.ed-tender-ref__hint {\n margin-block-start: var(--mj-space-1);\n}\n"] }]
2237
- }], null, { Order: [{
2238
- type: Input
2239
- }], Catalog: [{
2240
- type: Input
2241
- }], Companies: [{
2242
- type: Input
2243
- }], Status: [{
2244
- type: Input
2245
- }], OrderNumber: [{
2246
- type: Input
2247
- }], ShowActions: [{
2248
- type: Input
2249
- }], Tenders: [{
2250
- type: Input
2251
- }], JournalEntries: [{
2252
- type: Input
2253
- }], ConfirmRequested: [{
2254
- type: Output
2255
- }], Saved: [{
2256
- type: Output
2257
- }], LineOpened: [{
2258
- type: Output
2259
- }], OpenInAccounting: [{
2260
- type: Output
2261
- }], OnDocumentPointerDown: [{
2262
- type: HostListener,
2263
- args: ['document:pointerdown', ['$event']]
2264
- }], OnEscape: [{
2265
- type: HostListener,
2266
- args: ['document:keydown.escape']
2267
- }] }); })();
2268
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJOOrderEditorPageComponent, { className: "MJOOrderEditorPageComponent", filePath: "lib/pages/orders/order-editor.page.ts", lineNumber: 130 }); })();
2269
- //# sourceMappingURL=order-editor.page.js.map