@things-factory/sales 0.0.0-stage → 10.1.176
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/CHANGELOG.md +8 -0
- package/assets/images/hatiolab-logo.png +0 -0
- package/dist-client/bootstrap.d.ts +1 -0
- package/dist-client/bootstrap.js +5 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/entity360/opportunity-360.d.ts +12 -0
- package/dist-client/entity360/opportunity-360.js +114 -0
- package/dist-client/entity360/opportunity-360.js.map +1 -0
- package/dist-client/index.d.ts +4 -0
- package/dist-client/index.js +5 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/opportunity-attach.d.ts +17 -0
- package/dist-client/opportunity-attach.js +8 -0
- package/dist-client/opportunity-attach.js.map +1 -0
- package/dist-client/opportunity-words.d.ts +1 -0
- package/dist-client/opportunity-words.js +13 -0
- package/dist-client/opportunity-words.js.map +1 -0
- package/dist-client/pages/opportunity-editor.d.ts +81 -0
- package/dist-client/pages/opportunity-editor.js +482 -0
- package/dist-client/pages/opportunity-editor.js.map +1 -0
- package/dist-client/pages/opportunity-list.d.ts +40 -0
- package/dist-client/pages/opportunity-list.js +134 -0
- package/dist-client/pages/opportunity-list.js.map +1 -0
- package/dist-client/pages/quotation-editor.d.ts +44 -0
- package/dist-client/pages/quotation-editor.js +315 -0
- package/dist-client/pages/quotation-editor.js.map +1 -0
- package/dist-client/pages/quotation-list.d.ts +36 -0
- package/dist-client/pages/quotation-list.js +113 -0
- package/dist-client/pages/quotation-list.js.map +1 -0
- package/dist-client/quotation-attach.d.ts +16 -0
- package/dist-client/quotation-attach.js +8 -0
- package/dist-client/quotation-attach.js.map +1 -0
- package/dist-client/quotation-words.d.ts +1 -0
- package/dist-client/quotation-words.js +13 -0
- package/dist-client/quotation-words.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +17 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-server/controllers/index.d.ts +0 -0
- package/dist-server/controllers/index.js +1 -0
- package/dist-server/controllers/index.js.map +1 -0
- package/dist-server/index.d.ts +4 -0
- package/dist-server/index.js +8 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/middlewares/index.d.ts +2 -0
- package/dist-server/middlewares/index.js +7 -0
- package/dist-server/middlewares/index.js.map +1 -0
- package/dist-server/migrations/index.d.ts +1 -0
- package/dist-server/migrations/index.js +12 -0
- package/dist-server/migrations/index.js.map +1 -0
- package/dist-server/routes.d.ts +0 -0
- package/dist-server/routes.js +24 -0
- package/dist-server/routes.js.map +1 -0
- package/dist-server/service/index.d.ts +16 -0
- package/dist-server/service/index.js +21 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/opportunity/index.d.ts +8 -0
- package/dist-server/service/opportunity/index.js +12 -0
- package/dist-server/service/opportunity/index.js.map +1 -0
- package/dist-server/service/opportunity/opportunity-event-query.d.ts +9 -0
- package/dist-server/service/opportunity/opportunity-event-query.js +55 -0
- package/dist-server/service/opportunity/opportunity-event-query.js.map +1 -0
- package/dist-server/service/opportunity/opportunity-event.d.ts +27 -0
- package/dist-server/service/opportunity/opportunity-event.js +115 -0
- package/dist-server/service/opportunity/opportunity-event.js.map +1 -0
- package/dist-server/service/opportunity/opportunity-mutation.d.ts +7 -0
- package/dist-server/service/opportunity/opportunity-mutation.js +64 -0
- package/dist-server/service/opportunity/opportunity-mutation.js.map +1 -0
- package/dist-server/service/opportunity/opportunity-query.d.ts +19 -0
- package/dist-server/service/opportunity/opportunity-query.js +144 -0
- package/dist-server/service/opportunity/opportunity-query.js.map +1 -0
- package/dist-server/service/opportunity/opportunity-rules.d.ts +22 -0
- package/dist-server/service/opportunity/opportunity-rules.js +59 -0
- package/dist-server/service/opportunity/opportunity-rules.js.map +1 -0
- package/dist-server/service/opportunity/opportunity-service.d.ts +19 -0
- package/dist-server/service/opportunity/opportunity-service.js +107 -0
- package/dist-server/service/opportunity/opportunity-service.js.map +1 -0
- package/dist-server/service/opportunity/opportunity-type.d.ts +23 -0
- package/dist-server/service/opportunity/opportunity-type.js +86 -0
- package/dist-server/service/opportunity/opportunity-type.js.map +1 -0
- package/dist-server/service/opportunity/opportunity.d.ts +35 -0
- package/dist-server/service/opportunity/opportunity.js +147 -0
- package/dist-server/service/opportunity/opportunity.js.map +1 -0
- package/dist-server/service/quotation/index.d.ts +10 -0
- package/dist-server/service/quotation/index.js +14 -0
- package/dist-server/service/quotation/index.js.map +1 -0
- package/dist-server/service/quotation/quotation-event-query.d.ts +9 -0
- package/dist-server/service/quotation/quotation-event-query.js +55 -0
- package/dist-server/service/quotation/quotation-event-query.js.map +1 -0
- package/dist-server/service/quotation/quotation-event.d.ts +22 -0
- package/dist-server/service/quotation/quotation-event.js +98 -0
- package/dist-server/service/quotation/quotation-event.js.map +1 -0
- package/dist-server/service/quotation/quotation-item-query.d.ts +8 -0
- package/dist-server/service/quotation/quotation-item-query.js +45 -0
- package/dist-server/service/quotation/quotation-item-query.js.map +1 -0
- package/dist-server/service/quotation/quotation-item.d.ts +18 -0
- package/dist-server/service/quotation/quotation-item.js +75 -0
- package/dist-server/service/quotation/quotation-item.js.map +1 -0
- package/dist-server/service/quotation/quotation-mutation.d.ts +11 -0
- package/dist-server/service/quotation/quotation-mutation.js +117 -0
- package/dist-server/service/quotation/quotation-mutation.js.map +1 -0
- package/dist-server/service/quotation/quotation-query.d.ts +17 -0
- package/dist-server/service/quotation/quotation-query.js +125 -0
- package/dist-server/service/quotation/quotation-query.js.map +1 -0
- package/dist-server/service/quotation/quotation-rules.d.ts +6 -0
- package/dist-server/service/quotation/quotation-rules.js +22 -0
- package/dist-server/service/quotation/quotation-rules.js.map +1 -0
- package/dist-server/service/quotation/quotation-service.d.ts +23 -0
- package/dist-server/service/quotation/quotation-service.js +115 -0
- package/dist-server/service/quotation/quotation-service.js.map +1 -0
- package/dist-server/service/quotation/quotation-type.d.ts +9 -0
- package/dist-server/service/quotation/quotation-type.js +32 -0
- package/dist-server/service/quotation/quotation-type.js.map +1 -0
- package/dist-server/service/quotation/quotation.d.ts +33 -0
- package/dist-server/service/quotation/quotation.js +109 -0
- package/dist-server/service/quotation/quotation.js.map +1 -0
- package/dist-server/service/sales-event.d.ts +15 -0
- package/dist-server/service/sales-event.js +12 -0
- package/dist-server/service/sales-event.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/helps/quotation/quotation.md +160 -0
- package/package.json +46 -4
- package/things-factory.config.js +13 -0
- package/translations/en.json +98 -0
- package/translations/es.json +98 -0
- package/translations/ja.json +98 -0
- package/translations/ko.json +98 -0
- package/translations/ms.json +98 -0
- package/translations/zh.json +98 -0
- package/README.md +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opportunity-rules.js","sourceRoot":"","sources":["../../../server/service/opportunity/opportunity-rules.ts"],"names":[],"mappings":";;;AAuCA,8BAIC;AAGD,4CAGC;AAjDD,+CAA+C;AAE/C,IAAY,gBAOX;AAPD,WAAY,gBAAgB;IAC1B,iCAAa,CAAA;IACb,yCAAqB,CAAA;IACrB,qCAAiB,CAAA;IACjB,+CAA2B,CAAA;IAC3B,+BAAW,CAAA;IACX,iCAAa,CAAA;AACf,CAAC,EAPW,gBAAgB,gCAAhB,gBAAgB,QAO3B;AACD,IAAA,+BAAgB,EAAC,gBAAgB,EAAE;IACjC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,0FAA0F;CACxG,CAAC,CAAA;AAEF,+FAA+F;AAClF,QAAA,WAAW,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAA;AAEpI;;;;GAIG;AACU,QAAA,iBAAiB,GAAqC;IACjE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,EAAE;IAC3B,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,EAAE;IAC/B,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,EAAE;IAC7B,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,EAAE;IAClC,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG;IAC3B,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;CAC3B,CAAA;AAEM,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,mBAAW,CAAC,QAAQ,CAAC,KAAyB,CAAC,CAAA;AAA3E,QAAA,MAAM,UAAqE;AAExF;;;;GAIG;AACH,SAAgB,SAAS,CAAC,IAAY,EAAE,EAAU;IAChD,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,gBAAgB,CAAC,GAAG;QAAE,OAAO,KAAK,CAAA;IAC9D,IAAI,IAAA,cAAM,EAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAA;IAC3B,OAAO,IAAA,cAAM,EAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,gBAAgB,CAAC,GAAG,IAAI,EAAE,KAAK,gBAAgB,CAAC,IAAI,CAAC,CAAA;AACtF,CAAC;AAED,4GAA4G;AAC5G,SAAgB,gBAAgB,CAAC,KAAuB,EAAE,KAAqB;IAC7E,IAAI,KAAK,KAAK,gBAAgB,CAAC,GAAG,IAAI,KAAK,KAAK,gBAAgB,CAAC,IAAI;QAAE,OAAO,yBAAiB,CAAC,KAAK,CAAC,CAAA;IACtG,OAAO,KAAK,IAAI,yBAAiB,CAAC,KAAK,CAAC,CAAA;AAC1C,CAAC;AAEM,MAAM,gBAAgB,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAK,KAAgB,IAAI,CAAC,IAAK,KAAgB,IAAI,GAAG,CAAA;AAApH,QAAA,gBAAgB,oBAAoG;AAE1H,MAAM,UAAU,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAAnG,QAAA,UAAU,cAAyF","sourcesContent":["import { registerEnumType } from 'type-graphql'\n\nexport enum OpportunityStage {\n LEAD = 'LEAD',\n PROPOSAL = 'PROPOSAL',\n QUOTED = 'QUOTED',\n NEGOTIATION = 'NEGOTIATION',\n WON = 'WON',\n LOST = 'LOST'\n}\nregisterEnumType(OpportunityStage, {\n name: 'OpportunityStage',\n description: 'where a sales opportunity stands — lead, proposal, quoted, negotiation, then won or lost'\n})\n\n/** The stages a person moves an opportunity through, in order; the two after them close it. */\nexport const OPEN_STAGES = [OpportunityStage.LEAD, OpportunityStage.PROPOSAL, OpportunityStage.QUOTED, OpportunityStage.NEGOTIATION]\n\n/*\n * The probability a stage starts an opportunity at, in percent. These are judgements, not measurements: nobody has\n * counted how often a proposal of ours is won. A person changes the probability of one opportunity whenever they know\n * better, and the history (OpportunityEvent) will one day show each stage's real rate beside these (ADR-0138 decision 5).\n */\nexport const STAGE_PROBABILITY: Record<OpportunityStage, number> = {\n [OpportunityStage.LEAD]: 10,\n [OpportunityStage.PROPOSAL]: 30,\n [OpportunityStage.QUOTED]: 50,\n [OpportunityStage.NEGOTIATION]: 70,\n [OpportunityStage.WON]: 100,\n [OpportunityStage.LOST]: 0\n}\n\nexport const isOpen = (stage: string) => OPEN_STAGES.includes(stage as OpportunityStage)\n\n/**\n * Whether an opportunity may go from one stage to another. A person moves an open one to any open stage, or closes it\n * as lost; a lost one may be opened again. Winning closes it for good — an application turns the win into its own\n * record (a contract) and only it closes an opportunity as won.\n */\nexport function stageMove(from: string, to: string): boolean {\n if (from === to || from === OpportunityStage.WON) return false\n if (isOpen(to)) return true\n return isOpen(from) && (to === OpportunityStage.WON || to === OpportunityStage.LOST)\n}\n\n/** The probability an opportunity keeps after a stage change: the one a person gave, or the stage's own. */\nexport function probabilityAfter(stage: OpportunityStage, given?: number | null): number {\n if (stage === OpportunityStage.WON || stage === OpportunityStage.LOST) return STAGE_PROBABILITY[stage]\n return given ?? STAGE_PROBABILITY[stage]\n}\n\nexport const validProbability = (value: unknown) => Number.isInteger(value) && (value as number) >= 0 && (value as number) <= 100\n\nexport const validMonth = (value: unknown) => typeof value === 'string' && /^\\d{4}-(0[1-9]|1[0-2])$/.test(value)\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Domain } from '@things-factory/shell';
|
|
2
|
+
import { EntityManager } from 'typeorm';
|
|
3
|
+
import { Opportunity } from './opportunity';
|
|
4
|
+
import { OpportunityStage } from './opportunity-rules';
|
|
5
|
+
import { NewOpportunity } from './opportunity-type';
|
|
6
|
+
export declare function opportunityInDomain(tx: EntityManager, domain: Domain, id: string): Promise<Opportunity>;
|
|
7
|
+
/**
|
|
8
|
+
* Create an opportunity, or change one a person may still change. An open one takes any open stage; a lost one is
|
|
9
|
+
* opened again by giving it an open stage. Closing is `closeOpportunity`'s.
|
|
10
|
+
*/
|
|
11
|
+
export declare function saveOpportunity(tx: EntityManager, domain: Domain, user: any, input: NewOpportunity, id?: string): Promise<Opportunity>;
|
|
12
|
+
/**
|
|
13
|
+
* Close an open opportunity — lost, with the reason, by a person; won by the application that turned it into its own
|
|
14
|
+
* record (Office's contract, ADR-0138 decision 8). The day is the domain's today unless one is given.
|
|
15
|
+
*/
|
|
16
|
+
export declare function closeOpportunity(tx: EntityManager, domain: Domain, user: any, id: string, outcome: OpportunityStage.WON | OpportunityStage.LOST, { closedOn, reason }?: {
|
|
17
|
+
closedOn?: string;
|
|
18
|
+
reason?: string;
|
|
19
|
+
}): Promise<Opportunity>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.opportunityInDomain = opportunityInDomain;
|
|
4
|
+
exports.saveOpportunity = saveOpportunity;
|
|
5
|
+
exports.closeOpportunity = closeOpportunity;
|
|
6
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
7
|
+
const biz_base_1 = require("@things-factory/biz-base");
|
|
8
|
+
const invoice_1 = require("@things-factory/invoice");
|
|
9
|
+
const shell_1 = require("@things-factory/shell");
|
|
10
|
+
const sales_event_1 = require("../sales-event");
|
|
11
|
+
const opportunity_1 = require("./opportunity");
|
|
12
|
+
const opportunity_event_1 = require("./opportunity-event");
|
|
13
|
+
const opportunity_rules_1 = require("./opportunity-rules");
|
|
14
|
+
async function opportunityInDomain(tx, domain, id) {
|
|
15
|
+
const opportunity = await tx.getRepository(opportunity_1.Opportunity).findOne({ where: { id, domain: { id: domain.id } } });
|
|
16
|
+
if (!opportunity)
|
|
17
|
+
throw new shell_1.Refusal('opportunity-not-found', {}, 'Opportunity not found');
|
|
18
|
+
return opportunity;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Create an opportunity, or change one a person may still change. An open one takes any open stage; a lost one is
|
|
22
|
+
* opened again by giving it an open stage. Closing is `closeOpportunity`'s.
|
|
23
|
+
*/
|
|
24
|
+
async function saveOpportunity(tx, domain, user, input, id) {
|
|
25
|
+
const old = id ? await opportunityInDomain(tx, domain, id) : undefined;
|
|
26
|
+
const stage = input.stage ?? old?.stage ?? opportunity_rules_1.OpportunityStage.LEAD;
|
|
27
|
+
/* A closed one changes only by being opened again, and only a lost one may be. */
|
|
28
|
+
if (old && !(0, opportunity_rules_1.isOpen)(old.stage) && !((0, opportunity_rules_1.isOpen)(stage) && (0, opportunity_rules_1.stageMove)(old.stage, stage)))
|
|
29
|
+
throw new shell_1.Refusal('opportunity-closed', {}, 'A closed opportunity is not changed');
|
|
30
|
+
if (!(0, opportunity_rules_1.isOpen)(stage))
|
|
31
|
+
throw new shell_1.Refusal('opportunity-stage-open-required', {}, 'Give an open stage; won and lost are closings');
|
|
32
|
+
const name = input.name?.trim();
|
|
33
|
+
if (!name)
|
|
34
|
+
throw new shell_1.Refusal('opportunity-name-required', {}, 'Name the opportunity');
|
|
35
|
+
if (!Number.isFinite(input.amount) || input.amount < 0)
|
|
36
|
+
throw new shell_1.Refusal('opportunity-amount-invalid', {}, 'The expected amount is zero or more');
|
|
37
|
+
const currency = (input.currency?.trim() || 'KRW').toUpperCase();
|
|
38
|
+
(0, invoice_1.currencyDigits)(currency);
|
|
39
|
+
if (!(0, opportunity_rules_1.validMonth)(input.expectedCloseMonth))
|
|
40
|
+
throw new shell_1.Refusal('opportunity-close-month-invalid', {}, 'Give the expected month as YYYY-MM');
|
|
41
|
+
if (input.probability !== undefined && input.probability !== null && !(0, opportunity_rules_1.validProbability)(input.probability))
|
|
42
|
+
throw new shell_1.Refusal('opportunity-probability-invalid', {}, 'The probability is a whole number from 0 to 100');
|
|
43
|
+
const counterparties = tx.getRepository(biz_base_1.Counterparty);
|
|
44
|
+
const counterparty = input.counterpartyId ? await counterparties.findOne({ where: { id: input.counterpartyId, domain: { id: domain.id } } }) : null;
|
|
45
|
+
if (!counterparty)
|
|
46
|
+
throw new shell_1.Refusal('opportunity-counterparty-required', {}, 'Choose the counterparty of this domain');
|
|
47
|
+
const endCustomer = input.endCustomerId ? await counterparties.findOne({ where: { id: input.endCustomerId, domain: { id: domain.id } } }) : null;
|
|
48
|
+
if (input.endCustomerId && !endCustomer)
|
|
49
|
+
throw new shell_1.Refusal('opportunity-end-customer-invalid', {}, 'Choose the end customer among the counterparties of this domain');
|
|
50
|
+
const ownerId = input.ownerId || old?.ownerId || user.id;
|
|
51
|
+
/* The people work here may be given to — auth-base's one answer, the same a license's recipient gets. */
|
|
52
|
+
if (ownerId !== user.id && ownerId !== old?.ownerId && !(await (0, auth_base_1.getDomainAssignees)(domain, tx)).some(one => one.id === ownerId))
|
|
53
|
+
throw new shell_1.Refusal('opportunity-owner-invalid', {}, 'Put it in the charge of a member of this domain');
|
|
54
|
+
const staged = !!old && old.stage !== stage;
|
|
55
|
+
/* The probability follows the stage unless the person gave one; with the stage unchanged it stays as it was. */
|
|
56
|
+
const probability = !old || staged ? (0, opportunity_rules_1.probabilityAfter)(stage, input.probability) : input.probability ?? old.probability;
|
|
57
|
+
const repository = tx.getRepository(opportunity_1.Opportunity);
|
|
58
|
+
const row = await repository.save(repository.create({
|
|
59
|
+
...(old ? { id: old.id, creator: old.creatorId ? { id: old.creatorId } : undefined } : { creator: user }),
|
|
60
|
+
domain,
|
|
61
|
+
name,
|
|
62
|
+
counterparty,
|
|
63
|
+
endCustomer: endCustomer ?? null,
|
|
64
|
+
amount: input.amount,
|
|
65
|
+
currency,
|
|
66
|
+
expectedCloseMonth: input.expectedCloseMonth,
|
|
67
|
+
stage,
|
|
68
|
+
probability,
|
|
69
|
+
owner: { id: ownerId },
|
|
70
|
+
/* A lost opportunity opened again is no longer closed. */
|
|
71
|
+
closedOn: null,
|
|
72
|
+
lostReason: null,
|
|
73
|
+
description: input.description?.trim() || null,
|
|
74
|
+
updater: user
|
|
75
|
+
}));
|
|
76
|
+
const saved = await opportunityInDomain(tx, domain, row.id);
|
|
77
|
+
await recordOpportunityEvent(tx, domain, user, saved, !old ? 'CREATED' : staged ? 'STAGED' : 'UPDATED', staged ? old.stage : undefined);
|
|
78
|
+
return saved;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Close an open opportunity — lost, with the reason, by a person; won by the application that turned it into its own
|
|
82
|
+
* record (Office's contract, ADR-0138 decision 8). The day is the domain's today unless one is given.
|
|
83
|
+
*/
|
|
84
|
+
async function closeOpportunity(tx, domain, user, id, outcome, { closedOn, reason } = {}) {
|
|
85
|
+
const opportunity = await opportunityInDomain(tx, domain, id);
|
|
86
|
+
if (!(0, opportunity_rules_1.stageMove)(opportunity.stage, outcome))
|
|
87
|
+
throw new shell_1.Refusal('opportunity-stage-move-invalid', {}, 'The opportunity cannot move to that stage');
|
|
88
|
+
if (outcome === opportunity_rules_1.OpportunityStage.LOST && !reason?.trim())
|
|
89
|
+
throw new shell_1.Refusal('opportunity-reason-required', {}, 'Say why it was lost');
|
|
90
|
+
const day = closedOn || (0, invoice_1.calendarDay)(domain.timezone);
|
|
91
|
+
if (!(0, invoice_1.validDay)(day))
|
|
92
|
+
throw new shell_1.Refusal('opportunity-closed-on-invalid', {}, 'Give the closing day as YYYY-MM-DD');
|
|
93
|
+
const from = opportunity.stage;
|
|
94
|
+
await tx.getRepository(opportunity_1.Opportunity).update({ id: opportunity.id }, { stage: outcome, probability: (0, opportunity_rules_1.probabilityAfter)(outcome), closedOn: day, lostReason: outcome === opportunity_rules_1.OpportunityStage.LOST ? reason.trim() : null, updater: user });
|
|
95
|
+
const closed = await opportunityInDomain(tx, domain, id);
|
|
96
|
+
await recordOpportunityEvent(tx, domain, user, closed, outcome, from, outcome === opportunity_rules_1.OpportunityStage.LOST ? closed.lostReason : undefined);
|
|
97
|
+
return closed;
|
|
98
|
+
}
|
|
99
|
+
function recordOpportunityEvent(tx, domain, user, opportunity, action, fromStage, reason) {
|
|
100
|
+
return (0, sales_event_1.recordSalesEvent)(tx, opportunity_event_1.OpportunityEvent, { opportunity, fromStage: fromStage ?? null, stage: opportunity.stage, probability: opportunity.probability }, { domain, user, action, reason, snapshot: snapshotOf(opportunity) });
|
|
101
|
+
}
|
|
102
|
+
/** The opportunity as it stood. */
|
|
103
|
+
function snapshotOf(opportunity) {
|
|
104
|
+
const keys = ['id', 'name', 'counterpartyId', 'endCustomerId', 'amount', 'currency', 'expectedCloseMonth', 'stage', 'probability', 'ownerId', 'closedOn', 'lostReason', 'description'];
|
|
105
|
+
return Object.fromEntries(keys.map(key => [key, opportunity[key] ?? null]));
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=opportunity-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opportunity-service.js","sourceRoot":"","sources":["../../../server/service/opportunity/opportunity-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getDomainAssignees } from '@things-factory/auth-base'\nimport { Counterparty } from '@things-factory/biz-base'\nimport { calendarDay, currencyDigits, validDay } from '@things-factory/invoice'\nimport { Domain, Refusal } from '@things-factory/shell'\nimport { EntityManager } from 'typeorm'\n\nimport { recordSalesEvent } from '../sales-event'\nimport { Opportunity } from './opportunity'\nimport { OpportunityEvent } from './opportunity-event'\nimport { isOpen, OpportunityStage, probabilityAfter, stageMove, validMonth, validProbability } from './opportunity-rules'\nimport { NewOpportunity } from './opportunity-type'\n\nexport async function opportunityInDomain(tx: EntityManager, domain: Domain, id: string) {\n const opportunity = await tx.getRepository(Opportunity).findOne({ where: { id, domain: { id: domain.id } } })\n if (!opportunity) throw new Refusal('opportunity-not-found', {}, 'Opportunity not found')\n return opportunity\n}\n\n/**\n * Create an opportunity, or change one a person may still change. An open one takes any open stage; a lost one is\n * opened again by giving it an open stage. Closing is `closeOpportunity`'s.\n */\nexport async function saveOpportunity(tx: EntityManager, domain: Domain, user: any, input: NewOpportunity, id?: string) {\n const old = id ? await opportunityInDomain(tx, domain, id) : undefined\n const stage = input.stage ?? old?.stage ?? OpportunityStage.LEAD\n /* A closed one changes only by being opened again, and only a lost one may be. */\n if (old && !isOpen(old.stage) && !(isOpen(stage) && stageMove(old.stage, stage))) throw new Refusal('opportunity-closed', {}, 'A closed opportunity is not changed')\n if (!isOpen(stage)) throw new Refusal('opportunity-stage-open-required', {}, 'Give an open stage; won and lost are closings')\n\n const name = input.name?.trim()\n if (!name) throw new Refusal('opportunity-name-required', {}, 'Name the opportunity')\n if (!Number.isFinite(input.amount) || input.amount < 0) throw new Refusal('opportunity-amount-invalid', {}, 'The expected amount is zero or more')\n const currency = (input.currency?.trim() || 'KRW').toUpperCase()\n currencyDigits(currency)\n if (!validMonth(input.expectedCloseMonth)) throw new Refusal('opportunity-close-month-invalid', {}, 'Give the expected month as YYYY-MM')\n if (input.probability !== undefined && input.probability !== null && !validProbability(input.probability))\n throw new Refusal('opportunity-probability-invalid', {}, 'The probability is a whole number from 0 to 100')\n\n const counterparties = tx.getRepository(Counterparty)\n const counterparty = input.counterpartyId ? await counterparties.findOne({ where: { id: input.counterpartyId, domain: { id: domain.id } } }) : null\n if (!counterparty) throw new Refusal('opportunity-counterparty-required', {}, 'Choose the counterparty of this domain')\n const endCustomer = input.endCustomerId ? await counterparties.findOne({ where: { id: input.endCustomerId, domain: { id: domain.id } } }) : null\n if (input.endCustomerId && !endCustomer) throw new Refusal('opportunity-end-customer-invalid', {}, 'Choose the end customer among the counterparties of this domain')\n\n const ownerId = input.ownerId || old?.ownerId || user.id\n /* The people work here may be given to — auth-base's one answer, the same a license's recipient gets. */\n if (ownerId !== user.id && ownerId !== old?.ownerId && !(await getDomainAssignees(domain, tx)).some(one => one.id === ownerId))\n throw new Refusal('opportunity-owner-invalid', {}, 'Put it in the charge of a member of this domain')\n\n const staged = !!old && old.stage !== stage\n /* The probability follows the stage unless the person gave one; with the stage unchanged it stays as it was. */\n const probability = !old || staged ? probabilityAfter(stage, input.probability) : input.probability ?? old.probability\n\n const repository = tx.getRepository(Opportunity)\n const row = await repository.save(\n repository.create({\n ...(old ? { id: old.id, creator: old.creatorId ? ({ id: old.creatorId } as any) : undefined } : { creator: user }),\n domain,\n name,\n counterparty,\n endCustomer: endCustomer ?? null,\n amount: input.amount,\n currency,\n expectedCloseMonth: input.expectedCloseMonth,\n stage,\n probability,\n owner: { id: ownerId } as any,\n /* A lost opportunity opened again is no longer closed. */\n closedOn: null,\n lostReason: null,\n description: input.description?.trim() || null,\n updater: user\n })\n )\n const saved = await opportunityInDomain(tx, domain, row.id)\n await recordOpportunityEvent(tx, domain, user, saved, !old ? 'CREATED' : staged ? 'STAGED' : 'UPDATED', staged ? old.stage : undefined)\n return saved\n}\n\n/**\n * Close an open opportunity — lost, with the reason, by a person; won by the application that turned it into its own\n * record (Office's contract, ADR-0138 decision 8). The day is the domain's today unless one is given.\n */\nexport async function closeOpportunity(\n tx: EntityManager,\n domain: Domain,\n user: any,\n id: string,\n outcome: OpportunityStage.WON | OpportunityStage.LOST,\n { closedOn, reason }: { closedOn?: string; reason?: string } = {}\n) {\n const opportunity = await opportunityInDomain(tx, domain, id)\n if (!stageMove(opportunity.stage, outcome)) throw new Refusal('opportunity-stage-move-invalid', {}, 'The opportunity cannot move to that stage')\n if (outcome === OpportunityStage.LOST && !reason?.trim()) throw new Refusal('opportunity-reason-required', {}, 'Say why it was lost')\n const day = closedOn || calendarDay(domain.timezone)\n if (!validDay(day)) throw new Refusal('opportunity-closed-on-invalid', {}, 'Give the closing day as YYYY-MM-DD')\n\n const from = opportunity.stage\n await tx.getRepository(Opportunity).update(\n { id: opportunity.id },\n { stage: outcome, probability: probabilityAfter(outcome), closedOn: day, lostReason: outcome === OpportunityStage.LOST ? reason!.trim() : null, updater: user }\n )\n const closed = await opportunityInDomain(tx, domain, id)\n await recordOpportunityEvent(tx, domain, user, closed, outcome, from, outcome === OpportunityStage.LOST ? closed.lostReason : undefined)\n return closed\n}\n\nfunction recordOpportunityEvent(tx: EntityManager, domain: Domain, user: any, opportunity: Opportunity, action: string, fromStage?: OpportunityStage, reason?: string) {\n return recordSalesEvent(\n tx,\n OpportunityEvent,\n { opportunity, fromStage: fromStage ?? null, stage: opportunity.stage, probability: opportunity.probability },\n { domain, user, action, reason, snapshot: snapshotOf(opportunity) }\n )\n}\n\n/** The opportunity as it stood. */\nfunction snapshotOf(opportunity: Opportunity) {\n const keys = ['id', 'name', 'counterpartyId', 'endCustomerId', 'amount', 'currency', 'expectedCloseMonth', 'stage', 'probability', 'ownerId', 'closedOn', 'lostReason', 'description']\n return Object.fromEntries(keys.map(key => [key, opportunity[key] ?? null]))\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Opportunity } from './opportunity';
|
|
2
|
+
import { OpportunityStage } from './opportunity-rules';
|
|
3
|
+
export declare class NewOpportunity {
|
|
4
|
+
name: string;
|
|
5
|
+
counterpartyId: string;
|
|
6
|
+
endCustomerId?: string;
|
|
7
|
+
amount: number;
|
|
8
|
+
currency?: string;
|
|
9
|
+
expectedCloseMonth: string;
|
|
10
|
+
stage?: OpportunityStage;
|
|
11
|
+
probability?: number;
|
|
12
|
+
ownerId?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class OpportunityList {
|
|
16
|
+
items: Opportunity[];
|
|
17
|
+
total: number;
|
|
18
|
+
}
|
|
19
|
+
export declare class OpportunityStageDefault {
|
|
20
|
+
stage: OpportunityStage;
|
|
21
|
+
probability: number;
|
|
22
|
+
open: boolean;
|
|
23
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpportunityStageDefault = exports.OpportunityList = exports.NewOpportunity = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const opportunity_1 = require("./opportunity");
|
|
7
|
+
const opportunity_rules_1 = require("./opportunity-rules");
|
|
8
|
+
let NewOpportunity = class NewOpportunity {
|
|
9
|
+
};
|
|
10
|
+
exports.NewOpportunity = NewOpportunity;
|
|
11
|
+
tslib_1.__decorate([
|
|
12
|
+
(0, type_graphql_1.Field)({ description: 'What the opportunity is called' }),
|
|
13
|
+
tslib_1.__metadata("design:type", String)
|
|
14
|
+
], NewOpportunity.prototype, "name", void 0);
|
|
15
|
+
tslib_1.__decorate([
|
|
16
|
+
(0, type_graphql_1.Field)({ description: 'Id of the counterparty the domain would contract with' }),
|
|
17
|
+
tslib_1.__metadata("design:type", String)
|
|
18
|
+
], NewOpportunity.prototype, "counterpartyId", void 0);
|
|
19
|
+
tslib_1.__decorate([
|
|
20
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Id of the end customer, when the work comes through another party' }),
|
|
21
|
+
tslib_1.__metadata("design:type", String)
|
|
22
|
+
], NewOpportunity.prototype, "endCustomerId", void 0);
|
|
23
|
+
tslib_1.__decorate([
|
|
24
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Float, { description: 'Expected amount before tax' }),
|
|
25
|
+
tslib_1.__metadata("design:type", Number)
|
|
26
|
+
], NewOpportunity.prototype, "amount", void 0);
|
|
27
|
+
tslib_1.__decorate([
|
|
28
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'ISO 4217 currency code, KRW when empty' }),
|
|
29
|
+
tslib_1.__metadata("design:type", String)
|
|
30
|
+
], NewOpportunity.prototype, "currency", void 0);
|
|
31
|
+
tslib_1.__decorate([
|
|
32
|
+
(0, type_graphql_1.Field)({ description: 'Month the domain expects to win it, YYYY-MM' }),
|
|
33
|
+
tslib_1.__metadata("design:type", String)
|
|
34
|
+
], NewOpportunity.prototype, "expectedCloseMonth", void 0);
|
|
35
|
+
tslib_1.__decorate([
|
|
36
|
+
(0, type_graphql_1.Field)(type => opportunity_rules_1.OpportunityStage, { nullable: true, description: 'An open stage; a new opportunity starts as a lead when empty' }),
|
|
37
|
+
tslib_1.__metadata("design:type", String)
|
|
38
|
+
], NewOpportunity.prototype, "stage", void 0);
|
|
39
|
+
tslib_1.__decorate([
|
|
40
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: 'Chance of winning in percent; the stage gives it when empty' }),
|
|
41
|
+
tslib_1.__metadata("design:type", Number)
|
|
42
|
+
], NewOpportunity.prototype, "probability", void 0);
|
|
43
|
+
tslib_1.__decorate([
|
|
44
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Id of the person in charge; the caller when empty' }),
|
|
45
|
+
tslib_1.__metadata("design:type", String)
|
|
46
|
+
], NewOpportunity.prototype, "ownerId", void 0);
|
|
47
|
+
tslib_1.__decorate([
|
|
48
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Notes' }),
|
|
49
|
+
tslib_1.__metadata("design:type", String)
|
|
50
|
+
], NewOpportunity.prototype, "description", void 0);
|
|
51
|
+
exports.NewOpportunity = NewOpportunity = tslib_1.__decorate([
|
|
52
|
+
(0, type_graphql_1.InputType)({ description: 'An opportunity to create, or what a person changes on one' })
|
|
53
|
+
], NewOpportunity);
|
|
54
|
+
let OpportunityList = class OpportunityList {
|
|
55
|
+
};
|
|
56
|
+
exports.OpportunityList = OpportunityList;
|
|
57
|
+
tslib_1.__decorate([
|
|
58
|
+
(0, type_graphql_1.Field)(type => [opportunity_1.Opportunity], { description: 'Opportunities on the page' }),
|
|
59
|
+
tslib_1.__metadata("design:type", Array)
|
|
60
|
+
], OpportunityList.prototype, "items", void 0);
|
|
61
|
+
tslib_1.__decorate([
|
|
62
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Number of opportunities matching the list parameters' }),
|
|
63
|
+
tslib_1.__metadata("design:type", Number)
|
|
64
|
+
], OpportunityList.prototype, "total", void 0);
|
|
65
|
+
exports.OpportunityList = OpportunityList = tslib_1.__decorate([
|
|
66
|
+
(0, type_graphql_1.ObjectType)({ description: 'A page of opportunities' })
|
|
67
|
+
], OpportunityList);
|
|
68
|
+
let OpportunityStageDefault = class OpportunityStageDefault {
|
|
69
|
+
};
|
|
70
|
+
exports.OpportunityStageDefault = OpportunityStageDefault;
|
|
71
|
+
tslib_1.__decorate([
|
|
72
|
+
(0, type_graphql_1.Field)(type => opportunity_rules_1.OpportunityStage, { description: 'The stage' }),
|
|
73
|
+
tslib_1.__metadata("design:type", String)
|
|
74
|
+
], OpportunityStageDefault.prototype, "stage", void 0);
|
|
75
|
+
tslib_1.__decorate([
|
|
76
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'The probability the stage gives, in percent — a judgement, not a measurement' }),
|
|
77
|
+
tslib_1.__metadata("design:type", Number)
|
|
78
|
+
], OpportunityStageDefault.prototype, "probability", void 0);
|
|
79
|
+
tslib_1.__decorate([
|
|
80
|
+
(0, type_graphql_1.Field)({ description: 'Whether a person moves an opportunity through this stage; won and lost close it' }),
|
|
81
|
+
tslib_1.__metadata("design:type", Boolean)
|
|
82
|
+
], OpportunityStageDefault.prototype, "open", void 0);
|
|
83
|
+
exports.OpportunityStageDefault = OpportunityStageDefault = tslib_1.__decorate([
|
|
84
|
+
(0, type_graphql_1.ObjectType)({ description: 'A stage and the probability it starts an opportunity at' })
|
|
85
|
+
], OpportunityStageDefault);
|
|
86
|
+
//# sourceMappingURL=opportunity-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opportunity-type.js","sourceRoot":"","sources":["../../../server/service/opportunity/opportunity-type.ts"],"names":[],"mappings":";;;;AAAA,+CAAuE;AAEvE,+CAA2C;AAC3C,2DAAsD;AAG/C,IAAM,cAAc,GAApB,MAAM,cAAc;CAW1B,CAAA;AAXY,wCAAc;AACiC;IAAzD,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,gCAAgC,EAAE,CAAC;;4CAAa;AACW;IAAhF,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,uDAAuD,EAAE,CAAC;;sDAAuB;AACM;IAA5G,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mEAAmE,EAAE,CAAC;;qDAAuB;AAC9D;IAApE,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAK,EAAE,EAAE,WAAW,EAAE,4BAA4B,EAAE,CAAC;;8CAAe;AACD;IAAjF,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC;;gDAAkB;AAC5B;IAAtE,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC;;0DAA2B;AACiC;IAAjI,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oCAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC;;6CAAyB;AACtC;IAAnH,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6DAA6D,EAAE,CAAC;;mDAAqB;AAC3C;IAA5F,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mDAAmD,EAAE,CAAC;;+CAAiB;AAC5D;IAAhD,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;;mDAAqB;yBAV1D,cAAc;IAD1B,IAAA,wBAAS,EAAC,EAAE,WAAW,EAAE,2DAA2D,EAAE,CAAC;GAC3E,cAAc,CAW1B;AAGM,IAAM,eAAe,GAArB,MAAM,eAAe;CAG3B,CAAA;AAHY,0CAAe;AACkD;IAA3E,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,yBAAW,CAAC,EAAE,EAAE,WAAW,EAAE,2BAA2B,EAAE,CAAC;;8CAAqB;AACH;IAA5F,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,WAAW,EAAE,sDAAsD,EAAE,CAAC;;8CAAc;0BAF/F,eAAe;IAD3B,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,yBAAyB,EAAE,CAAC;GAC1C,eAAe,CAG3B;AAGM,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;CAInC,CAAA;AAJY,0DAAuB;AAC6B;IAA9D,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oCAAgB,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;;sDAAwB;AAC+B;IAApH,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,WAAW,EAAE,8EAA8E,EAAE,CAAC;;4DAAoB;AAC7B;IAA1G,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,iFAAiF,EAAE,CAAC;;qDAAc;kCAH7G,uBAAuB;IADnC,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,yDAAyD,EAAE,CAAC;GAC1E,uBAAuB,CAInC","sourcesContent":["import { Field, Float, InputType, Int, ObjectType } from 'type-graphql'\n\nimport { Opportunity } from './opportunity'\nimport { OpportunityStage } from './opportunity-rules'\n\n@InputType({ description: 'An opportunity to create, or what a person changes on one' })\nexport class NewOpportunity {\n @Field({ description: 'What the opportunity is called' }) name: string\n @Field({ description: 'Id of the counterparty the domain would contract with' }) counterpartyId: string\n @Field({ nullable: true, description: 'Id of the end customer, when the work comes through another party' }) endCustomerId?: string\n @Field(type => Float, { description: 'Expected amount before tax' }) amount: number\n @Field({ nullable: true, description: 'ISO 4217 currency code, KRW when empty' }) currency?: string\n @Field({ description: 'Month the domain expects to win it, YYYY-MM' }) expectedCloseMonth: string\n @Field(type => OpportunityStage, { nullable: true, description: 'An open stage; a new opportunity starts as a lead when empty' }) stage?: OpportunityStage\n @Field(type => Int, { nullable: true, description: 'Chance of winning in percent; the stage gives it when empty' }) probability?: number\n @Field({ nullable: true, description: 'Id of the person in charge; the caller when empty' }) ownerId?: string\n @Field({ nullable: true, description: 'Notes' }) description?: string\n}\n\n@ObjectType({ description: 'A page of opportunities' })\nexport class OpportunityList {\n @Field(type => [Opportunity], { description: 'Opportunities on the page' }) items: Opportunity[]\n @Field(type => Int, { description: 'Number of opportunities matching the list parameters' }) total: number\n}\n\n@ObjectType({ description: 'A stage and the probability it starts an opportunity at' })\nexport class OpportunityStageDefault {\n @Field(type => OpportunityStage, { description: 'The stage' }) stage: OpportunityStage\n @Field(type => Int, { description: 'The probability the stage gives, in percent — a judgement, not a measurement' }) probability: number\n @Field({ description: 'Whether a person moves an opportunity through this stage; won and lost close it' }) open: boolean\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { User } from '@things-factory/auth-base';
|
|
2
|
+
import { Counterparty } from '@things-factory/biz-base';
|
|
3
|
+
import { Domain } from '@things-factory/shell';
|
|
4
|
+
import { OpportunityStage } from './opportunity-rules';
|
|
5
|
+
/**
|
|
6
|
+
* A sales opportunity — work the domain hopes to win, before there is a contract: with whom, for how much, by when,
|
|
7
|
+
* and how likely. A person moves it through the stages; it closes as won or lost (ADR-0138 decision 5).
|
|
8
|
+
*/
|
|
9
|
+
export declare class Opportunity {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
domain?: Domain;
|
|
12
|
+
domainId?: string;
|
|
13
|
+
name: string;
|
|
14
|
+
counterparty: Counterparty;
|
|
15
|
+
counterpartyId: string;
|
|
16
|
+
endCustomer?: Counterparty;
|
|
17
|
+
endCustomerId?: string;
|
|
18
|
+
amount: number;
|
|
19
|
+
currency: string;
|
|
20
|
+
expectedCloseMonth: string;
|
|
21
|
+
stage: OpportunityStage;
|
|
22
|
+
probability: number;
|
|
23
|
+
owner?: User;
|
|
24
|
+
ownerId?: string;
|
|
25
|
+
closedOn?: string;
|
|
26
|
+
lostReason?: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
createdAt?: Date;
|
|
29
|
+
updatedAt?: Date;
|
|
30
|
+
deletedAt?: Date;
|
|
31
|
+
creator?: User;
|
|
32
|
+
creatorId?: string;
|
|
33
|
+
updater?: User;
|
|
34
|
+
updaterId?: string;
|
|
35
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Opportunity = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
6
|
+
const biz_base_1 = require("@things-factory/biz-base");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const type_graphql_1 = require("type-graphql");
|
|
9
|
+
const typeorm_1 = require("typeorm");
|
|
10
|
+
const opportunity_rules_1 = require("./opportunity-rules");
|
|
11
|
+
/**
|
|
12
|
+
* A sales opportunity — work the domain hopes to win, before there is a contract: with whom, for how much, by when,
|
|
13
|
+
* and how likely. A person moves it through the stages; it closes as won or lost (ADR-0138 decision 5).
|
|
14
|
+
*/
|
|
15
|
+
let Opportunity = class Opportunity {
|
|
16
|
+
};
|
|
17
|
+
exports.Opportunity = Opportunity;
|
|
18
|
+
tslib_1.__decorate([
|
|
19
|
+
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
|
20
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.ID),
|
|
21
|
+
tslib_1.__metadata("design:type", String)
|
|
22
|
+
], Opportunity.prototype, "id", void 0);
|
|
23
|
+
tslib_1.__decorate([
|
|
24
|
+
(0, typeorm_1.ManyToOne)(type => shell_1.Domain),
|
|
25
|
+
(0, type_graphql_1.Field)(type => shell_1.Domain, { nullable: true }),
|
|
26
|
+
tslib_1.__metadata("design:type", shell_1.Domain)
|
|
27
|
+
], Opportunity.prototype, "domain", void 0);
|
|
28
|
+
tslib_1.__decorate([
|
|
29
|
+
(0, typeorm_1.RelationId)((opportunity) => opportunity.domain),
|
|
30
|
+
tslib_1.__metadata("design:type", String)
|
|
31
|
+
], Opportunity.prototype, "domainId", void 0);
|
|
32
|
+
tslib_1.__decorate([
|
|
33
|
+
(0, typeorm_1.Column)(),
|
|
34
|
+
(0, type_graphql_1.Field)({ description: 'What the opportunity is called' }),
|
|
35
|
+
tslib_1.__metadata("design:type", String)
|
|
36
|
+
], Opportunity.prototype, "name", void 0);
|
|
37
|
+
tslib_1.__decorate([
|
|
38
|
+
(0, typeorm_1.ManyToOne)(type => biz_base_1.Counterparty, { nullable: false }),
|
|
39
|
+
(0, type_graphql_1.Field)(type => biz_base_1.Counterparty, { nullable: true, description: 'The party the domain would contract with' }),
|
|
40
|
+
tslib_1.__metadata("design:type", biz_base_1.Counterparty)
|
|
41
|
+
], Opportunity.prototype, "counterparty", void 0);
|
|
42
|
+
tslib_1.__decorate([
|
|
43
|
+
(0, typeorm_1.RelationId)((opportunity) => opportunity.counterparty),
|
|
44
|
+
(0, type_graphql_1.Field)({ description: 'Id of the party the domain would contract with' }),
|
|
45
|
+
tslib_1.__metadata("design:type", String)
|
|
46
|
+
], Opportunity.prototype, "counterpartyId", void 0);
|
|
47
|
+
tslib_1.__decorate([
|
|
48
|
+
(0, typeorm_1.ManyToOne)(type => biz_base_1.Counterparty, { nullable: true }),
|
|
49
|
+
(0, type_graphql_1.Field)(type => biz_base_1.Counterparty, { nullable: true, description: 'The end customer, when the work comes through another party' }),
|
|
50
|
+
tslib_1.__metadata("design:type", biz_base_1.Counterparty)
|
|
51
|
+
], Opportunity.prototype, "endCustomer", void 0);
|
|
52
|
+
tslib_1.__decorate([
|
|
53
|
+
(0, typeorm_1.RelationId)((opportunity) => opportunity.endCustomer),
|
|
54
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Id of the end customer' }),
|
|
55
|
+
tslib_1.__metadata("design:type", String)
|
|
56
|
+
], Opportunity.prototype, "endCustomerId", void 0);
|
|
57
|
+
tslib_1.__decorate([
|
|
58
|
+
(0, typeorm_1.Column)({ ...(0, shell_1.moneyColumn)(), default: 0 }),
|
|
59
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Float, { description: 'Expected amount before tax' }),
|
|
60
|
+
tslib_1.__metadata("design:type", Number)
|
|
61
|
+
], Opportunity.prototype, "amount", void 0);
|
|
62
|
+
tslib_1.__decorate([
|
|
63
|
+
(0, typeorm_1.Column)({ default: 'KRW' }),
|
|
64
|
+
(0, type_graphql_1.Field)({ description: 'ISO 4217 currency code of the amount' }),
|
|
65
|
+
tslib_1.__metadata("design:type", String)
|
|
66
|
+
], Opportunity.prototype, "currency", void 0);
|
|
67
|
+
tslib_1.__decorate([
|
|
68
|
+
(0, typeorm_1.Column)(),
|
|
69
|
+
(0, type_graphql_1.Field)({ description: 'Month the domain expects to win it, YYYY-MM' }),
|
|
70
|
+
tslib_1.__metadata("design:type", String)
|
|
71
|
+
], Opportunity.prototype, "expectedCloseMonth", void 0);
|
|
72
|
+
tslib_1.__decorate([
|
|
73
|
+
(0, typeorm_1.Column)({ default: opportunity_rules_1.OpportunityStage.LEAD }),
|
|
74
|
+
(0, type_graphql_1.Field)(type => opportunity_rules_1.OpportunityStage, { description: 'Lead, proposal, quoted, negotiation, won or lost' }),
|
|
75
|
+
tslib_1.__metadata("design:type", String)
|
|
76
|
+
], Opportunity.prototype, "stage", void 0);
|
|
77
|
+
tslib_1.__decorate([
|
|
78
|
+
(0, typeorm_1.Column)({ type: 'int' }),
|
|
79
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Chance of winning in percent, 0 to 100 — the stage gives it, a person may change it' }),
|
|
80
|
+
tslib_1.__metadata("design:type", Number)
|
|
81
|
+
], Opportunity.prototype, "probability", void 0);
|
|
82
|
+
tslib_1.__decorate([
|
|
83
|
+
(0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
|
|
84
|
+
(0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
|
|
85
|
+
tslib_1.__metadata("design:type", auth_base_1.User)
|
|
86
|
+
], Opportunity.prototype, "owner", void 0);
|
|
87
|
+
tslib_1.__decorate([
|
|
88
|
+
(0, typeorm_1.RelationId)((opportunity) => opportunity.owner),
|
|
89
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Id of the person in charge' }),
|
|
90
|
+
tslib_1.__metadata("design:type", String)
|
|
91
|
+
], Opportunity.prototype, "ownerId", void 0);
|
|
92
|
+
tslib_1.__decorate([
|
|
93
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
94
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Day it was closed as won or lost, YYYY-MM-DD' }),
|
|
95
|
+
tslib_1.__metadata("design:type", String)
|
|
96
|
+
], Opportunity.prototype, "closedOn", void 0);
|
|
97
|
+
tslib_1.__decorate([
|
|
98
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
99
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Why it was lost' }),
|
|
100
|
+
tslib_1.__metadata("design:type", String)
|
|
101
|
+
], Opportunity.prototype, "lostReason", void 0);
|
|
102
|
+
tslib_1.__decorate([
|
|
103
|
+
(0, typeorm_1.Column)({ type: 'text', nullable: true }),
|
|
104
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Notes' }),
|
|
105
|
+
tslib_1.__metadata("design:type", String)
|
|
106
|
+
], Opportunity.prototype, "description", void 0);
|
|
107
|
+
tslib_1.__decorate([
|
|
108
|
+
(0, typeorm_1.CreateDateColumn)(),
|
|
109
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When the opportunity was created' }),
|
|
110
|
+
tslib_1.__metadata("design:type", Date)
|
|
111
|
+
], Opportunity.prototype, "createdAt", void 0);
|
|
112
|
+
tslib_1.__decorate([
|
|
113
|
+
(0, typeorm_1.UpdateDateColumn)(),
|
|
114
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When the opportunity last changed' }),
|
|
115
|
+
tslib_1.__metadata("design:type", Date)
|
|
116
|
+
], Opportunity.prototype, "updatedAt", void 0);
|
|
117
|
+
tslib_1.__decorate([
|
|
118
|
+
(0, typeorm_1.DeleteDateColumn)(),
|
|
119
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When the opportunity was deleted' }),
|
|
120
|
+
tslib_1.__metadata("design:type", Date)
|
|
121
|
+
], Opportunity.prototype, "deletedAt", void 0);
|
|
122
|
+
tslib_1.__decorate([
|
|
123
|
+
(0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
|
|
124
|
+
(0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
|
|
125
|
+
tslib_1.__metadata("design:type", auth_base_1.User)
|
|
126
|
+
], Opportunity.prototype, "creator", void 0);
|
|
127
|
+
tslib_1.__decorate([
|
|
128
|
+
(0, typeorm_1.RelationId)((opportunity) => opportunity.creator),
|
|
129
|
+
tslib_1.__metadata("design:type", String)
|
|
130
|
+
], Opportunity.prototype, "creatorId", void 0);
|
|
131
|
+
tslib_1.__decorate([
|
|
132
|
+
(0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
|
|
133
|
+
(0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
|
|
134
|
+
tslib_1.__metadata("design:type", auth_base_1.User)
|
|
135
|
+
], Opportunity.prototype, "updater", void 0);
|
|
136
|
+
tslib_1.__decorate([
|
|
137
|
+
(0, typeorm_1.RelationId)((opportunity) => opportunity.updater),
|
|
138
|
+
tslib_1.__metadata("design:type", String)
|
|
139
|
+
], Opportunity.prototype, "updaterId", void 0);
|
|
140
|
+
exports.Opportunity = Opportunity = tslib_1.__decorate([
|
|
141
|
+
(0, typeorm_1.Entity)(),
|
|
142
|
+
(0, typeorm_1.Index)('ix_opportunity_0', (opportunity) => [opportunity.domain, opportunity.stage, opportunity.expectedCloseMonth]),
|
|
143
|
+
(0, typeorm_1.Index)('ix_opportunity_1', (opportunity) => [opportunity.domain, opportunity.counterparty]),
|
|
144
|
+
(0, typeorm_1.Index)('ix_opportunity_2', (opportunity) => [opportunity.domain, opportunity.endCustomer]),
|
|
145
|
+
(0, type_graphql_1.ObjectType)({ description: 'Entity for Opportunity — work hoped for, before a contract' })
|
|
146
|
+
], Opportunity);
|
|
147
|
+
//# sourceMappingURL=opportunity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opportunity.js","sourceRoot":"","sources":["../../../server/service/opportunity/opportunity.ts"],"names":[],"mappings":"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","sourcesContent":["import { User } from '@things-factory/auth-base'\nimport { Counterparty } from '@things-factory/biz-base'\nimport { Domain, moneyColumn } from '@things-factory/shell'\nimport { Field, Float, ID, Int, ObjectType } from 'type-graphql'\nimport { Column, CreateDateColumn, DeleteDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId, UpdateDateColumn } from 'typeorm'\n\nimport { OpportunityStage } from './opportunity-rules'\n\n/**\n * A sales opportunity — work the domain hopes to win, before there is a contract: with whom, for how much, by when,\n * and how likely. A person moves it through the stages; it closes as won or lost (ADR-0138 decision 5).\n */\n@Entity()\n@Index('ix_opportunity_0', (opportunity: Opportunity) => [opportunity.domain, opportunity.stage, opportunity.expectedCloseMonth])\n@Index('ix_opportunity_1', (opportunity: Opportunity) => [opportunity.domain, opportunity.counterparty])\n@Index('ix_opportunity_2', (opportunity: Opportunity) => [opportunity.domain, opportunity.endCustomer])\n@ObjectType({ description: 'Entity for Opportunity — work hoped for, before a contract' })\nexport class Opportunity {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true })\n domain?: Domain\n\n @RelationId((opportunity: Opportunity) => opportunity.domain)\n domainId?: string\n\n @Column()\n @Field({ description: 'What the opportunity is called' })\n name: string\n\n @ManyToOne(type => Counterparty, { nullable: false })\n @Field(type => Counterparty, { nullable: true, description: 'The party the domain would contract with' })\n counterparty: Counterparty\n\n @RelationId((opportunity: Opportunity) => opportunity.counterparty)\n @Field({ description: 'Id of the party the domain would contract with' })\n counterpartyId: string\n\n @ManyToOne(type => Counterparty, { nullable: true })\n @Field(type => Counterparty, { nullable: true, description: 'The end customer, when the work comes through another party' })\n endCustomer?: Counterparty\n\n @RelationId((opportunity: Opportunity) => opportunity.endCustomer)\n @Field({ nullable: true, description: 'Id of the end customer' })\n endCustomerId?: string\n\n @Column({ ...moneyColumn(), default: 0 })\n @Field(type => Float, { description: 'Expected amount before tax' })\n amount: number\n\n @Column({ default: 'KRW' })\n @Field({ description: 'ISO 4217 currency code of the amount' })\n currency: string\n\n @Column()\n @Field({ description: 'Month the domain expects to win it, YYYY-MM' })\n expectedCloseMonth: string\n\n @Column({ default: OpportunityStage.LEAD })\n @Field(type => OpportunityStage, { description: 'Lead, proposal, quoted, negotiation, won or lost' })\n stage: OpportunityStage\n\n @Column({ type: 'int' })\n @Field(type => Int, { description: 'Chance of winning in percent, 0 to 100 — the stage gives it, a person may change it' })\n probability: number\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n owner?: User\n\n @RelationId((opportunity: Opportunity) => opportunity.owner)\n @Field({ nullable: true, description: 'Id of the person in charge' })\n ownerId?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Day it was closed as won or lost, YYYY-MM-DD' })\n closedOn?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Why it was lost' })\n lostReason?: string\n\n @Column({ type: 'text', nullable: true })\n @Field({ nullable: true, description: 'Notes' })\n description?: string\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'When the opportunity was created' })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'When the opportunity last changed' })\n updatedAt?: Date\n\n @DeleteDateColumn()\n @Field({ nullable: true, description: 'When the opportunity was deleted' })\n deletedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((opportunity: Opportunity) => opportunity.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((opportunity: Opportunity) => opportunity.updater)\n updaterId?: string\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Quotation } from './quotation';
|
|
2
|
+
import { QuotationEvent } from './quotation-event';
|
|
3
|
+
import { QuotationEventQuery } from './quotation-event-query';
|
|
4
|
+
import { QuotationItem } from './quotation-item';
|
|
5
|
+
import { QuotationItemQuery } from './quotation-item-query';
|
|
6
|
+
import { QuotationMutation } from './quotation-mutation';
|
|
7
|
+
import { QuotationQuery } from './quotation-query';
|
|
8
|
+
export declare const entities: (typeof QuotationItem | typeof Quotation | typeof QuotationEvent)[];
|
|
9
|
+
export declare const resolvers: (typeof QuotationEventQuery | typeof QuotationItemQuery | typeof QuotationMutation | typeof QuotationQuery)[];
|
|
10
|
+
export declare const subscribers: any[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.subscribers = exports.resolvers = exports.entities = void 0;
|
|
4
|
+
const quotation_1 = require("./quotation");
|
|
5
|
+
const quotation_event_1 = require("./quotation-event");
|
|
6
|
+
const quotation_event_query_1 = require("./quotation-event-query");
|
|
7
|
+
const quotation_item_1 = require("./quotation-item");
|
|
8
|
+
const quotation_item_query_1 = require("./quotation-item-query");
|
|
9
|
+
const quotation_mutation_1 = require("./quotation-mutation");
|
|
10
|
+
const quotation_query_1 = require("./quotation-query");
|
|
11
|
+
exports.entities = [quotation_1.Quotation, quotation_item_1.QuotationItem, quotation_event_1.QuotationEvent];
|
|
12
|
+
exports.resolvers = [quotation_query_1.QuotationQuery, quotation_mutation_1.QuotationMutation, quotation_item_query_1.QuotationItemQuery, quotation_event_query_1.QuotationEventQuery];
|
|
13
|
+
exports.subscribers = [];
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/quotation/index.ts"],"names":[],"mappings":";;;AAAA,2CAAuC;AACvC,uDAAkD;AAClD,mEAA6D;AAC7D,qDAAgD;AAChD,iEAA2D;AAC3D,6DAAwD;AACxD,uDAAkD;AAErC,QAAA,QAAQ,GAAG,CAAC,qBAAS,EAAE,8BAAa,EAAE,gCAAc,CAAC,CAAA;AACrD,QAAA,SAAS,GAAG,CAAC,gCAAc,EAAE,sCAAiB,EAAE,yCAAkB,EAAE,2CAAmB,CAAC,CAAA;AACxF,QAAA,WAAW,GAAG,EAAE,CAAA","sourcesContent":["import { Quotation } from './quotation'\nimport { QuotationEvent } from './quotation-event'\nimport { QuotationEventQuery } from './quotation-event-query'\nimport { QuotationItem } from './quotation-item'\nimport { QuotationItemQuery } from './quotation-item-query'\nimport { QuotationMutation } from './quotation-mutation'\nimport { QuotationQuery } from './quotation-query'\n\nexport const entities = [Quotation, QuotationItem, QuotationEvent]\nexport const resolvers = [QuotationQuery, QuotationMutation, QuotationItemQuery, QuotationEventQuery]\nexport const subscribers = []\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { User } from '@things-factory/auth-base';
|
|
2
|
+
import { Domain } from '@things-factory/shell';
|
|
3
|
+
import { QuotationEvent } from './quotation-event';
|
|
4
|
+
export declare class QuotationEventQuery {
|
|
5
|
+
actor(row: QuotationEvent): User | Promise<User>;
|
|
6
|
+
domain(row: QuotationEvent): Domain | Promise<Domain>;
|
|
7
|
+
creator(row: QuotationEvent): User | Promise<User>;
|
|
8
|
+
updater(row: QuotationEvent): User | Promise<User>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QuotationEventQuery = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
6
|
+
const shell_1 = require("@things-factory/shell");
|
|
7
|
+
const type_graphql_1 = require("type-graphql");
|
|
8
|
+
const quotation_event_1 = require("./quotation-event");
|
|
9
|
+
let QuotationEventQuery = class QuotationEventQuery {
|
|
10
|
+
actor(row) {
|
|
11
|
+
return row.actor ?? (row.actorId ? (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: row.actorId }) : undefined);
|
|
12
|
+
}
|
|
13
|
+
domain(row) {
|
|
14
|
+
return row.domain ?? (row.domainId ? (0, shell_1.getRepository)(shell_1.Domain).findOneBy({ id: row.domainId }) : undefined);
|
|
15
|
+
}
|
|
16
|
+
creator(row) {
|
|
17
|
+
return row.creator ?? (row.creatorId ? (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: row.creatorId }) : undefined);
|
|
18
|
+
}
|
|
19
|
+
updater(row) {
|
|
20
|
+
return row.updater ?? (row.updaterId ? (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: row.updaterId }) : undefined);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
exports.QuotationEventQuery = QuotationEventQuery;
|
|
24
|
+
tslib_1.__decorate([
|
|
25
|
+
(0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true }),
|
|
26
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
27
|
+
tslib_1.__metadata("design:type", Function),
|
|
28
|
+
tslib_1.__metadata("design:paramtypes", [quotation_event_1.QuotationEvent]),
|
|
29
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
30
|
+
], QuotationEventQuery.prototype, "actor", null);
|
|
31
|
+
tslib_1.__decorate([
|
|
32
|
+
(0, type_graphql_1.FieldResolver)(type => shell_1.Domain, { nullable: true }),
|
|
33
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
34
|
+
tslib_1.__metadata("design:type", Function),
|
|
35
|
+
tslib_1.__metadata("design:paramtypes", [quotation_event_1.QuotationEvent]),
|
|
36
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
37
|
+
], QuotationEventQuery.prototype, "domain", null);
|
|
38
|
+
tslib_1.__decorate([
|
|
39
|
+
(0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true }),
|
|
40
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
41
|
+
tslib_1.__metadata("design:type", Function),
|
|
42
|
+
tslib_1.__metadata("design:paramtypes", [quotation_event_1.QuotationEvent]),
|
|
43
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
44
|
+
], QuotationEventQuery.prototype, "creator", null);
|
|
45
|
+
tslib_1.__decorate([
|
|
46
|
+
(0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true }),
|
|
47
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
48
|
+
tslib_1.__metadata("design:type", Function),
|
|
49
|
+
tslib_1.__metadata("design:paramtypes", [quotation_event_1.QuotationEvent]),
|
|
50
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
51
|
+
], QuotationEventQuery.prototype, "updater", null);
|
|
52
|
+
exports.QuotationEventQuery = QuotationEventQuery = tslib_1.__decorate([
|
|
53
|
+
(0, type_graphql_1.Resolver)(quotation_event_1.QuotationEvent)
|
|
54
|
+
], QuotationEventQuery);
|
|
55
|
+
//# sourceMappingURL=quotation-event-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quotation-event-query.js","sourceRoot":"","sources":["../../../server/service/quotation/quotation-event-query.ts"],"names":[],"mappings":";;;;AAAA,yDAAgD;AAChD,iDAA6D;AAC7D,+CAA4D;AAE5D,uDAAkD;AAG3C,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAE9B,KAAK,CAAS,GAAmB;QAC/B,OAAO,GAAG,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IACpG,CAAC;IAED,MAAM,CAAS,GAAmB;QAChC,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAA,qBAAa,EAAC,cAAM,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IACzG,CAAC;IAGD,OAAO,CAAS,GAAmB;QACjC,OAAO,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAC1G,CAAC;IAGD,OAAO,CAAS,GAAmB;QACjC,OAAO,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAC1G,CAAC;CACF,CAAA;AAnBY,kDAAmB;AAE9B;IADC,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACzC,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAM,gCAAc;;gDAEhC;AAED;IADC,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1C,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAM,gCAAc;;iDAEjC;AAGD;IADC,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACvC,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAM,gCAAc;;kDAElC;AAGD;IADC,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACvC,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAM,gCAAc;;kDAElC;8BAlBU,mBAAmB;IAD/B,IAAA,uBAAQ,EAAC,gCAAc,CAAC;GACZ,mBAAmB,CAmB/B","sourcesContent":["import { User } from '@things-factory/auth-base'\nimport { Domain, getRepository } from '@things-factory/shell'\nimport { FieldResolver, Resolver, Root } from 'type-graphql'\n\nimport { QuotationEvent } from './quotation-event'\n\n@Resolver(QuotationEvent)\nexport class QuotationEventQuery {\n @FieldResolver(type => User, { nullable: true })\n actor(@Root() row: QuotationEvent) {\n return row.actor ?? (row.actorId ? getRepository(User).findOneBy({ id: row.actorId }) : undefined)\n }\n @FieldResolver(type => Domain, { nullable: true })\n domain(@Root() row: QuotationEvent) {\n return row.domain ?? (row.domainId ? getRepository(Domain).findOneBy({ id: row.domainId }) : undefined)\n }\n\n @FieldResolver(type => User, { nullable: true })\n creator(@Root() row: QuotationEvent) {\n return row.creator ?? (row.creatorId ? getRepository(User).findOneBy({ id: row.creatorId }) : undefined)\n }\n\n @FieldResolver(type => User, { nullable: true })\n updater(@Root() row: QuotationEvent) {\n return row.updater ?? (row.updaterId ? getRepository(User).findOneBy({ id: row.updaterId }) : undefined)\n }\n}\n"]}
|