@mj-biz-apps/orders-entities 0.0.1 → 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 (115) hide show
  1. package/LICENSE +183 -0
  2. package/README.md +50 -2
  3. package/dist/CustomerPaymentMethodEntity.d.ts +4 -0
  4. package/dist/CustomerPaymentMethodEntity.d.ts.map +1 -0
  5. package/dist/CustomerPaymentMethodEntity.js +26 -0
  6. package/dist/CustomerPaymentMethodEntity.js.map +1 -0
  7. package/dist/InitialPaymentIntentCompanion.d.ts +29 -0
  8. package/dist/InitialPaymentIntentCompanion.d.ts.map +1 -0
  9. package/dist/InitialPaymentIntentCompanion.js +40 -0
  10. package/dist/InitialPaymentIntentCompanion.js.map +1 -0
  11. package/dist/OrderHeaderEntity.d.ts +224 -0
  12. package/dist/OrderHeaderEntity.d.ts.map +1 -0
  13. package/dist/OrderHeaderEntity.js +509 -0
  14. package/dist/OrderHeaderEntity.js.map +1 -0
  15. package/dist/OrderLineEntity.d.ts +25 -0
  16. package/dist/OrderLineEntity.d.ts.map +1 -0
  17. package/dist/OrderLineEntity.js +54 -0
  18. package/dist/OrderLineEntity.js.map +1 -0
  19. package/dist/OrderLineExtensionCompanion.d.ts +54 -0
  20. package/dist/OrderLineExtensionCompanion.d.ts.map +1 -0
  21. package/dist/OrderLineExtensionCompanion.js +167 -0
  22. package/dist/OrderLineExtensionCompanion.js.map +1 -0
  23. package/dist/OrderStatusBehavior.d.ts +86 -0
  24. package/dist/OrderStatusBehavior.d.ts.map +1 -0
  25. package/dist/OrderStatusBehavior.js +160 -0
  26. package/dist/OrderStatusBehavior.js.map +1 -0
  27. package/dist/PartyAffiliationBehavior.d.ts +20 -0
  28. package/dist/PartyAffiliationBehavior.d.ts.map +1 -0
  29. package/dist/PartyAffiliationBehavior.js +52 -0
  30. package/dist/PartyAffiliationBehavior.js.map +1 -0
  31. package/dist/PaymentHeaderEntity.d.ts +18 -0
  32. package/dist/PaymentHeaderEntity.d.ts.map +1 -0
  33. package/dist/PaymentHeaderEntity.js +80 -0
  34. package/dist/PaymentHeaderEntity.js.map +1 -0
  35. package/dist/PricingDriverResolver.d.ts +70 -0
  36. package/dist/PricingDriverResolver.d.ts.map +1 -0
  37. package/dist/PricingDriverResolver.js +145 -0
  38. package/dist/PricingDriverResolver.js.map +1 -0
  39. package/dist/PromotionCodesCompanion.d.ts +77 -0
  40. package/dist/PromotionCodesCompanion.d.ts.map +1 -0
  41. package/dist/PromotionCodesCompanion.js +111 -0
  42. package/dist/PromotionCodesCompanion.js.map +1 -0
  43. package/dist/booked-money.d.ts +27 -0
  44. package/dist/booked-money.d.ts.map +1 -0
  45. package/dist/booked-money.js +67 -0
  46. package/dist/booked-money.js.map +1 -0
  47. package/dist/configuration-types.d.ts +157 -0
  48. package/dist/configuration-types.d.ts.map +1 -0
  49. package/dist/configuration-types.js +10 -0
  50. package/dist/configuration-types.js.map +1 -0
  51. package/dist/date-cell.d.ts +109 -0
  52. package/dist/date-cell.d.ts.map +1 -0
  53. package/dist/date-cell.js +131 -0
  54. package/dist/date-cell.js.map +1 -0
  55. package/dist/generated/entity_subclasses.d.ts +12055 -0
  56. package/dist/generated/entity_subclasses.d.ts.map +1 -0
  57. package/dist/generated/entity_subclasses.js +17800 -0
  58. package/dist/generated/entity_subclasses.js.map +1 -0
  59. package/dist/generated/remote_operations.d.ts +2365 -0
  60. package/dist/generated/remote_operations.d.ts.map +1 -0
  61. package/dist/generated/remote_operations.js +768 -0
  62. package/dist/generated/remote_operations.js.map +1 -0
  63. package/dist/index.d.ts +102 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +103 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/line-quantity.d.ts +6 -0
  68. package/dist/line-quantity.d.ts.map +1 -0
  69. package/dist/line-quantity.js +11 -0
  70. package/dist/line-quantity.js.map +1 -0
  71. package/dist/overdue.d.ts +77 -0
  72. package/dist/overdue.d.ts.map +1 -0
  73. package/dist/overdue.js +90 -0
  74. package/dist/overdue.js.map +1 -0
  75. package/dist/pricing/ChargeBehavior.d.ts +64 -0
  76. package/dist/pricing/ChargeBehavior.d.ts.map +1 -0
  77. package/dist/pricing/ChargeBehavior.js +124 -0
  78. package/dist/pricing/ChargeBehavior.js.map +1 -0
  79. package/dist/pricing/ChargeEngine.d.ts +54 -0
  80. package/dist/pricing/ChargeEngine.d.ts.map +1 -0
  81. package/dist/pricing/ChargeEngine.js +154 -0
  82. package/dist/pricing/ChargeEngine.js.map +1 -0
  83. package/dist/pricing/OrderPricingService.d.ts +244 -0
  84. package/dist/pricing/OrderPricingService.d.ts.map +1 -0
  85. package/dist/pricing/OrderPricingService.js +516 -0
  86. package/dist/pricing/OrderPricingService.js.map +1 -0
  87. package/dist/pricing/OrdersEngine.d.ts +100 -0
  88. package/dist/pricing/OrdersEngine.d.ts.map +1 -0
  89. package/dist/pricing/OrdersEngine.js +156 -0
  90. package/dist/pricing/OrdersEngine.js.map +1 -0
  91. package/dist/pricing/PriceResolver.d.ts +127 -0
  92. package/dist/pricing/PriceResolver.d.ts.map +1 -0
  93. package/dist/pricing/PriceResolver.js +345 -0
  94. package/dist/pricing/PriceResolver.js.map +1 -0
  95. package/dist/pricing/PricingBehavior.d.ts +161 -0
  96. package/dist/pricing/PricingBehavior.d.ts.map +1 -0
  97. package/dist/pricing/PricingBehavior.js +351 -0
  98. package/dist/pricing/PricingBehavior.js.map +1 -0
  99. package/dist/pricing/PromotionBehavior.d.ts +73 -0
  100. package/dist/pricing/PromotionBehavior.d.ts.map +1 -0
  101. package/dist/pricing/PromotionBehavior.js +166 -0
  102. package/dist/pricing/PromotionBehavior.js.map +1 -0
  103. package/dist/pricing/PromotionEngine.d.ts +131 -0
  104. package/dist/pricing/PromotionEngine.d.ts.map +1 -0
  105. package/dist/pricing/PromotionEngine.js +505 -0
  106. package/dist/pricing/PromotionEngine.js.map +1 -0
  107. package/dist/pricing/TaxResolver.d.ts +162 -0
  108. package/dist/pricing/TaxResolver.d.ts.map +1 -0
  109. package/dist/pricing/TaxResolver.js +361 -0
  110. package/dist/pricing/TaxResolver.js.map +1 -0
  111. package/dist/save-populated-fields.d.ts +17 -0
  112. package/dist/save-populated-fields.d.ts.map +1 -0
  113. package/dist/save-populated-fields.js +25 -0
  114. package/dist/save-populated-fields.js.map +1 -0
  115. package/package.json +34 -5
