@mj-biz-apps/sales-entities 6.15.2 → 6.16.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/account-contact-defaults.d.ts +36 -0
- package/dist/account-contact-defaults.d.ts.map +1 -0
- package/dist/account-contact-defaults.js +43 -0
- package/dist/account-contact-defaults.js.map +1 -0
- package/dist/billing-contact-default.d.ts +28 -0
- package/dist/billing-contact-default.d.ts.map +1 -0
- package/dist/billing-contact-default.js +42 -0
- package/dist/billing-contact-default.js.map +1 -0
- package/dist/close-lock.d.ts +4 -0
- package/dist/close-lock.d.ts.map +1 -1
- package/dist/close-lock.js +23 -0
- package/dist/close-lock.js.map +1 -1
- package/dist/deal-entity.d.ts +41 -1
- package/dist/deal-entity.d.ts.map +1 -1
- package/dist/deal-entity.js +96 -2
- package/dist/deal-entity.js.map +1 -1
- package/dist/deal-team-member-entity.d.ts +45 -0
- package/dist/deal-team-member-entity.d.ts.map +1 -0
- package/dist/deal-team-member-entity.js +83 -0
- package/dist/deal-team-member-entity.js.map +1 -0
- package/dist/downstream-seams.d.ts +5 -0
- package/dist/downstream-seams.d.ts.map +1 -1
- package/dist/downstream-seams.js.map +1 -1
- package/dist/generated/entities/__mj_BizAppsSales.d.ts +48 -6
- package/dist/generated/entities/__mj_BizAppsSales.d.ts.map +1 -1
- package/dist/generated/entities/__mj_BizAppsSales.js +62 -0
- package/dist/generated/entities/__mj_BizAppsSales.js.map +1 -1
- package/dist/generated/remote_operations.d.ts +5 -1
- package/dist/generated/remote_operations.d.ts.map +1 -1
- package/dist/generated/remote_operations.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Which of a deal's contacts take the account's default contacts.
|
|
3
|
+
*
|
|
4
|
+
* A Sales Account can name a default primary contact and a default billing contact (issue #254). When
|
|
5
|
+
* a rep chooses the account on a deal, each EMPTY contact field on the deal takes the account's
|
|
6
|
+
* default; the rep can still change or clear it.
|
|
7
|
+
*
|
|
8
|
+
* ── WHAT THIS NEVER DOES ────────────────────────────────────────────────────────────────────────
|
|
9
|
+
*
|
|
10
|
+
* - Overwrite a contact the deal already has. A contact on the deal is a choice somebody made, and the
|
|
11
|
+
* account changing is no reason to move the invoice or the relationship.
|
|
12
|
+
* - Copy an empty default. An account with no default billing contact leaves the deal's billing contact
|
|
13
|
+
* to the primary-contact rule (`BillingContactFromPrimary`), which is what an empty billing contact
|
|
14
|
+
* already means.
|
|
15
|
+
*
|
|
16
|
+
* A pure function for the same reason that rule is one: every caller shares one answer, and it is
|
|
17
|
+
* testable without standing up an entity.
|
|
18
|
+
*/
|
|
19
|
+
/** A pair of contact ids, as the deal and the account each hold them. */
|
|
20
|
+
export interface ContactPair {
|
|
21
|
+
PrimaryContactID: string | null | undefined;
|
|
22
|
+
BillingContactID: string | null | undefined;
|
|
23
|
+
}
|
|
24
|
+
/** The writes to make on the deal. A field that is absent is left alone. */
|
|
25
|
+
export interface ContactWrites {
|
|
26
|
+
PrimaryContactID?: string;
|
|
27
|
+
BillingContactID?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The contacts to write onto a deal from its account's defaults.
|
|
31
|
+
*
|
|
32
|
+
* @param deal The deal's contacts as they stand.
|
|
33
|
+
* @param defaults The account's default contacts.
|
|
34
|
+
*/
|
|
35
|
+
export declare function ContactsFromAccount(deal: ContactPair, defaults: ContactPair): ContactWrites;
|
|
36
|
+
//# sourceMappingURL=account-contact-defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-contact-defaults.d.ts","sourceRoot":"","sources":["../src/account-contact-defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,yEAAyE;AACzE,MAAM,WAAW,WAAW;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5C,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAC/C;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAYD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,GAAG,aAAa,CAO3F"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Which of a deal's contacts take the account's default contacts.
|
|
3
|
+
*
|
|
4
|
+
* A Sales Account can name a default primary contact and a default billing contact (issue #254). When
|
|
5
|
+
* a rep chooses the account on a deal, each EMPTY contact field on the deal takes the account's
|
|
6
|
+
* default; the rep can still change or clear it.
|
|
7
|
+
*
|
|
8
|
+
* ── WHAT THIS NEVER DOES ────────────────────────────────────────────────────────────────────────
|
|
9
|
+
*
|
|
10
|
+
* - Overwrite a contact the deal already has. A contact on the deal is a choice somebody made, and the
|
|
11
|
+
* account changing is no reason to move the invoice or the relationship.
|
|
12
|
+
* - Copy an empty default. An account with no default billing contact leaves the deal's billing contact
|
|
13
|
+
* to the primary-contact rule (`BillingContactFromPrimary`), which is what an empty billing contact
|
|
14
|
+
* already means.
|
|
15
|
+
*
|
|
16
|
+
* A pure function for the same reason that rule is one: every caller shares one answer, and it is
|
|
17
|
+
* testable without standing up an entity.
|
|
18
|
+
*/
|
|
19
|
+
/** True when the value names no record. */
|
|
20
|
+
function isEmpty(id) {
|
|
21
|
+
return id == null || id === '';
|
|
22
|
+
}
|
|
23
|
+
/** The account's default for one field, when the deal's own value is empty and the default is not. */
|
|
24
|
+
function fillFrom(dealValue, accountDefault) {
|
|
25
|
+
return isEmpty(dealValue) && !isEmpty(accountDefault) ? accountDefault : null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The contacts to write onto a deal from its account's defaults.
|
|
29
|
+
*
|
|
30
|
+
* @param deal The deal's contacts as they stand.
|
|
31
|
+
* @param defaults The account's default contacts.
|
|
32
|
+
*/
|
|
33
|
+
export function ContactsFromAccount(deal, defaults) {
|
|
34
|
+
const writes = {};
|
|
35
|
+
const primary = fillFrom(deal.PrimaryContactID, defaults.PrimaryContactID);
|
|
36
|
+
const billing = fillFrom(deal.BillingContactID, defaults.BillingContactID);
|
|
37
|
+
if (primary)
|
|
38
|
+
writes.PrimaryContactID = primary;
|
|
39
|
+
if (billing)
|
|
40
|
+
writes.BillingContactID = billing;
|
|
41
|
+
return writes;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=account-contact-defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-contact-defaults.js","sourceRoot":"","sources":["../src/account-contact-defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAcH,2CAA2C;AAC3C,SAAS,OAAO,CAAC,EAA6B;IAC1C,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC;AAED,sGAAsG;AACtG,SAAS,QAAQ,CAAC,SAAoC,EAAE,cAAyC;IAC7F,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAe,CAAC,CAAC,CAAC,IAAI,CAAC;AACnF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAiB,EAAE,QAAqB;IACxE,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAC3E,IAAI,OAAO;QAAE,MAAM,CAAC,gBAAgB,GAAG,OAAO,CAAC;IAC/C,IAAI,OAAO;QAAE,MAAM,CAAC,gBAAgB,GAAG,OAAO,CAAC;IAC/C,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview When a deal's Billing Contact takes its Primary Contact's value.
|
|
3
|
+
*
|
|
4
|
+
* The primary contact is usually the person the invoice goes to, so a rep who picks one should not
|
|
5
|
+
* have to search for the same person again in Billing Contact (issue #312). Picking a primary contact
|
|
6
|
+
* fills an EMPTY billing contact with the same person; the rep can still change or clear it.
|
|
7
|
+
*
|
|
8
|
+
* ── WHAT THIS NEVER DOES ────────────────────────────────────────────────────────────────────────
|
|
9
|
+
*
|
|
10
|
+
* - Overwrite a billing contact that is already filled in. A different billing contact is a choice
|
|
11
|
+
* somebody made, and replacing it because the primary changed would silently move the invoice.
|
|
12
|
+
* - Follow the primary contact after the copy. Once filled, the billing contact is its own value;
|
|
13
|
+
* changing the primary later leaves it alone (the rule above).
|
|
14
|
+
* - Treat an empty billing contact as missing. Empty still means "bill the primary contact", which is
|
|
15
|
+
* what the column says and what order provisioning falls back to. A rep who clears the copy gets that.
|
|
16
|
+
*
|
|
17
|
+
* A pure function so both tiers and every caller share one answer, and so it is testable without
|
|
18
|
+
* standing up an entity.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* The contact to write into Billing Contact after Primary Contact was set, or null to leave it alone.
|
|
22
|
+
*
|
|
23
|
+
* @param priorPrimary Primary Contact before the write.
|
|
24
|
+
* @param nextPrimary Primary Contact after the write.
|
|
25
|
+
* @param billing Billing Contact as it stands.
|
|
26
|
+
*/
|
|
27
|
+
export declare function BillingContactFromPrimary(priorPrimary: string | null | undefined, nextPrimary: string | null | undefined, billing: string | null | undefined): string | null;
|
|
28
|
+
//# sourceMappingURL=billing-contact-default.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing-contact-default.d.ts","sourceRoot":"","sources":["../src/billing-contact-default.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACrC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACvC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACtC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,MAAM,GAAG,IAAI,CAUf"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview When a deal's Billing Contact takes its Primary Contact's value.
|
|
3
|
+
*
|
|
4
|
+
* The primary contact is usually the person the invoice goes to, so a rep who picks one should not
|
|
5
|
+
* have to search for the same person again in Billing Contact (issue #312). Picking a primary contact
|
|
6
|
+
* fills an EMPTY billing contact with the same person; the rep can still change or clear it.
|
|
7
|
+
*
|
|
8
|
+
* ── WHAT THIS NEVER DOES ────────────────────────────────────────────────────────────────────────
|
|
9
|
+
*
|
|
10
|
+
* - Overwrite a billing contact that is already filled in. A different billing contact is a choice
|
|
11
|
+
* somebody made, and replacing it because the primary changed would silently move the invoice.
|
|
12
|
+
* - Follow the primary contact after the copy. Once filled, the billing contact is its own value;
|
|
13
|
+
* changing the primary later leaves it alone (the rule above).
|
|
14
|
+
* - Treat an empty billing contact as missing. Empty still means "bill the primary contact", which is
|
|
15
|
+
* what the column says and what order provisioning falls back to. A rep who clears the copy gets that.
|
|
16
|
+
*
|
|
17
|
+
* A pure function so both tiers and every caller share one answer, and so it is testable without
|
|
18
|
+
* standing up an entity.
|
|
19
|
+
*/
|
|
20
|
+
/** True when the value names no record. */
|
|
21
|
+
function isEmpty(id) {
|
|
22
|
+
return id == null || id === '';
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The contact to write into Billing Contact after Primary Contact was set, or null to leave it alone.
|
|
26
|
+
*
|
|
27
|
+
* @param priorPrimary Primary Contact before the write.
|
|
28
|
+
* @param nextPrimary Primary Contact after the write.
|
|
29
|
+
* @param billing Billing Contact as it stands.
|
|
30
|
+
*/
|
|
31
|
+
export function BillingContactFromPrimary(priorPrimary, nextPrimary, billing) {
|
|
32
|
+
if (isEmpty(nextPrimary) || !isEmpty(billing)) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
// Only a CHANGE of primary copies. Writing the same value again (a field re-emitting its value)
|
|
36
|
+
// must not refill a billing contact the rep deliberately cleared.
|
|
37
|
+
if (!isEmpty(priorPrimary) && priorPrimary.toLowerCase() === nextPrimary.toLowerCase()) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return nextPrimary;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=billing-contact-default.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing-contact-default.js","sourceRoot":"","sources":["../src/billing-contact-default.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,2CAA2C;AAC3C,SAAS,OAAO,CAAC,EAA6B;IAC1C,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CACrC,YAAuC,EACvC,WAAsC,EACtC,OAAkC;IAElC,IAAI,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,gGAAgG;IAChG,kEAAkE;IAClE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,YAAa,CAAC,WAAW,EAAE,KAAK,WAAY,CAAC,WAAW,EAAE,EAAE,CAAC;QACvF,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,WAAY,CAAC;AACxB,CAAC"}
|
package/dist/close-lock.d.ts
CHANGED
|
@@ -43,6 +43,10 @@ export declare function DealFieldsEditableWhileLocked(isLost: boolean): Readonly
|
|
|
43
43
|
* Callers should prefer this to reaching into the sets, so the membership test stays in one place.
|
|
44
44
|
*/
|
|
45
45
|
export declare function IsDealFieldEditableWhileLocked(fieldName: string, isLost: boolean): boolean;
|
|
46
|
+
/** Every close stamp, for a caller that has to walk them. */
|
|
47
|
+
export declare function DealCloseStampFields(): readonly string[];
|
|
48
|
+
/** Whether `fieldName` is a close stamp, which only the close and the reopen may write. */
|
|
49
|
+
export declare function IsDealCloseStamp(fieldName: string): boolean;
|
|
46
50
|
/** The on-screen label for a deal field: the override if there is one, else the field name split into words. */
|
|
47
51
|
export declare function DealFieldLabel(fieldName: string): string;
|
|
48
52
|
/**
|
package/dist/close-lock.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"close-lock.d.ts","sourceRoot":"","sources":["../src/close-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AA0C9D;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAKlF;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAE1F;
|
|
1
|
+
{"version":3,"file":"close-lock.d.ts","sourceRoot":"","sources":["../src/close-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AA0C9D;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAKlF;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAE1F;AAgBD,6DAA6D;AAC7D,wBAAgB,oBAAoB,IAAI,SAAS,MAAM,EAAE,CAExD;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE3D;AAoDD,gHAAgH;AAChH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAE7E;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAI5D;AAKD,mGAAmG;AACnG,MAAM,WAAW,aAAa;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,sEAAsE;IACtE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;;;;;OAQG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,KAAK,EAAE,OAAO,CAAC;IACf,oEAAoE;IACpE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,oBAAoB,CACtC,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC5C,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,aAAa,CAAC,CAyExB;AAED,4FAA4F;AAC5F,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,SAAS,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAiC/F"}
|
package/dist/close-lock.js
CHANGED
|
@@ -88,6 +88,27 @@ export function DealFieldsEditableWhileLocked(isLost) {
|
|
|
88
88
|
export function IsDealFieldEditableWhileLocked(fieldName, isLost) {
|
|
89
89
|
return EDITABLE_ON_ANY_LOCKED_DEAL.has(fieldName) || (isLost && EDITABLE_ON_A_LOST_DEAL.has(fieldName));
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* The close stamps: written by `Sales.CloseDeal`, cleared by `Sales.ReopenDeal`, and by nothing else
|
|
93
|
+
* (bizapps-sales#252).
|
|
94
|
+
*
|
|
95
|
+
* Not a lock rule -- they are frozen on an OPEN deal too. Every surface that asks "has this deal
|
|
96
|
+
* closed?" reads these stamps, because they are what the close writes when it actually runs. A stamp
|
|
97
|
+
* typed onto an open deal therefore made the whole header call it closed: a rep looking for where to
|
|
98
|
+
* enter an expected close found Actual Close Date, typed a future day, and the deal read "Closed".
|
|
99
|
+
*
|
|
100
|
+
* Here for the reason the lock's own list is: the entity server refuses a direct write and the form
|
|
101
|
+
* renders the fields read-only, and both read this one set.
|
|
102
|
+
*/
|
|
103
|
+
const DEAL_CLOSE_STAMP_FIELDS = new Set(['ClosedAt', 'ActualCloseDate', 'ClosedByUserID']);
|
|
104
|
+
/** Every close stamp, for a caller that has to walk them. */
|
|
105
|
+
export function DealCloseStampFields() {
|
|
106
|
+
return [...DEAL_CLOSE_STAMP_FIELDS];
|
|
107
|
+
}
|
|
108
|
+
/** Whether `fieldName` is a close stamp, which only the close and the reopen may write. */
|
|
109
|
+
export function IsDealCloseStamp(fieldName) {
|
|
110
|
+
return DEAL_CLOSE_STAMP_FIELDS.has(fieldName);
|
|
111
|
+
}
|
|
91
112
|
/**
|
|
92
113
|
* What each editable-while-locked field is CALLED on screen.
|
|
93
114
|
*
|
|
@@ -108,6 +129,8 @@ const DEAL_FIELD_LABELS = {
|
|
|
108
129
|
CampaignID: 'Campaign',
|
|
109
130
|
LossNotes: 'Loss Notes',
|
|
110
131
|
DealStatusTypeID: 'Deal Status',
|
|
132
|
+
// The close stamps, named in the refusal a direct write gets (#252).
|
|
133
|
+
ClosedByUserID: 'Closed By',
|
|
111
134
|
};
|
|
112
135
|
/**
|
|
113
136
|
* Splits a column name into words and drops a trailing `ID`: `ExpectedCloseDate` -> `Expected Close
|
package/dist/close-lock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"close-lock.js","sourceRoot":"","sources":["../src/close-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,OAAO,EAAiB,MAAM,sBAAsB,CAAC;AAE9D;;;;;;GAMG;AACH,MAAM,2BAA2B,GAAwB,IAAI,GAAG,CAAS;IACrE,gGAAgG;IAChG,2CAA2C;IAC3C,aAAa;IACb,kGAAkG;IAClG,2DAA2D;IAC3D,UAAU;IACV,cAAc;IACd,gGAAgG;IAChG,mGAAmG;IACnG,gCAAgC;IAChC,kBAAkB;IAClB,kBAAkB;IAClB,YAAY;CACf,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,uBAAuB,GAAwB,IAAI,GAAG,CAAS,CAAC,WAAW,CAAC,CAAC,CAAC;AAEpF;;;;;;;;GAQG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAAe;IACzD,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,2BAA2B,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,GAAG,CAAS,CAAC,GAAG,2BAA2B,EAAE,GAAG,uBAAuB,CAAC,CAAC,CAAC;AACzF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAAC,SAAiB,EAAE,MAAe;IAC7E,OAAO,2BAA2B,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,IAAI,uBAAuB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AAC5G,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,iBAAiB,GAAqC;IACxD,WAAW,EAAE,aAAa;IAC1B,QAAQ,EAAE,WAAW;IACrB,YAAY,EAAE,gBAAgB;IAC9B,gBAAgB,EAAE,iBAAiB;IACnC,gBAAgB,EAAE,aAAa;IAC/B,UAAU,EAAE,UAAU;IACtB,SAAS,EAAE,YAAY;IACvB,gBAAgB,EAAE,aAAa;
|
|
1
|
+
{"version":3,"file":"close-lock.js","sourceRoot":"","sources":["../src/close-lock.ts"],"names":[],"mappings":"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"}
|
package/dist/deal-entity.d.ts
CHANGED
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
*/
|
|
48
48
|
import { EntitySaveOptions, ValidationResult } from '@memberjunction/core';
|
|
49
49
|
import { mjBizAppsOrdersOrderHeaderEntity } from '@mj-biz-apps/orders-entities';
|
|
50
|
+
import { type ContactPair } from './account-contact-defaults.js';
|
|
50
51
|
import { mjBizAppsSalesDealEntity, mjBizAppsSalesDealPaymentScheduleEntity } from './generated/entity_subclasses.js';
|
|
51
52
|
/** The house default the form pre-fills for a new deal's payment method. */
|
|
52
53
|
export declare const DEAL_DEFAULT_PAYMENT_METHOD = "ACH";
|
|
@@ -169,6 +170,45 @@ export declare class DealEntity extends mjBizAppsSalesDealEntity {
|
|
|
169
170
|
* twice.
|
|
170
171
|
*/
|
|
171
172
|
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
173
|
+
/**
|
|
174
|
+
* ── PICKING A PRIMARY CONTACT FILLS AN EMPTY BILLING CONTACT (#312) ─────────────────────────────
|
|
175
|
+
*
|
|
176
|
+
* The rule is {@link BillingContactFromPrimary}; this is where it runs.
|
|
177
|
+
*
|
|
178
|
+
* WHY `Set` AND NOT THE `PrimaryContactID` SETTER. The deal form's `mj-form-field` writes through
|
|
179
|
+
* `Record.Set(FieldName, value)`, which never touches the generated accessor; the deal workspace's
|
|
180
|
+
* `ngModel` writes through the accessor, which calls `Set`. Overriding `Set` is the one place both
|
|
181
|
+
* reach, so the two surfaces cannot drift. Loads and `SetMany` hydrate through `SetLocal` and skip
|
|
182
|
+
* this, so reading a deal from the database never fills anything.
|
|
183
|
+
*
|
|
184
|
+
* `Value` is `unknown` because the base signature is untyped and this only forwards it.
|
|
185
|
+
*/
|
|
186
|
+
Set(FieldName: string, Value: unknown): void;
|
|
187
|
+
/**
|
|
188
|
+
* ── CHOOSING AN ACCOUNT FILLS THE DEAL'S EMPTY CONTACTS FROM IT (#254) ────────────────────────
|
|
189
|
+
*
|
|
190
|
+
* The rule is {@link ContactsFromAccount}; this reads the account and applies it. The deal form and
|
|
191
|
+
* the deal workspace call it after the rep changes the account.
|
|
192
|
+
*
|
|
193
|
+
* WHY A METHOD THE SURFACES CALL, NOT PART OF `Set`. Filling needs the account's row, which is a
|
|
194
|
+
* database read, and `Set` cannot wait for one. A read started inside `Set` and left running could
|
|
195
|
+
* land after the save it was meant to feed, or after the rep had picked a different account.
|
|
196
|
+
*
|
|
197
|
+
* BILLING IS WRITTEN BEFORE PRIMARY, so the account's billing default wins over the
|
|
198
|
+
* primary-fills-billing rule in `Set`. When the account has no billing default, writing the primary
|
|
199
|
+
* then fills an empty billing contact from it, as picking a primary by hand does.
|
|
200
|
+
*
|
|
201
|
+
* @returns the fields it filled; empty when there was nothing to fill, or when the account changed
|
|
202
|
+
* while the read was in flight (that account's own call fills from it).
|
|
203
|
+
*/
|
|
204
|
+
FillContactsFromAccount(): Promise<Array<keyof ContactPair>>;
|
|
205
|
+
/**
|
|
206
|
+
* The account's two default contacts. Throws when the read fails, so a caller can say the defaults
|
|
207
|
+
* were not applied rather than leave the fields empty without a word.
|
|
208
|
+
*
|
|
209
|
+
* Protected so tests can stand in for the database.
|
|
210
|
+
*/
|
|
211
|
+
protected ReadAccountContactDefaults(accountID: string): Promise<ContactPair>;
|
|
172
212
|
/**
|
|
173
213
|
* @remarks
|
|
174
214
|
* `super.Validate()` is what fans out to the child collections, so it must be called and its result
|
|
@@ -225,7 +265,7 @@ export declare class DealPaymentScheduleEntity extends mjBizAppsSalesDealPayment
|
|
|
225
265
|
Validate(): ValidationResult;
|
|
226
266
|
}
|
|
227
267
|
/**
|
|
228
|
-
* Anchor that keeps the
|
|
268
|
+
* Anchor that keeps the shared registrations (these and `DealTeamMemberEntity`) from being tree-shaken.
|
|
229
269
|
*
|
|
230
270
|
* THIS LOOKS POINTLESS AND IS NOT. `@RegisterClass` registers as a side effect of the module being
|
|
231
271
|
* imported, and nothing references these classes by name — so a bundler is entirely correct to elide
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deal-entity.d.ts","sourceRoot":"","sources":["../src/deal-entity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,OAAO,EAEH,iBAAiB,EAIjB,gBAAgB,EACnB,MAAM,sBAAsB,CAAC;AAW9B,OAAO,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAEhF,OAAO,EACH,wBAAwB,EACxB,uCAAuC,EAC1C,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"deal-entity.d.ts","sourceRoot":"","sources":["../src/deal-entity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,OAAO,EAEH,iBAAiB,EAIjB,gBAAgB,EACnB,MAAM,sBAAsB,CAAC;AAW9B,OAAO,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAEhF,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEnF,OAAO,EACH,wBAAwB,EACxB,uCAAuC,EAC1C,MAAM,+BAA+B,CAAC;AAGvC,4EAA4E;AAC5E,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AAgDjD;;;;;GAKG;AACH,qBACa,UAAW,SAAQ,wBAAwB;IACpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACH,OAAO,CAAC,QAAQ,CAAC,eAAe,CAI7B;IAEH;;;;;OAKG;IACH,IAAW,cAAc,IAAI,gCAAgC,GAAG,IAAI,CAEnE;IAED;;;;;;OAMG;IACI,oBAAoB,IAAI,gCAAgC;IAI/D;;;;;;;;OAQG;IACU,kBAAkB,IAAI,OAAO,CAAC,gCAAgC,GAAG,IAAI,CAAC;IAKnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiDG;IACmB,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAQzE;;;;;;;;;;;;OAYG;IACa,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAa5D;;;;;;;;;;;;;;;;OAgBG;IACU,uBAAuB,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,CAAC;IAyBzE;;;;;OAKG;cACa,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAwBnF;;;;;OAKG;IACa,QAAQ,IAAI,gBAAgB;IA2D5C;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACU,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B/D;;;;;;OAMG;cACa,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;CAsBxD;AAED;;;;;;;;GAQG;AAEH;;GAEG;AACH,qBACa,yBAA0B,SAAQ,uCAAuC;IAClE,QAAQ,IAAI,gBAAgB;CAa/C;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAK5C"}
|
package/dist/deal-entity.js
CHANGED
|
@@ -53,9 +53,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
53
53
|
*/
|
|
54
54
|
import { BaseEntity, ValidationErrorInfo, ValidationErrorType, } from '@memberjunction/core';
|
|
55
55
|
import { RegisterClass } from '@memberjunction/global';
|
|
56
|
+
import { ContactsFromAccount } from './account-contact-defaults.js';
|
|
57
|
+
import { BillingContactFromPrimary } from './billing-contact-default.js';
|
|
56
58
|
import { mjBizAppsSalesDealEntity, mjBizAppsSalesDealPaymentScheduleEntity, } from './generated/entity_subclasses.js';
|
|
59
|
+
import { DealTeamMemberEntity } from './deal-team-member-entity.js';
|
|
57
60
|
/** The house default the form pre-fills for a new deal's payment method. */
|
|
58
61
|
export const DEAL_DEFAULT_PAYMENT_METHOD = 'ACH';
|
|
62
|
+
/** A record id the account-defaults lookup may put in a filter. Anything else is refused, not quoted. */
|
|
63
|
+
const GUID_PATTERN = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
59
64
|
/**
|
|
60
65
|
* Records a blocking problem. Separated from {@link warn} because only a failure clears
|
|
61
66
|
* `result.Success`, and the difference is what lets a surface distinguish "you cannot save this" from
|
|
@@ -223,6 +228,95 @@ let DealEntity = class DealEntity extends mjBizAppsSalesDealEntity {
|
|
|
223
228
|
}
|
|
224
229
|
return saved;
|
|
225
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* ── PICKING A PRIMARY CONTACT FILLS AN EMPTY BILLING CONTACT (#312) ─────────────────────────────
|
|
233
|
+
*
|
|
234
|
+
* The rule is {@link BillingContactFromPrimary}; this is where it runs.
|
|
235
|
+
*
|
|
236
|
+
* WHY `Set` AND NOT THE `PrimaryContactID` SETTER. The deal form's `mj-form-field` writes through
|
|
237
|
+
* `Record.Set(FieldName, value)`, which never touches the generated accessor; the deal workspace's
|
|
238
|
+
* `ngModel` writes through the accessor, which calls `Set`. Overriding `Set` is the one place both
|
|
239
|
+
* reach, so the two surfaces cannot drift. Loads and `SetMany` hydrate through `SetLocal` and skip
|
|
240
|
+
* this, so reading a deal from the database never fills anything.
|
|
241
|
+
*
|
|
242
|
+
* `Value` is `unknown` because the base signature is untyped and this only forwards it.
|
|
243
|
+
*/
|
|
244
|
+
Set(FieldName, Value) {
|
|
245
|
+
if (FieldName !== 'PrimaryContactID') {
|
|
246
|
+
super.Set(FieldName, Value);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const priorPrimary = this.PrimaryContactID;
|
|
250
|
+
super.Set(FieldName, Value);
|
|
251
|
+
const billing = BillingContactFromPrimary(priorPrimary, this.PrimaryContactID, this.BillingContactID);
|
|
252
|
+
if (billing) {
|
|
253
|
+
super.Set('BillingContactID', billing);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* ── CHOOSING AN ACCOUNT FILLS THE DEAL'S EMPTY CONTACTS FROM IT (#254) ────────────────────────
|
|
258
|
+
*
|
|
259
|
+
* The rule is {@link ContactsFromAccount}; this reads the account and applies it. The deal form and
|
|
260
|
+
* the deal workspace call it after the rep changes the account.
|
|
261
|
+
*
|
|
262
|
+
* WHY A METHOD THE SURFACES CALL, NOT PART OF `Set`. Filling needs the account's row, which is a
|
|
263
|
+
* database read, and `Set` cannot wait for one. A read started inside `Set` and left running could
|
|
264
|
+
* land after the save it was meant to feed, or after the rep had picked a different account.
|
|
265
|
+
*
|
|
266
|
+
* BILLING IS WRITTEN BEFORE PRIMARY, so the account's billing default wins over the
|
|
267
|
+
* primary-fills-billing rule in `Set`. When the account has no billing default, writing the primary
|
|
268
|
+
* then fills an empty billing contact from it, as picking a primary by hand does.
|
|
269
|
+
*
|
|
270
|
+
* @returns the fields it filled; empty when there was nothing to fill, or when the account changed
|
|
271
|
+
* while the read was in flight (that account's own call fills from it).
|
|
272
|
+
*/
|
|
273
|
+
async FillContactsFromAccount() {
|
|
274
|
+
const accountID = this.AccountID;
|
|
275
|
+
if (!accountID) {
|
|
276
|
+
return [];
|
|
277
|
+
}
|
|
278
|
+
const defaults = await this.ReadAccountContactDefaults(accountID);
|
|
279
|
+
if (this.AccountID?.toLowerCase() !== accountID.toLowerCase()) {
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
const writes = ContactsFromAccount({ PrimaryContactID: this.PrimaryContactID, BillingContactID: this.BillingContactID }, defaults);
|
|
283
|
+
const filled = [];
|
|
284
|
+
if (writes.BillingContactID) {
|
|
285
|
+
this.Set('BillingContactID', writes.BillingContactID);
|
|
286
|
+
filled.push('BillingContactID');
|
|
287
|
+
}
|
|
288
|
+
if (writes.PrimaryContactID) {
|
|
289
|
+
this.Set('PrimaryContactID', writes.PrimaryContactID);
|
|
290
|
+
filled.push('PrimaryContactID');
|
|
291
|
+
}
|
|
292
|
+
return filled;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The account's two default contacts. Throws when the read fails, so a caller can say the defaults
|
|
296
|
+
* were not applied rather than leave the fields empty without a word.
|
|
297
|
+
*
|
|
298
|
+
* Protected so tests can stand in for the database.
|
|
299
|
+
*/
|
|
300
|
+
async ReadAccountContactDefaults(accountID) {
|
|
301
|
+
if (!GUID_PATTERN.test(accountID)) {
|
|
302
|
+
throw new Error(`DealEntity: the deal's account id "${accountID}" is not a record id.`);
|
|
303
|
+
}
|
|
304
|
+
const provider = this.ProviderToUse;
|
|
305
|
+
const result = await provider.RunView({
|
|
306
|
+
EntityName: 'MJ_BizApps_Sales: Sales Accounts',
|
|
307
|
+
ExtraFilter: `ID = '${accountID}'`,
|
|
308
|
+
ResultType: 'simple',
|
|
309
|
+
Fields: ['DefaultPrimaryContactID', 'DefaultBillingContactID'],
|
|
310
|
+
}, this.ContextCurrentUser);
|
|
311
|
+
if (!result.Success) {
|
|
312
|
+
throw new Error(`DealEntity: could not read the account's default contacts: ${result.ErrorMessage}`);
|
|
313
|
+
}
|
|
314
|
+
const row = (result.Results ?? [])[0];
|
|
315
|
+
return {
|
|
316
|
+
PrimaryContactID: row?.DefaultPrimaryContactID ?? null,
|
|
317
|
+
BillingContactID: row?.DefaultBillingContactID ?? null,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
226
320
|
/**
|
|
227
321
|
* @remarks
|
|
228
322
|
* `super.Validate()` is what fans out to the child collections, so it must be called and its result
|
|
@@ -367,7 +461,7 @@ DealPaymentScheduleEntity = __decorate([
|
|
|
367
461
|
], DealPaymentScheduleEntity);
|
|
368
462
|
export { DealPaymentScheduleEntity };
|
|
369
463
|
/**
|
|
370
|
-
* Anchor that keeps the
|
|
464
|
+
* Anchor that keeps the shared registrations (these and `DealTeamMemberEntity`) from being tree-shaken.
|
|
371
465
|
*
|
|
372
466
|
* THIS LOOKS POINTLESS AND IS NOT. `@RegisterClass` registers as a side effect of the module being
|
|
373
467
|
* imported, and nothing references these classes by name — so a bundler is entirely correct to elide
|
|
@@ -375,7 +469,7 @@ export { DealPaymentScheduleEntity };
|
|
|
375
469
|
* this file quietly stops applying. Touching the symbols is what keeps the import alive.
|
|
376
470
|
*/
|
|
377
471
|
export function LoadSalesDealEntities() {
|
|
378
|
-
const anchors = [DealEntity, DealPaymentScheduleEntity];
|
|
472
|
+
const anchors = [DealEntity, DealPaymentScheduleEntity, DealTeamMemberEntity];
|
|
379
473
|
if (anchors.length === 0) {
|
|
380
474
|
throw new Error('LoadSalesDealEntities: registration anchors were tree-shaken away.');
|
|
381
475
|
}
|
package/dist/deal-entity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deal-entity.js","sourceRoot":"","sources":["../src/deal-entity.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,OAAO,EACH,UAAU,EAGV,mBAAmB,EACnB,mBAAmB,GAEtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAYvD,OAAO,EACH,wBAAwB,EACxB,uCAAuC,GAC1C,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"deal-entity.js","sourceRoot":"","sources":["../src/deal-entity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The shared `DealTeamMember` entity subclass — the employee-or-person rule, on the entity
|
|
3
|
+
* so the browser and the server run the same code.
|
|
4
|
+
*
|
|
5
|
+
* A team member is EITHER an MJ Employee (the internal rep, the common case) OR a common.Person (a
|
|
6
|
+
* partner rep or contractor). The table enforces it with `CK_DealTeamMember_EmployeeXorPerson`, and
|
|
7
|
+
* until this class nothing above the database did. A row that ended up with both — a new employee
|
|
8
|
+
* picked on a row whose Person was already filled — reached SQL and came back as a raw CHECK
|
|
9
|
+
* constraint error, on the exact path the duplicate-role refusal tells a user to take ("change that
|
|
10
|
+
* row's employee").
|
|
11
|
+
*
|
|
12
|
+
* Two halves, and both are needed:
|
|
13
|
+
*
|
|
14
|
+
* - `Set()` CLEARS THE OTHER FIELD when one is given a value, so changing who holds the row is one
|
|
15
|
+
* action rather than two. It is on the entity rather than a form because the Internal team grid is
|
|
16
|
+
* MJ's generic related-entity grid with no hook to attach to, and the generated team row form is
|
|
17
|
+
* regenerated by CodeGen.
|
|
18
|
+
* - `Validate()` REFUSES both-or-neither with a message a user can act on, for every write that did
|
|
19
|
+
* not go through `Set()` — `SetMany`, a hydrated payload, an API caller. The CHECK constraint stays
|
|
20
|
+
* as the backstop it was written to be.
|
|
21
|
+
*
|
|
22
|
+
* `DealTeamMemberEntityServer` extends THIS class, so the server keeps both and adds the rules that need
|
|
23
|
+
* a database on top.
|
|
24
|
+
*
|
|
25
|
+
* @module @mj-biz-apps/sales-entities
|
|
26
|
+
*/
|
|
27
|
+
import { ValidationResult } from '@memberjunction/core';
|
|
28
|
+
import { mjBizAppsSalesDealTeamMemberEntity } from './generated/entity_subclasses.js';
|
|
29
|
+
export declare const TEAM_MEMBER_BOTH_MESSAGE = "A team member is either an employee or a person, not both. Clear one of them.";
|
|
30
|
+
export declare const TEAM_MEMBER_NEITHER_MESSAGE = "Choose an employee, or a person for someone outside the company.";
|
|
31
|
+
export declare class DealTeamMemberEntity extends mjBizAppsSalesDealTeamMemberEntity {
|
|
32
|
+
/**
|
|
33
|
+
* Giving EmployeeID or PersonID a value clears the other.
|
|
34
|
+
*
|
|
35
|
+
* Only a NON-EMPTY value clears, so emptying one field never empties its partner. Loads do not come
|
|
36
|
+
* through here (`SetMany` writes with `SetLocal`), so reading a stored row changes nothing.
|
|
37
|
+
*/
|
|
38
|
+
Set(FieldName: string, Value: unknown): void;
|
|
39
|
+
/**
|
|
40
|
+
* @remarks `super.Validate()` carries the generated field checks, so its result is built upon rather
|
|
41
|
+
* than replaced.
|
|
42
|
+
*/
|
|
43
|
+
Validate(): ValidationResult;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=deal-team-member-entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deal-team-member-entity.d.ts","sourceRoot":"","sources":["../src/deal-team-member-entity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAwD,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG9G,OAAO,EAAE,kCAAkC,EAAE,MAAM,+BAA+B,CAAC;AAQnF,eAAO,MAAM,wBAAwB,kFAC8C,CAAC;AACpF,eAAO,MAAM,2BAA2B,qEAC8B,CAAC;AAMvE,qBACa,oBAAqB,SAAQ,kCAAkC;IACxE;;;;;OAKG;IACa,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAQ5D;;;OAGG;IACa,QAAQ,IAAI,gBAAgB;CAiB/C"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* @fileoverview The shared `DealTeamMember` entity subclass — the employee-or-person rule, on the entity
|
|
9
|
+
* so the browser and the server run the same code.
|
|
10
|
+
*
|
|
11
|
+
* A team member is EITHER an MJ Employee (the internal rep, the common case) OR a common.Person (a
|
|
12
|
+
* partner rep or contractor). The table enforces it with `CK_DealTeamMember_EmployeeXorPerson`, and
|
|
13
|
+
* until this class nothing above the database did. A row that ended up with both — a new employee
|
|
14
|
+
* picked on a row whose Person was already filled — reached SQL and came back as a raw CHECK
|
|
15
|
+
* constraint error, on the exact path the duplicate-role refusal tells a user to take ("change that
|
|
16
|
+
* row's employee").
|
|
17
|
+
*
|
|
18
|
+
* Two halves, and both are needed:
|
|
19
|
+
*
|
|
20
|
+
* - `Set()` CLEARS THE OTHER FIELD when one is given a value, so changing who holds the row is one
|
|
21
|
+
* action rather than two. It is on the entity rather than a form because the Internal team grid is
|
|
22
|
+
* MJ's generic related-entity grid with no hook to attach to, and the generated team row form is
|
|
23
|
+
* regenerated by CodeGen.
|
|
24
|
+
* - `Validate()` REFUSES both-or-neither with a message a user can act on, for every write that did
|
|
25
|
+
* not go through `Set()` — `SetMany`, a hydrated payload, an API caller. The CHECK constraint stays
|
|
26
|
+
* as the backstop it was written to be.
|
|
27
|
+
*
|
|
28
|
+
* `DealTeamMemberEntityServer` extends THIS class, so the server keeps both and adds the rules that need
|
|
29
|
+
* a database on top.
|
|
30
|
+
*
|
|
31
|
+
* @module @mj-biz-apps/sales-entities
|
|
32
|
+
*/
|
|
33
|
+
import { BaseEntity, ValidationErrorInfo, ValidationErrorType } from '@memberjunction/core';
|
|
34
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
35
|
+
import { mjBizAppsSalesDealTeamMemberEntity } from './generated/entity_subclasses.js';
|
|
36
|
+
/** Each identity field and the one it excludes. */
|
|
37
|
+
const OTHER_IDENTITY_FIELD = {
|
|
38
|
+
EmployeeID: 'PersonID',
|
|
39
|
+
PersonID: 'EmployeeID',
|
|
40
|
+
};
|
|
41
|
+
export const TEAM_MEMBER_BOTH_MESSAGE = 'A team member is either an employee or a person, not both. Clear one of them.';
|
|
42
|
+
export const TEAM_MEMBER_NEITHER_MESSAGE = 'Choose an employee, or a person for someone outside the company.';
|
|
43
|
+
function hasValue(value) {
|
|
44
|
+
return value !== null && value !== undefined && value !== '';
|
|
45
|
+
}
|
|
46
|
+
let DealTeamMemberEntity = class DealTeamMemberEntity extends mjBizAppsSalesDealTeamMemberEntity {
|
|
47
|
+
/**
|
|
48
|
+
* Giving EmployeeID or PersonID a value clears the other.
|
|
49
|
+
*
|
|
50
|
+
* Only a NON-EMPTY value clears, so emptying one field never empties its partner. Loads do not come
|
|
51
|
+
* through here (`SetMany` writes with `SetLocal`), so reading a stored row changes nothing.
|
|
52
|
+
*/
|
|
53
|
+
Set(FieldName, Value) {
|
|
54
|
+
super.Set(FieldName, Value);
|
|
55
|
+
const other = OTHER_IDENTITY_FIELD[FieldName];
|
|
56
|
+
if (other && hasValue(Value) && hasValue(this.Get(other))) {
|
|
57
|
+
super.Set(other, null);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* @remarks `super.Validate()` carries the generated field checks, so its result is built upon rather
|
|
62
|
+
* than replaced.
|
|
63
|
+
*/
|
|
64
|
+
Validate() {
|
|
65
|
+
const result = super.Validate();
|
|
66
|
+
const hasEmployee = hasValue(this.EmployeeID);
|
|
67
|
+
const hasPerson = hasValue(this.PersonID);
|
|
68
|
+
if (hasEmployee && hasPerson) {
|
|
69
|
+
result.Success = false;
|
|
70
|
+
result.Errors.push(new ValidationErrorInfo('PersonID', TEAM_MEMBER_BOTH_MESSAGE, this.PersonID, ValidationErrorType.Failure));
|
|
71
|
+
}
|
|
72
|
+
else if (!hasEmployee && !hasPerson) {
|
|
73
|
+
result.Success = false;
|
|
74
|
+
result.Errors.push(new ValidationErrorInfo('EmployeeID', TEAM_MEMBER_NEITHER_MESSAGE, this.EmployeeID, ValidationErrorType.Failure));
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
DealTeamMemberEntity = __decorate([
|
|
80
|
+
RegisterClass(BaseEntity, 'MJ_BizApps_Sales: Deal Team Members')
|
|
81
|
+
], DealTeamMemberEntity);
|
|
82
|
+
export { DealTeamMemberEntity };
|
|
83
|
+
//# sourceMappingURL=deal-team-member-entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deal-team-member-entity.js","sourceRoot":"","sources":["../src/deal-team-member-entity.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,mBAAmB,EAAoB,MAAM,sBAAsB,CAAC;AAC9G,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EAAE,kCAAkC,EAAE,MAAM,+BAA+B,CAAC;AAEnF,mDAAmD;AACnD,MAAM,oBAAoB,GAAqC;IAC3D,UAAU,EAAE,UAAU;IACtB,QAAQ,EAAE,YAAY;CACzB,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GACjC,+EAA+E,CAAC;AACpF,MAAM,CAAC,MAAM,2BAA2B,GACpC,kEAAkE,CAAC;AAEvE,SAAS,QAAQ,CAAC,KAAc;IAC5B,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC;AACjE,CAAC;AAGM,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,kCAAkC;IACxE;;;;;OAKG;IACa,GAAG,CAAC,SAAiB,EAAE,KAAc;QACjD,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACxD,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC3B,CAAC;IACL,CAAC;IAED;;;OAGG;IACa,QAAQ;QACpB,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,WAAW,IAAI,SAAS,EAAE,CAAC;YAC3B,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;YACvB,MAAM,CAAC,MAAM,CAAC,IAAI,CACd,IAAI,mBAAmB,CAAC,UAAU,EAAE,wBAAwB,EAAE,IAAI,CAAC,QAAQ,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAC5G,CAAC;QACN,CAAC;aAAM,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,EAAE,CAAC;YACpC,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;YACvB,MAAM,CAAC,MAAM,CAAC,IAAI,CACd,IAAI,mBAAmB,CAAC,YAAY,EAAE,2BAA2B,EAAE,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,OAAO,CAAC,CACnH,CAAC;QACN,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ,CAAA;AApCY,oBAAoB;IADhC,aAAa,CAAC,UAAU,EAAE,qCAAqC,CAAC;GACpD,oBAAoB,CAoChC"}
|