@mj-biz-apps/contracts-entities 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ContractEntity.d.ts +36 -0
- package/dist/ContractEntity.d.ts.map +1 -1
- package/dist/ContractEntity.js +54 -0
- package/dist/ContractEntity.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/supersede-candidates.d.ts +54 -0
- package/dist/supersede-candidates.d.ts.map +1 -0
- package/dist/supersede-candidates.js +60 -0
- package/dist/supersede-candidates.js.map +1 -0
- package/package.json +4 -3
package/dist/ContractEntity.d.ts
CHANGED
|
@@ -57,6 +57,26 @@ export declare function IsSameContractLevel(myParentID: string | null | undefine
|
|
|
57
57
|
* provision is one problem rather than two.
|
|
58
58
|
*/
|
|
59
59
|
export declare function FindDuplicateProvisionIDs(provisionIDs: readonly unknown[]): string[];
|
|
60
|
+
/**
|
|
61
|
+
* R-12 — `CK_Contract_Dates` as a predicate: is this pair of dates definitely out of order?
|
|
62
|
+
*
|
|
63
|
+
* MIRRORS THE CONSTRAINT EXACTLY, which is `EndDate IS NULL OR EffectiveDate IS NULL OR EndDate >=
|
|
64
|
+
* EffectiveDate`. So this returns true ONLY when both dates are readable and the end really does fall
|
|
65
|
+
* before the start. Three consequences worth stating, because each is a way the obvious version would
|
|
66
|
+
* be wrong:
|
|
67
|
+
*
|
|
68
|
+
* * EQUAL DATES PASS. A contract that starts and ends on the same day is a real one-day agreement.
|
|
69
|
+
* Refusing it would reject rows the database accepts — worse than the error being replaced.
|
|
70
|
+
* * EITHER MISSING PASSES. Half-filled dates are the normal state of a form mid-edit, and the
|
|
71
|
+
* constraint itself allows them.
|
|
72
|
+
* * UNREADABLE PASSES. Typed `Date | null`, but a form binding can put a string here, and comparing
|
|
73
|
+
* a string to a Date compares nonsense rather than throwing. Anything that will not parse is
|
|
74
|
+
* treated as "not yet known" rather than as an error on a field still being typed.
|
|
75
|
+
*
|
|
76
|
+
* Exported and pure so it can be asserted directly, the way `IsSameContractLevel` above is — not
|
|
77
|
+
* restated in a test, which is a copy that can drift from the rule it claims to check.
|
|
78
|
+
*/
|
|
79
|
+
export declare function IsEndBeforeEffective(effectiveDate: unknown, endDate: unknown): boolean;
|
|
60
80
|
export declare class ContractEntity extends mjBizAppsContractsContractEntity {
|
|
61
81
|
/**
|
|
62
82
|
* `HasModifications` is MONOTONIC: it must be true when modification rows exist, and it is never
|
|
@@ -73,6 +93,22 @@ export declare class ContractEntity extends mjBizAppsContractsContractEntity {
|
|
|
73
93
|
* on a contract whose paper really was negotiated. A human sets it false, or it stays true.
|
|
74
94
|
*/
|
|
75
95
|
Validate(): ValidationResult;
|
|
96
|
+
/**
|
|
97
|
+
* R-12 — `CK_Contract_Dates` in words, before the database says it in SQL.
|
|
98
|
+
*
|
|
99
|
+
* The constraint has always existed, so the data was never at risk; what the user got was the raw
|
|
100
|
+
* violation text naming a constraint and no field. This runs in the browser AND on the server
|
|
101
|
+
* (`Validate()` is shared), so the message arrives on the End Date field before a save is attempted.
|
|
102
|
+
*
|
|
103
|
+
* THE PREDICATE MIRRORS THE CONSTRAINT EXACTLY — `EndDate IS NULL OR EffectiveDate IS NULL OR
|
|
104
|
+
* EndDate >= EffectiveDate`. Both-null and either-null pass, and equal dates pass: a contract that
|
|
105
|
+
* starts and ends on the same day is a real one-day agreement, and refusing it here would reject
|
|
106
|
+
* rows the database accepts, which is worse than the error it replaces.
|
|
107
|
+
*
|
|
108
|
+
* The constraint STAYS. This is the friendly path, not the enforcement: a write that reaches the
|
|
109
|
+
* table by some other route still meets the check.
|
|
110
|
+
*/
|
|
111
|
+
private refuseEndBeforeEffective;
|
|
76
112
|
/**
|
|
77
113
|
* R-10 — two modifications of the SAME provision, caught among the rows in hand.
|
|
78
114
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContractEntity.d.ts","sourceRoot":"","sources":["../src/ContractEntity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAwD,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE9G,OAAO,EAAE,gCAAgC,EAAE,MAAM,+BAA+B,CAAC;AAEjF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAM5H;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,EAAE,CAWpF;AAED,qBACa,cAAe,SAAQ,gCAAgC;IAChE;;;;;;;;;;;;;OAaG;IACa,QAAQ,IAAI,gBAAgB;
|
|
1
|
+
{"version":3,"file":"ContractEntity.d.ts","sourceRoot":"","sources":["../src/ContractEntity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAwD,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE9G,OAAO,EAAE,gCAAgC,EAAE,MAAM,+BAA+B,CAAC;AAEjF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAM5H;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,EAAE,CAWpF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAUtF;AAED,qBACa,cAAe,SAAQ,gCAAgC;IAChE;;;;;;;;;;;;;OAaG;IACa,QAAQ,IAAI,gBAAgB;IAwB5C;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,wBAAwB;IAchC;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,kCAAkC;IAkB1C;;;;;;;;;;;;;;;;;;;OAmBG;IACH;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,OAAO,CAAC,4BAA4B;IAmBpC;;;;OAIG;IACH,SAAS,CAAC,uBAAuB,UAAS;IAE1C;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IAIjC;;;;;;;;;;;OAWG;IACI,SAAS,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI;CAgBpD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
package/dist/ContractEntity.js
CHANGED
|
@@ -85,6 +85,38 @@ export function FindDuplicateProvisionIDs(provisionIDs) {
|
|
|
85
85
|
}
|
|
86
86
|
return duplicates;
|
|
87
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* R-12 — `CK_Contract_Dates` as a predicate: is this pair of dates definitely out of order?
|
|
90
|
+
*
|
|
91
|
+
* MIRRORS THE CONSTRAINT EXACTLY, which is `EndDate IS NULL OR EffectiveDate IS NULL OR EndDate >=
|
|
92
|
+
* EffectiveDate`. So this returns true ONLY when both dates are readable and the end really does fall
|
|
93
|
+
* before the start. Three consequences worth stating, because each is a way the obvious version would
|
|
94
|
+
* be wrong:
|
|
95
|
+
*
|
|
96
|
+
* * EQUAL DATES PASS. A contract that starts and ends on the same day is a real one-day agreement.
|
|
97
|
+
* Refusing it would reject rows the database accepts — worse than the error being replaced.
|
|
98
|
+
* * EITHER MISSING PASSES. Half-filled dates are the normal state of a form mid-edit, and the
|
|
99
|
+
* constraint itself allows them.
|
|
100
|
+
* * UNREADABLE PASSES. Typed `Date | null`, but a form binding can put a string here, and comparing
|
|
101
|
+
* a string to a Date compares nonsense rather than throwing. Anything that will not parse is
|
|
102
|
+
* treated as "not yet known" rather than as an error on a field still being typed.
|
|
103
|
+
*
|
|
104
|
+
* Exported and pure so it can be asserted directly, the way `IsSameContractLevel` above is — not
|
|
105
|
+
* restated in a test, which is a copy that can drift from the rule it claims to check.
|
|
106
|
+
*/
|
|
107
|
+
export function IsEndBeforeEffective(effectiveDate, endDate) {
|
|
108
|
+
const at = (v) => {
|
|
109
|
+
if (v === null || v === undefined || v === '')
|
|
110
|
+
return null;
|
|
111
|
+
const t = v instanceof Date ? v.getTime() : new Date(v).getTime();
|
|
112
|
+
return Number.isFinite(t) ? t : null;
|
|
113
|
+
};
|
|
114
|
+
const effective = at(effectiveDate);
|
|
115
|
+
const end = at(endDate);
|
|
116
|
+
if (effective === null || end === null)
|
|
117
|
+
return false;
|
|
118
|
+
return end < effective;
|
|
119
|
+
}
|
|
88
120
|
let ContractEntity = class ContractEntity extends mjBizAppsContractsContractEntity {
|
|
89
121
|
constructor() {
|
|
90
122
|
super(...arguments);
|
|
@@ -119,8 +151,30 @@ let ContractEntity = class ContractEntity extends mjBizAppsContractsContractEnti
|
|
|
119
151
|
`the agreement really is standard.`, this.HasModifications, ValidationErrorType.Failure));
|
|
120
152
|
}
|
|
121
153
|
this.refuseDuplicateStagedModifications(result);
|
|
154
|
+
this.refuseEndBeforeEffective(result);
|
|
122
155
|
return result;
|
|
123
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* R-12 — `CK_Contract_Dates` in words, before the database says it in SQL.
|
|
159
|
+
*
|
|
160
|
+
* The constraint has always existed, so the data was never at risk; what the user got was the raw
|
|
161
|
+
* violation text naming a constraint and no field. This runs in the browser AND on the server
|
|
162
|
+
* (`Validate()` is shared), so the message arrives on the End Date field before a save is attempted.
|
|
163
|
+
*
|
|
164
|
+
* THE PREDICATE MIRRORS THE CONSTRAINT EXACTLY — `EndDate IS NULL OR EffectiveDate IS NULL OR
|
|
165
|
+
* EndDate >= EffectiveDate`. Both-null and either-null pass, and equal dates pass: a contract that
|
|
166
|
+
* starts and ends on the same day is a real one-day agreement, and refusing it here would reject
|
|
167
|
+
* rows the database accepts, which is worse than the error it replaces.
|
|
168
|
+
*
|
|
169
|
+
* The constraint STAYS. This is the friendly path, not the enforcement: a write that reaches the
|
|
170
|
+
* table by some other route still meets the check.
|
|
171
|
+
*/
|
|
172
|
+
refuseEndBeforeEffective(result) {
|
|
173
|
+
if (!IsEndBeforeEffective(this.EffectiveDate, this.EndDate))
|
|
174
|
+
return;
|
|
175
|
+
result.Success = false;
|
|
176
|
+
result.Errors.push(new ValidationErrorInfo('EndDate', 'End Date must be on or after the Effective Date.', this.EndDate, ValidationErrorType.Failure));
|
|
177
|
+
}
|
|
124
178
|
/**
|
|
125
179
|
* R-10 — two modifications of the SAME provision, caught among the rows in hand.
|
|
126
180
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContractEntity.js","sourceRoot":"","sources":["../src/ContractEntity.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,mBAAmB,EAAoB,MAAM,sBAAsB,CAAC;AAC9G,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,gCAAgC,EAAE,MAAM,+BAA+B,CAAC;AAEjF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAqC,EAAE,aAAwC;IAC/G,MAAM,CAAC,GAAG,UAAU,IAAI,IAAI,CAAC;IAC7B,MAAM,CAAC,GAAG,aAAa,IAAI,IAAI,CAAC;IAChC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC3C,OAAO,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,yBAAyB,CAAC,YAAgC;IACtE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAClD,IAAI,CAAC,EAAE;YAAE,SAAS;QAClB,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACrB,IAAI,IAAI,KAAK,CAAC;YAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,UAAU,CAAC;AACtB,CAAC;AAGM,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,gCAAgC;IAA7D;;
|
|
1
|
+
{"version":3,"file":"ContractEntity.js","sourceRoot":"","sources":["../src/ContractEntity.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -27,4 +27,6 @@ export * from './required-field-prose.js';
|
|
|
27
27
|
export * from './ContractTypeEntity.js';
|
|
28
28
|
export * from './value-list-validation.js';
|
|
29
29
|
export * from './contract-state.js';
|
|
30
|
+
/** Which contracts the Supersedes picker may offer, and how it names them (#28 item 4). */
|
|
31
|
+
export * from './supersede-candidates.js';
|
|
30
32
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,cAAc,+BAA+B,CAAC;AAI9C,cAAc,kBAAkB,CAAC;AAIjC,cAAc,sCAAsC,CAAC;AAIrD,cAAc,mCAAmC,CAAC;AAIlD,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AAIvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AAMxC,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,cAAc,+BAA+B,CAAC;AAI9C,cAAc,kBAAkB,CAAC;AAIjC,cAAc,sCAAsC,CAAC;AAIrD,cAAc,mCAAmC,CAAC;AAIlD,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AAIvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AAMxC,cAAc,kBAAkB,CAAC;AAEjC,2FAA2F;AAC3F,cAAc,wBAAwB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,8 @@ export * from './value-list-validation.js';
|
|
|
41
41
|
* would contradict the form on screen — and because StateSQL() is what the migration's CASE is checked
|
|
42
42
|
* against by contract-state.test.ts. */
|
|
43
43
|
export * from './contract-state.js';
|
|
44
|
+
/** Which contracts the Supersedes picker may offer, and how it names them (#28 item 4). */
|
|
45
|
+
export * from './supersede-candidates.js';
|
|
44
46
|
/* NOTE on `src/generated/remote_operations.ts`: CodeGen writes it, and it is deliberately NOT
|
|
45
47
|
* re-exported. v2 ships zero remote operations (plan §6.3), so every symbol in that file is an
|
|
46
48
|
* MJ-CORE operation (AISkill, PredictiveStudio, TaskGraph, …) emitted into every app's file
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,cAAc,+BAA+B,CAAC;AAE9C;kFACkF;AAClF,cAAc,kBAAkB,CAAC;AAEjC;qGACqG;AACrG,cAAc,sCAAsC,CAAC;AAErD;wEACwE;AACxE,cAAc,mCAAmC,CAAC;AAElD;wGACwG;AACxG,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AAEvC;2FAC2F;AAC3F,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AAExC;;;wCAGwC;AACxC,cAAc,kBAAkB,CAAC;AAEjC;;;;oFAIoF"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,cAAc,+BAA+B,CAAC;AAE9C;kFACkF;AAClF,cAAc,kBAAkB,CAAC;AAEjC;qGACqG;AACrG,cAAc,sCAAsC,CAAC;AAErD;wEACwE;AACxE,cAAc,mCAAmC,CAAC;AAElD;wGACwG;AACxG,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AAEvC;2FAC2F;AAC3F,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AAExC;;;wCAGwC;AACxC,cAAc,kBAAkB,CAAC;AAEjC,2FAA2F;AAC3F,cAAc,wBAAwB,CAAC;AAEvC;;;;oFAIoF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Which contracts the Supersedes picker may offer, and how it names them.
|
|
3
|
+
*
|
|
4
|
+
* contracts#28 item 4 states the rule as four conditions, all of which must hold. A candidate is a
|
|
5
|
+
* contract that is:
|
|
6
|
+
*
|
|
7
|
+
* 1. the SAME CUSTOMER as this contract — {@link SameCustomerClause}
|
|
8
|
+
* 2. at the SAME LEVEL — `IsSameContractLevel`, in `ContractEntity.ts`, where it already lived
|
|
9
|
+
* 3. NOT already superseded — a plain `SupersededByContractID IS NULL`
|
|
10
|
+
* 4. not this contract — a plain `ID <> …`
|
|
11
|
+
*
|
|
12
|
+
* WHY THESE LIVE HERE AND NOT ON THE PANEL. `supersede.panel.ts` is an Angular component, so anything
|
|
13
|
+
* declared inside it can only be asserted by standing up Angular's DI — importing it from a unit test
|
|
14
|
+
* fails with "the injectable 'PlatformLocation' needs to be compiled using the JIT compiler". Rules 3
|
|
15
|
+
* and 4 have nothing to decide, but 1 and the label format both do, and both are stated as final in
|
|
16
|
+
* the issue, which makes them worth pinning. Rule 2 was already here for the same reason.
|
|
17
|
+
*
|
|
18
|
+
* The panel still owns the QUERY. These own the decisions inside it.
|
|
19
|
+
*
|
|
20
|
+
* @module @mj-biz-apps/contracts-entities
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The same-customer clause — rule 1 — or one that deliberately matches nothing.
|
|
24
|
+
*
|
|
25
|
+
* A re-papering replaces one customer's agreement with another agreement for THAT customer. Offering
|
|
26
|
+
* another customer's contract is not merely untidy: linking it points one organisation's lineage at
|
|
27
|
+
* another's, so the successor's terms read as governing a party that never signed them, and the
|
|
28
|
+
* predecessor's customer loses the trail to whatever replaced their agreement.
|
|
29
|
+
*
|
|
30
|
+
* AN ABSENT CUSTOMER YIELDS NOTHING, NOT EVERYTHING, and the direction is the whole point.
|
|
31
|
+
* `CustomerOrganizationID` is NOT NULL on Contract, so a missing value never means "this contract has
|
|
32
|
+
* no customer" — it means the record could not be read. Widening to every contract at that moment
|
|
33
|
+
* would offer the whole book precisely when the caller knows least, which is the failure rule 1
|
|
34
|
+
* exists to prevent.
|
|
35
|
+
*/
|
|
36
|
+
export declare function SameCustomerClause(customerID: string | null | undefined): string;
|
|
37
|
+
/**
|
|
38
|
+
* The option label: `<ContractNumber> — <Description>`, falling back to the contract type.
|
|
39
|
+
*
|
|
40
|
+
* Quoted as final in the issue. The description is what a person recognises — "Platform licence, 2026
|
|
41
|
+
* renewal" — while the type is a category several contracts share, so a list labelled by type reads
|
|
42
|
+
* as several copies of the same row.
|
|
43
|
+
*
|
|
44
|
+
* The description is TRIMMED before the emptiness test, because blank descriptions are common on
|
|
45
|
+
* imported records and a label reading `CTR-0007 — ` looks like missing data rather than an
|
|
46
|
+
* uncategorised agreement. The second fallback to "Contract" exists so a row with neither can never
|
|
47
|
+
* render a dangling dash.
|
|
48
|
+
*/
|
|
49
|
+
export declare function ContractOptionLabel(c: {
|
|
50
|
+
ContractNumber: string;
|
|
51
|
+
ContractType: string | null;
|
|
52
|
+
Description: string | null;
|
|
53
|
+
}): string;
|
|
54
|
+
//# sourceMappingURL=supersede-candidates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supersede-candidates.d.ts","sourceRoot":"","sources":["../src/supersede-candidates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAMhF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,MAAM,CAGT"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Which contracts the Supersedes picker may offer, and how it names them.
|
|
3
|
+
*
|
|
4
|
+
* contracts#28 item 4 states the rule as four conditions, all of which must hold. A candidate is a
|
|
5
|
+
* contract that is:
|
|
6
|
+
*
|
|
7
|
+
* 1. the SAME CUSTOMER as this contract — {@link SameCustomerClause}
|
|
8
|
+
* 2. at the SAME LEVEL — `IsSameContractLevel`, in `ContractEntity.ts`, where it already lived
|
|
9
|
+
* 3. NOT already superseded — a plain `SupersededByContractID IS NULL`
|
|
10
|
+
* 4. not this contract — a plain `ID <> …`
|
|
11
|
+
*
|
|
12
|
+
* WHY THESE LIVE HERE AND NOT ON THE PANEL. `supersede.panel.ts` is an Angular component, so anything
|
|
13
|
+
* declared inside it can only be asserted by standing up Angular's DI — importing it from a unit test
|
|
14
|
+
* fails with "the injectable 'PlatformLocation' needs to be compiled using the JIT compiler". Rules 3
|
|
15
|
+
* and 4 have nothing to decide, but 1 and the label format both do, and both are stated as final in
|
|
16
|
+
* the issue, which makes them worth pinning. Rule 2 was already here for the same reason.
|
|
17
|
+
*
|
|
18
|
+
* The panel still owns the QUERY. These own the decisions inside it.
|
|
19
|
+
*
|
|
20
|
+
* @module @mj-biz-apps/contracts-entities
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The same-customer clause — rule 1 — or one that deliberately matches nothing.
|
|
24
|
+
*
|
|
25
|
+
* A re-papering replaces one customer's agreement with another agreement for THAT customer. Offering
|
|
26
|
+
* another customer's contract is not merely untidy: linking it points one organisation's lineage at
|
|
27
|
+
* another's, so the successor's terms read as governing a party that never signed them, and the
|
|
28
|
+
* predecessor's customer loses the trail to whatever replaced their agreement.
|
|
29
|
+
*
|
|
30
|
+
* AN ABSENT CUSTOMER YIELDS NOTHING, NOT EVERYTHING, and the direction is the whole point.
|
|
31
|
+
* `CustomerOrganizationID` is NOT NULL on Contract, so a missing value never means "this contract has
|
|
32
|
+
* no customer" — it means the record could not be read. Widening to every contract at that moment
|
|
33
|
+
* would offer the whole book precisely when the caller knows least, which is the failure rule 1
|
|
34
|
+
* exists to prevent.
|
|
35
|
+
*/
|
|
36
|
+
export function SameCustomerClause(customerID) {
|
|
37
|
+
const id = (customerID ?? '').trim();
|
|
38
|
+
if (!id)
|
|
39
|
+
return '1 = 0';
|
|
40
|
+
// The value reaches an `ExtraFilter` as a string. It is a UUID by construction, so this should
|
|
41
|
+
// never fire — which is exactly why dropping it would go unnoticed.
|
|
42
|
+
return `CustomerOrganizationID = '${id.replace(/'/g, "''")}'`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The option label: `<ContractNumber> — <Description>`, falling back to the contract type.
|
|
46
|
+
*
|
|
47
|
+
* Quoted as final in the issue. The description is what a person recognises — "Platform licence, 2026
|
|
48
|
+
* renewal" — while the type is a category several contracts share, so a list labelled by type reads
|
|
49
|
+
* as several copies of the same row.
|
|
50
|
+
*
|
|
51
|
+
* The description is TRIMMED before the emptiness test, because blank descriptions are common on
|
|
52
|
+
* imported records and a label reading `CTR-0007 — ` looks like missing data rather than an
|
|
53
|
+
* uncategorised agreement. The second fallback to "Contract" exists so a row with neither can never
|
|
54
|
+
* render a dangling dash.
|
|
55
|
+
*/
|
|
56
|
+
export function ContractOptionLabel(c) {
|
|
57
|
+
const described = (c.Description ?? '').trim();
|
|
58
|
+
return `${c.ContractNumber} — ${described || c.ContractType || 'Contract'}`;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=supersede-candidates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supersede-candidates.js","sourceRoot":"","sources":["../src/supersede-candidates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAqC;IACpE,MAAM,EAAE,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,IAAI,CAAC,EAAE;QAAE,OAAO,OAAO,CAAC;IACxB,+FAA+F;IAC/F,oEAAoE;IACpE,OAAO,6BAA6B,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;AAClE,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,CAInC;IACG,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,OAAO,GAAG,CAAC,CAAC,cAAc,MAAM,SAAS,IAAI,CAAC,CAAC,YAAY,IAAI,UAAU,EAAE,CAAC;AAChF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mj-biz-apps/contracts-entities",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Generated entity subclasses for the app schema. TODO(template): rename package + description.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"@memberjunction/global": "^6.1.0-edge.4"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"typescript": "^5.9.3"
|
|
21
|
+
"typescript": "^5.9.3",
|
|
22
|
+
"vitest": "^4.0.18"
|
|
22
23
|
},
|
|
23
24
|
"files": [
|
|
24
25
|
"/dist"
|
|
@@ -28,6 +29,6 @@
|
|
|
28
29
|
},
|
|
29
30
|
"scripts": {
|
|
30
31
|
"build": "tsc && tsc-alias -f",
|
|
31
|
-
"test": "
|
|
32
|
+
"test": "vitest run --passWithNoTests"
|
|
32
33
|
}
|
|
33
34
|
}
|