@@ -0,0 +1,157 @@
1
+ /**
2
+ * @fileoverview Configuration JSON Types for BizApps Orders
3
+ *
4
+ * Defines strongly-typed JSON configuration schemas for Product Types, Checkout Widgets,
5
+ * and custom UI pluggability (custom JS lifecycle hooks, scoped CSS, themes, and component overrides).
6
+ *
7
+ * @module @mj-biz-apps/orders-entities/configuration-types
8
+ */
9
+ export interface CustomUIThemeConfiguration {
10
+ primaryColor?: string;
11
+ accentColor?: string;
12
+ borderRadius?: string;
13
+ fontFamily?: string;
14
+ backgroundColor?: string;
15
+ textColor?: string;
16
+ [key: string]: unknown;
17
+ }
18
+ export interface CustomUIConfiguration {
19
+ /**
20
+ * Custom JavaScript code string containing lifecycle hooks or UI handlers.
21
+ */
22
+ js?: string;
23
+ /**
24
+ * Custom CSS stylesheet string containing scoped styling rules.
25
+ */
26
+ css?: string;
27
+ /**
28
+ * Theme tokens and color customizations.
29
+ */
30
+ theme?: CustomUIThemeConfiguration;
31
+ /**
32
+ * Registered custom component override key/class name.
33
+ */
34
+ componentOverrideKey?: string;
35
+ /**
36
+ * Additional UI settings and options.
37
+ */
38
+ [key: string]: unknown;
39
+ }
40
+ export interface FieldOverrideConfiguration {
41
+ label?: string;
42
+ placeholder?: string;
43
+ hidden?: boolean;
44
+ required?: boolean;
45
+ defaultValue?: unknown;
46
+ order?: number;
47
+ options?: Array<{
48
+ label: string;
49
+ value: string | number;
50
+ }>;
51
+ [key: string]: unknown;
52
+ }
53
+ export interface ProductTypeConfiguration {
54
+ /**
55
+ * Unit mode: 'perUnit' (discrete repeating fieldsets) vs 'perLine' (single fieldset for the line).
56
+ */
57
+ unitMode?: 'perUnit' | 'perLine';
58
+ /**
59
+ * Maximum quantity allowed per order or line.
60
+ */
61
+ maxQuantity?: number;
62
+ /**
63
+ * Whether quantity selection is permitted in self-service checkout surfaces.
64
+ */
65
+ allowQuantity?: boolean;
66
+ /**
67
+ * Field overrides and customizations for line extension entity fields.
68
+ */
69
+ fieldOverrides?: Record<string, FieldOverrideConfiguration>;
70
+ /**
71
+ * Custom UI section containing JS hooks, scoped CSS, theme tokens, and component overrides.
72
+ */
73
+ customUI?: CustomUIConfiguration;
74
+ /**
75
+ * Extensible custom properties.
76
+ */
77
+ [key: string]: unknown;
78
+ }
79
+ export interface CheckoutWidgetConfiguration {
80
+ title?: string;
81
+ description?: string;
82
+ productId?: string;
83
+ /**
84
+ * Explicit catalog this widget may sell. The anonymous draft edge rejects any
85
+ * ProductID not in this list (plus `productId` / SKU-resolved id). An empty
86
+ * catalog is a misconfiguration and the draft is refused, unless
87
+ * `allowAnyProduct` is explicitly true.
88
+ */
89
+ allowedProductIds?: string[];
90
+ /**
91
+ * When true, this widget sells any product that shares its CompanyID — an
92
+ * explicit open catalog, not the default. Absence of `productId` /
93
+ * `allowedProductIds` is NOT an open catalog. Requires the widget
94
+ * CompanyID (fail-closed if unset). Server-side only.
95
+ */
96
+ allowAnyProduct?: boolean;
97
+ /** Alternative product resolution by SKU when productId is not set. */
98
+ productSku?: string;
99
+ productName?: string;
100
+ unitPrice?: number;
101
+ currency?: string;
102
+ unitMode?: 'perUnit' | 'perLine';
103
+ allowQuantity?: boolean;
104
+ maxQuantity?: number;
105
+ stripePublishableKey?: string;
106
+ successMessage?: string;
107
+ redirectUrl?: string;
108
+ extensionEntityName?: string;
109
+ /**
110
+ * Metadata-driven form field specs — auto-discovered from the product type's extension
111
+ * entity when not explicitly authored.
112
+ */
113
+ extensionFields?: Array<{
114
+ name: string;
115
+ label: string;
116
+ type: 'text' | 'textarea' | 'number' | 'date' | 'boolean' | 'select';
117
+ required?: boolean;
118
+ placeholder?: string;
119
+ options?: Array<string | {
120
+ label: string;
121
+ value: string | number;
122
+ }>;
123
+ }>;
124
+ /**
125
+ * The PaymentProvider row id used to open payment intents for this widget's sessions.
126
+ * Admin-authored, server-resolved — never accepted from the client. Required before a
127
+ * paid checkout can complete.
128
+ */
129
+ paymentProviderId?: string;
130
+ /**
131
+ * `PaymentType.Code` used when CompleteCheckout books `Orders.CapturePayment`
132
+ * (e.g. `CreditCard`, `ACH`). Server-side only. Defaults to `CreditCard`.
133
+ */
134
+ tenderCode?: string;
135
+ /**
136
+ * Origins (scheme + host [+ port]) allowed to embed and drive this widget through the
137
+ * anonymous checkout edge. When set, requests whose Origin header does not match are
138
+ * refused and receive no CORS grant. When absent, the edge allows any origin (the
139
+ * distribution slug remains the access control).
140
+ */
141
+ allowedOrigins?: string[];
142
+ /**
143
+ * When true, the anonymous checkout edge requires a Cloudflare Turnstile token on
144
+ * session initialization and completion (the edge must also be configured with a
145
+ * Turnstile secret for verification to run — fail-closed when it is not).
146
+ */
147
+ requireTurnstile?: boolean;
148
+ /**
149
+ * Custom UI section containing JS hooks, scoped CSS, theme tokens, and component overrides.
150
+ */
151
+ customUI?: CustomUIConfiguration;
152
+ /**
153
+ * Extensible custom properties.
154
+ */
155
+ [key: string]: unknown;
156
+ }
157
+ //# sourceMappingURL=configuration-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration-types.d.ts","sourceRoot":"","sources":["../src/configuration-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @fileoverview Configuration JSON Types for BizApps Orders
3
+ *
4
+ * Defines strongly-typed JSON configuration schemas for Product Types, Checkout Widgets,
5
+ * and custom UI pluggability (custom JS lifecycle hooks, scoped CSS, themes, and component overrides).
6
+ *
7
+ * @module @mj-biz-apps/orders-entities/configuration-types
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=configuration-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration-types.js","sourceRoot":"","sources":["../src/configuration-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @fileoverview Reading a date cell that may be a string or a `Date`, and getting the same day back.
3
+ *
4
+ * ## Why this is here rather than in the server package
5
+ *
6
+ * `ToISODate` was written in `InvoiceBuilder.ts`, got the reasoning right, and stayed there — where
7
+ * only the server can reach it. Meanwhile fifteen other call sites, most of them in Angular pages,
8
+ * went on doing `String(cell).slice(0, 10)` by hand. Moving it into the shared package is the whole
9
+ * point: one statement of the rule, on both sides of the wire.
10
+ *
11
+ * ## The shape of the bug it prevents
12
+ *
13
+ * A date arrives in more than one shape depending on how it was fetched:
14
+ *
15
+ * ```text
16
+ * RunView 'entity_object' → Date (BaseEntity coerces on Get)
17
+ * RunView 'simple' → a string historically; a Date once MJ normalizes simple rows
18
+ * a GraphQL payload → string
19
+ * ```
20
+ *
21
+ * `String(cell).slice(0, 10)` is exactly right on a string. On a `Date` it yields **`'Thu Jul 30'`**,
22
+ * because `String(date)` is the long human form, not ISO. That value then goes on to be:
23
+ *
24
+ * ```text
25
+ * printed → an invoice dated 'Thu Jul 30', with no year on it
26
+ * compared → 'Thu Jul 30' < '2026-07-31' is FALSE for every row, forever, because letters
27
+ * sort after digits — so an overdue count reads zero and the screen looks calm
28
+ * re-parsed → new Date('Thu Jul 30') is Invalid Date
29
+ * ```
30
+ *
31
+ * The middle one is the dangerous one, and it is dangerous precisely because nothing fails.
32
+ *
33
+ * @module @mj-biz-apps/orders-entities
34
+ */
35
+ /**
36
+ * A date as it may actually arrive: an ISO-ish string, a `Date`, or absent.
37
+ *
38
+ * Deliberately NOT widened to include epoch milliseconds. `ToISODate` copes with a number at
39
+ * runtime, but no transport in this app delivers one, and advertising it in the type forces every
40
+ * consumer — `FormatDate`, `DaysSince` — to widen for a case that never arrives.
41
+ *
42
+ * Prefer this over `string` on any interface describing a row cell. A field typed `string` that
43
+ * holds a `Date` at runtime is worse than an honest union — the compiler cheerfully certifies the
44
+ * string operations that are about to go wrong.
45
+ *
46
+ * The readers below take `unknown` rather than this type, deliberately: normalizing the boundary is
47
+ * their entire job, and a reader that demanded a pre-narrowed input would push callers back to the
48
+ * casts it exists to remove. `DateCell` is for DECLARING a field; the readers accept whatever came.
49
+ */
50
+ export type DateCell = string | Date | null | undefined;
51
+ /**
52
+ * A calendar date as `YYYY-MM-DD`, whatever the data layer handed over, or `null`.
53
+ *
54
+ * The **UTC** components of a `Date` are read rather than the local ones, because a SQL `date`
55
+ * column has no time and the driver materialises it at midnight UTC — `getDate()` on a machine west
56
+ * of Greenwich returns the day before, which files an order in the wrong period while every total
57
+ * still reconciles.
58
+ *
59
+ * Note this is the opposite choice from formatting a date the USER just picked, which is a local
60
+ * midnight and must be read with local parts. The difference is where the `Date` came from, not
61
+ * preference: {@link Today} reads local for exactly that reason.
62
+ *
63
+ * An unparseable value is `null` rather than `'Invalid Date'` — which would print literally and
64
+ * destroy the evidence of what the database actually held.
65
+ */
66
+ export declare function ToISODate(value: unknown): string | null;
67
+ /**
68
+ * The four-digit year of a date cell, or `null`.
69
+ *
70
+ * Its own function because `ToISODate(x)?.slice(0, 4)` is the same lurking `String(...).slice()`
71
+ * shape one call deeper: it happens to be correct, and it reads exactly like the thing that was not.
72
+ */
73
+ export declare function ISOYear(value: unknown): string | null;
74
+ /**
75
+ * True when the cell names a day strictly before `day`.
76
+ *
77
+ * The overdue test, spelled once. Safe because fixed-width ISO days sort lexically in the same order
78
+ * they sort chronologically — the property the raw string comparisons were relying on, and the one
79
+ * the long `Date` form silently breaks.
80
+ *
81
+ * A cell with no readable date is **not** overdue: absence is not evidence of lateness, and treating
82
+ * it as such dunning-notices a customer over missing data.
83
+ *
84
+ * @param day - The reference day as `YYYY-MM-DD`, normally {@link Today}.
85
+ */
86
+ export declare function IsBefore(value: unknown, day: string): boolean;
87
+ /**
88
+ * Today on the LOCAL calendar as `YYYY-MM-DD`.
89
+ *
90
+ * Not `new Date().toISOString().slice(0, 10)`, which is already tomorrow for part of every evening
91
+ * east of Greenwich and still yesterday for part of every morning west of it — so an order placed at
92
+ * 8pm in New York would be measured against a "today" that has not started.
93
+ *
94
+ * Local parts here and UTC parts in {@link ToISODate} is not an inconsistency: this `Date` is an
95
+ * instant that the user is living in, and that one is a calendar day the driver pinned to midnight.
96
+ */
97
+ export declare function Today(): string;
98
+ /**
99
+ * The LOCAL calendar day of a `Date` the code constructed itself, as `YYYY-MM-DD`.
100
+ *
101
+ * For bucketing by day: a loop that walks back seven days from `new Date()` carries the current
102
+ * time of day with it, so `toISOString().slice(0, 10)` names TOMORROW for anyone east of the
103
+ * meridian in the evening — putting a bar's label ("Mon", from `toLocaleDateString`) and its key
104
+ * ("2026-08-11") on different days, and quietly reporting a day's takings as zero.
105
+ *
106
+ * Use this for dates the program built; use {@link ToISODate} for cells that came from the database.
107
+ */
108
+ export declare function LocalDay(date: Date): string;
109
+ //# sourceMappingURL=date-cell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-cell.d.ts","sourceRoot":"","sources":["../src/date-cell.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAuBvD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAErD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAG7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAG3C"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * @fileoverview Reading a date cell that may be a string or a `Date`, and getting the same day back.
3
+ *
4
+ * ## Why this is here rather than in the server package
5
+ *
6
+ * `ToISODate` was written in `InvoiceBuilder.ts`, got the reasoning right, and stayed there — where
7
+ * only the server can reach it. Meanwhile fifteen other call sites, most of them in Angular pages,
8
+ * went on doing `String(cell).slice(0, 10)` by hand. Moving it into the shared package is the whole
9
+ * point: one statement of the rule, on both sides of the wire.
10
+ *
11
+ * ## The shape of the bug it prevents
12
+ *
13
+ * A date arrives in more than one shape depending on how it was fetched:
14
+ *
15
+ * ```text
16
+ * RunView 'entity_object' → Date (BaseEntity coerces on Get)
17
+ * RunView 'simple' → a string historically; a Date once MJ normalizes simple rows
18
+ * a GraphQL payload → string
19
+ * ```
20
+ *
21
+ * `String(cell).slice(0, 10)` is exactly right on a string. On a `Date` it yields **`'Thu Jul 30'`**,
22
+ * because `String(date)` is the long human form, not ISO. That value then goes on to be:
23
+ *
24
+ * ```text
25
+ * printed → an invoice dated 'Thu Jul 30', with no year on it
26
+ * compared → 'Thu Jul 30' < '2026-07-31' is FALSE for every row, forever, because letters
27
+ * sort after digits — so an overdue count reads zero and the screen looks calm
28
+ * re-parsed → new Date('Thu Jul 30') is Invalid Date
29
+ * ```
30
+ *
31
+ * The middle one is the dangerous one, and it is dangerous precisely because nothing fails.
32
+ *
33
+ * @module @mj-biz-apps/orders-entities
34
+ */
35
+ /**
36
+ * A calendar date as `YYYY-MM-DD`, whatever the data layer handed over, or `null`.
37
+ *
38
+ * The **UTC** components of a `Date` are read rather than the local ones, because a SQL `date`
39
+ * column has no time and the driver materialises it at midnight UTC — `getDate()` on a machine west
40
+ * of Greenwich returns the day before, which files an order in the wrong period while every total
41
+ * still reconciles.
42
+ *
43
+ * Note this is the opposite choice from formatting a date the USER just picked, which is a local
44
+ * midnight and must be read with local parts. The difference is where the `Date` came from, not
45
+ * preference: {@link Today} reads local for exactly that reason.
46
+ *
47
+ * An unparseable value is `null` rather than `'Invalid Date'` — which would print literally and
48
+ * destroy the evidence of what the database actually held.
49
+ */
50
+ export function ToISODate(value) {
51
+ if (value == null || value === '')
52
+ return null;
53
+ if (value instanceof Date) {
54
+ if (Number.isNaN(value.getTime()))
55
+ return null;
56
+ return utcDay(value);
57
+ }
58
+ if (typeof value === 'number') {
59
+ if (!Number.isFinite(value))
60
+ return null;
61
+ const fromEpoch = new Date(value);
62
+ return Number.isNaN(fromEpoch.getTime()) ? null : utcDay(fromEpoch);
63
+ }
64
+ const text = String(value);
65
+ // The common case, needing no interpretation: '2026-07-30T00:00:00.000Z' and '2026-07-30' both
66
+ // yield '2026-07-30', with no timezone reasoning available to get wrong.
67
+ if (/^\d{4}-\d{2}-\d{2}/.test(text))
68
+ return text.slice(0, 10);
69
+ // Anything else — '7/30/2026', a driver's own format, or a value some earlier String(date)
70
+ // already mangled — goes to the platform parser.
71
+ const parsed = new Date(text);
72
+ return Number.isNaN(parsed.getTime()) ? null : utcDay(parsed);
73
+ }
74
+ /**
75
+ * The four-digit year of a date cell, or `null`.
76
+ *
77
+ * Its own function because `ToISODate(x)?.slice(0, 4)` is the same lurking `String(...).slice()`
78
+ * shape one call deeper: it happens to be correct, and it reads exactly like the thing that was not.
79
+ */
80
+ export function ISOYear(value) {
81
+ return ToISODate(value)?.slice(0, 4) ?? null;
82
+ }
83
+ /**
84
+ * True when the cell names a day strictly before `day`.
85
+ *
86
+ * The overdue test, spelled once. Safe because fixed-width ISO days sort lexically in the same order
87
+ * they sort chronologically — the property the raw string comparisons were relying on, and the one
88
+ * the long `Date` form silently breaks.
89
+ *
90
+ * A cell with no readable date is **not** overdue: absence is not evidence of lateness, and treating
91
+ * it as such dunning-notices a customer over missing data.
92
+ *
93
+ * @param day - The reference day as `YYYY-MM-DD`, normally {@link Today}.
94
+ */
95
+ export function IsBefore(value, day) {
96
+ const iso = ToISODate(value);
97
+ return iso !== null && iso < day;
98
+ }
99
+ /**
100
+ * Today on the LOCAL calendar as `YYYY-MM-DD`.
101
+ *
102
+ * Not `new Date().toISOString().slice(0, 10)`, which is already tomorrow for part of every evening
103
+ * east of Greenwich and still yesterday for part of every morning west of it — so an order placed at
104
+ * 8pm in New York would be measured against a "today" that has not started.
105
+ *
106
+ * Local parts here and UTC parts in {@link ToISODate} is not an inconsistency: this `Date` is an
107
+ * instant that the user is living in, and that one is a calendar day the driver pinned to midnight.
108
+ */
109
+ export function Today() {
110
+ return LocalDay(new Date());
111
+ }
112
+ /**
113
+ * The LOCAL calendar day of a `Date` the code constructed itself, as `YYYY-MM-DD`.
114
+ *
115
+ * For bucketing by day: a loop that walks back seven days from `new Date()` carries the current
116
+ * time of day with it, so `toISOString().slice(0, 10)` names TOMORROW for anyone east of the
117
+ * meridian in the evening — putting a bar's label ("Mon", from `toLocaleDateString`) and its key
118
+ * ("2026-08-11") on different days, and quietly reporting a day's takings as zero.
119
+ *
120
+ * Use this for dates the program built; use {@link ToISODate} for cells that came from the database.
121
+ */
122
+ export function LocalDay(date) {
123
+ if (Number.isNaN(date.getTime()))
124
+ return '';
125
+ return `${String(date.getFullYear()).padStart(4, '0')}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
126
+ }
127
+ /** The UTC calendar fields, zero-padded. */
128
+ function utcDay(date) {
129
+ return `${String(date.getUTCFullYear()).padStart(4, '0')}-${String(date.getUTCMonth() + 1).padStart(2, '0')}-${String(date.getUTCDate()).padStart(2, '0')}`;
130
+ }
131
+ //# sourceMappingURL=date-cell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-cell.js","sourceRoot":"","sources":["../src/date-cell.ts"],"names":[],"mappings":"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"}