@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
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
6
|
+
and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
<!-- ## [Unreleased] -->
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function bootstrap(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AAExE,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,uBAAuB,EAAE,CAAA;AAC3B,CAAC","sourcesContent":["import { registerOpportunityKind } from './entity360/opportunity-360.js'\n\nexport default function bootstrap() {\n registerOpportunityKind()\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import { type Entity360DoorAnswer, type Entity360Subject } from '@operato/layout';
|
|
3
|
+
/** An opportunity's 360 (ADR-0067). The module draws the opportunity; an application hangs its own sections on 'opportunity'. */
|
|
4
|
+
export declare function registerOpportunityKind(): void;
|
|
5
|
+
export declare class OpportunityOverviewSection extends LitElement {
|
|
6
|
+
static styles: import("lit").CSSResult;
|
|
7
|
+
subject?: Entity360Subject;
|
|
8
|
+
answer?: Entity360DoorAnswer<any>;
|
|
9
|
+
updated(changed: Map<string, unknown>): void;
|
|
10
|
+
private read;
|
|
11
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import gql from 'graphql-tag';
|
|
3
|
+
import { css, html, LitElement } from 'lit';
|
|
4
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
5
|
+
import { client } from '@operato/graphql';
|
|
6
|
+
import { i18next } from '@operato/i18n';
|
|
7
|
+
import { entity360Name, readEntity360Door, registerEntity360Kind, registerEntity360Section } from '@operato/layout';
|
|
8
|
+
import { documentAmount } from '@things-factory/invoice/dist-client';
|
|
9
|
+
import { opportunityStageWord } from '../opportunity-words';
|
|
10
|
+
/** An opportunity's 360 (ADR-0067). The module draws the opportunity; an application hangs its own sections on 'opportunity'. */
|
|
11
|
+
export function registerOpportunityKind() {
|
|
12
|
+
registerEntity360Kind({
|
|
13
|
+
kind: 'opportunity',
|
|
14
|
+
typenames: ['Opportunity'],
|
|
15
|
+
title: ({ value }) => `${i18next.t('title.opportunity')} · ${value.name || ''}`,
|
|
16
|
+
context: ({ value }) => [value.counterparty?.name, value.stage ? opportunityStageWord(value.stage) : '', value.expectedCloseMonth].filter(Boolean).join(' · ')
|
|
17
|
+
});
|
|
18
|
+
registerEntity360Section('opportunity', {
|
|
19
|
+
name: 'overview',
|
|
20
|
+
order: 10,
|
|
21
|
+
render: subject => html `<opportunity-overview-section .subject=${subject}></opportunity-overview-section>`
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
let OpportunityOverviewSection = class OpportunityOverviewSection extends LitElement {
|
|
25
|
+
static { this.styles = css `
|
|
26
|
+
:host {
|
|
27
|
+
font-size: var(--ui-t-body);
|
|
28
|
+
line-height: 1.5;
|
|
29
|
+
}
|
|
30
|
+
dl {
|
|
31
|
+
margin: 0;
|
|
32
|
+
display: grid;
|
|
33
|
+
grid-template-columns: max-content 1fr;
|
|
34
|
+
gap: var(--spacing-small) var(--spacing-large);
|
|
35
|
+
}
|
|
36
|
+
dt {
|
|
37
|
+
color: var(--ui-muted);
|
|
38
|
+
}
|
|
39
|
+
dd {
|
|
40
|
+
margin: 0;
|
|
41
|
+
overflow-wrap: anywhere;
|
|
42
|
+
font-variant-numeric: tabular-nums;
|
|
43
|
+
}
|
|
44
|
+
`; }
|
|
45
|
+
updated(changed) {
|
|
46
|
+
if (changed.has('subject'))
|
|
47
|
+
this.read();
|
|
48
|
+
}
|
|
49
|
+
async read() {
|
|
50
|
+
const id = this.subject?.id;
|
|
51
|
+
this.answer = undefined;
|
|
52
|
+
if (!id)
|
|
53
|
+
return;
|
|
54
|
+
let response;
|
|
55
|
+
try {
|
|
56
|
+
response = await client.query({
|
|
57
|
+
query: gql `
|
|
58
|
+
query ($id: String!) {
|
|
59
|
+
opportunity(id: $id) {
|
|
60
|
+
id name stage probability amount currency expectedCloseMonth closedOn lostReason description
|
|
61
|
+
counterparty { id name } endCustomer { id name } owner { id name }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
`,
|
|
65
|
+
variables: { id },
|
|
66
|
+
fetchPolicy: 'no-cache',
|
|
67
|
+
errorPolicy: 'all'
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
response = { data: null, errors: e?.graphQLErrors?.length ? e.graphQLErrors : [{ message: e?.message ?? String(e) }] };
|
|
72
|
+
}
|
|
73
|
+
if (this.subject?.id !== id)
|
|
74
|
+
return;
|
|
75
|
+
this.answer = readEntity360Door(response, data => data?.opportunity);
|
|
76
|
+
}
|
|
77
|
+
render() {
|
|
78
|
+
const one = this.answer?.data;
|
|
79
|
+
const party = (value) => (value ? entity360Name({ __typename: 'Counterparty', ...value }, value.name) : '—');
|
|
80
|
+
return html `<ox-entity360-section .heading=${i18next.t('title.opportunity')} .state=${this.answer?.state ?? 'loading'} .message=${this.answer?.message ?? ''}>
|
|
81
|
+
${one
|
|
82
|
+
? html `<dl>
|
|
83
|
+
<dt>${i18next.t('field.opportunity-stage')}</dt>
|
|
84
|
+
<dd>${opportunityStageWord(one.stage)} · ${one.probability}%</dd>
|
|
85
|
+
<dt>${i18next.t('field.opportunity-counterparty')}</dt>
|
|
86
|
+
<dd>${party(one.counterparty)}</dd>
|
|
87
|
+
<dt>${i18next.t('field.opportunity-end-customer')}</dt>
|
|
88
|
+
<dd>${party(one.endCustomer)}</dd>
|
|
89
|
+
<dt>${i18next.t('field.opportunity-amount')}</dt>
|
|
90
|
+
<dd>${documentAmount(one.amount, one.currency || 'KRW')}</dd>
|
|
91
|
+
<dt>${i18next.t('field.opportunity-expected-close-month')}</dt>
|
|
92
|
+
<dd>${one.expectedCloseMonth}</dd>
|
|
93
|
+
<dt>${i18next.t('field.opportunity-owner')}</dt>
|
|
94
|
+
<dd>${one.owner?.name ?? '—'}</dd>
|
|
95
|
+
${one.closedOn ? html `<dt>${i18next.t('field.opportunity-closed-on')}</dt><dd>${one.closedOn}</dd>` : ''}
|
|
96
|
+
${one.lostReason ? html `<dt>${i18next.t('field.opportunity-lost-reason')}</dt><dd>${one.lostReason}</dd>` : ''}
|
|
97
|
+
</dl>`
|
|
98
|
+
: ''}
|
|
99
|
+
</ox-entity360-section>`;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
__decorate([
|
|
103
|
+
property({ attribute: false }),
|
|
104
|
+
__metadata("design:type", Object)
|
|
105
|
+
], OpportunityOverviewSection.prototype, "subject", void 0);
|
|
106
|
+
__decorate([
|
|
107
|
+
state(),
|
|
108
|
+
__metadata("design:type", Object)
|
|
109
|
+
], OpportunityOverviewSection.prototype, "answer", void 0);
|
|
110
|
+
OpportunityOverviewSection = __decorate([
|
|
111
|
+
customElement('opportunity-overview-section')
|
|
112
|
+
], OpportunityOverviewSection);
|
|
113
|
+
export { OpportunityOverviewSection };
|
|
114
|
+
//# sourceMappingURL=opportunity-360.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opportunity-360.js","sourceRoot":"","sources":["../../client/entity360/opportunity-360.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { entity360Name, readEntity360Door, registerEntity360Kind, registerEntity360Section, type Entity360DoorAnswer, type Entity360Subject } from '@operato/layout'\nimport { documentAmount } from '@things-factory/invoice/dist-client'\n\nimport { opportunityStageWord } from '../opportunity-words'\n\n/** An opportunity's 360 (ADR-0067). The module draws the opportunity; an application hangs its own sections on 'opportunity'. */\nexport function registerOpportunityKind() {\n registerEntity360Kind({\n kind: 'opportunity',\n typenames: ['Opportunity'],\n title: ({ value }) => `${i18next.t('title.opportunity')} · ${value.name || ''}`,\n context: ({ value }) => [value.counterparty?.name, value.stage ? opportunityStageWord(value.stage) : '', value.expectedCloseMonth].filter(Boolean).join(' · ')\n })\n registerEntity360Section('opportunity', {\n name: 'overview',\n order: 10,\n render: subject => html`<opportunity-overview-section .subject=${subject}></opportunity-overview-section>`\n })\n}\n\n@customElement('opportunity-overview-section')\nexport class OpportunityOverviewSection extends LitElement {\n static styles = css`\n :host {\n font-size: var(--ui-t-body);\n line-height: 1.5;\n }\n dl {\n margin: 0;\n display: grid;\n grid-template-columns: max-content 1fr;\n gap: var(--spacing-small) var(--spacing-large);\n }\n dt {\n color: var(--ui-muted);\n }\n dd {\n margin: 0;\n overflow-wrap: anywhere;\n font-variant-numeric: tabular-nums;\n }\n `\n\n @property({ attribute: false }) subject?: Entity360Subject\n @state() answer?: Entity360DoorAnswer<any>\n\n updated(changed: Map<string, unknown>) {\n if (changed.has('subject')) this.read()\n }\n\n private async read() {\n const id = this.subject?.id\n this.answer = undefined\n if (!id) return\n let response: any\n try {\n response = await client.query({\n query: gql`\n query ($id: String!) {\n opportunity(id: $id) {\n id name stage probability amount currency expectedCloseMonth closedOn lostReason description\n counterparty { id name } endCustomer { id name } owner { id name }\n }\n }\n `,\n variables: { id },\n fetchPolicy: 'no-cache',\n errorPolicy: 'all'\n } as any)\n } catch (e: any) {\n response = { data: null, errors: e?.graphQLErrors?.length ? e.graphQLErrors : [{ message: e?.message ?? String(e) }] }\n }\n if (this.subject?.id !== id) return\n this.answer = readEntity360Door(response, data => data?.opportunity)\n }\n\n render() {\n const one = this.answer?.data\n const party = (value?: { id: string; name: string }) => (value ? entity360Name({ __typename: 'Counterparty', ...value }, value.name) : '—')\n return html`<ox-entity360-section .heading=${i18next.t('title.opportunity')} .state=${this.answer?.state ?? 'loading'} .message=${this.answer?.message ?? ''}>\n ${one\n ? html`<dl>\n <dt>${i18next.t('field.opportunity-stage')}</dt>\n <dd>${opportunityStageWord(one.stage)} · ${one.probability}%</dd>\n <dt>${i18next.t('field.opportunity-counterparty')}</dt>\n <dd>${party(one.counterparty)}</dd>\n <dt>${i18next.t('field.opportunity-end-customer')}</dt>\n <dd>${party(one.endCustomer)}</dd>\n <dt>${i18next.t('field.opportunity-amount')}</dt>\n <dd>${documentAmount(one.amount, one.currency || 'KRW')}</dd>\n <dt>${i18next.t('field.opportunity-expected-close-month')}</dt>\n <dd>${one.expectedCloseMonth}</dd>\n <dt>${i18next.t('field.opportunity-owner')}</dt>\n <dd>${one.owner?.name ?? '—'}</dd>\n ${one.closedOn ? html`<dt>${i18next.t('field.opportunity-closed-on')}</dt><dd>${one.closedOn}</dd>` : ''}\n ${one.lostReason ? html`<dt>${i18next.t('field.opportunity-lost-reason')}</dt><dd>${one.lostReason}</dd>` : ''}\n </dl>`\n : ''}\n </ox-entity360-section>`\n }\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { configureQuotationSection, type QuotationSection } from './quotation-attach.js';
|
|
2
|
+
export { quotationStatusWord } from './quotation-words.js';
|
|
3
|
+
export { configureOpportunitySection, type OpportunitySection } from './opportunity-attach.js';
|
|
4
|
+
export { opportunityStageWord } from './opportunity-words.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { configureQuotationSection } from './quotation-attach.js';
|
|
2
|
+
export { quotationStatusWord } from './quotation-words.js';
|
|
3
|
+
export { configureOpportunitySection } from './opportunity-attach.js';
|
|
4
|
+
export { opportunityStageWord } from './opportunity-words.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAyB,MAAM,uBAAuB,CAAA;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,2BAA2B,EAA2B,MAAM,yBAAyB,CAAA;AAC9F,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA","sourcesContent":["export { configureQuotationSection, type QuotationSection } from './quotation-attach.js'\nexport { quotationStatusWord } from './quotation-words.js'\nexport { configureOpportunitySection, type OpportunitySection } from './opportunity-attach.js'\nexport { opportunityStageWord } from './opportunity-words.js'\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type TemplateResult } from 'lit';
|
|
2
|
+
export type OpportunitySection = {
|
|
3
|
+
/** The section's heading, already in the reader's words. */
|
|
4
|
+
heading: () => string;
|
|
5
|
+
/** The section's body for one saved opportunity; it reads and writes through the application's own API. */
|
|
6
|
+
render: (opportunity: {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
stage: string;
|
|
10
|
+
counterpartyId: string;
|
|
11
|
+
currency: string;
|
|
12
|
+
amount: number;
|
|
13
|
+
expectedCloseMonth: string;
|
|
14
|
+
}) => TemplateResult;
|
|
15
|
+
};
|
|
16
|
+
export declare function configureOpportunitySection(one: OpportunitySection): void;
|
|
17
|
+
export declare function opportunitySection(): OpportunitySection | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opportunity-attach.js","sourceRoot":"","sources":["../client/opportunity-attach.ts"],"names":[],"mappings":"AAcA,IAAI,OAAuC,CAAA;AAE3C,MAAM,UAAU,2BAA2B,CAAC,GAAuB;IACjE,OAAO,GAAG,GAAG,CAAA;AACf,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,OAAO,CAAA;AAChB,CAAC","sourcesContent":["import { type TemplateResult } from 'lit'\n\n/*\n * Where an application attaches its own work to an opportunity — Office ties it to the contract it became and to the\n * classification its pivot judgement reads (ADR-0138 decision 8). The sales module knows no application words.\n */\n\nexport type OpportunitySection = {\n /** The section's heading, already in the reader's words. */\n heading: () => string\n /** The section's body for one saved opportunity; it reads and writes through the application's own API. */\n render: (opportunity: { id: string; name: string; stage: string; counterpartyId: string; currency: string; amount: number; expectedCloseMonth: string }) => TemplateResult\n}\n\nlet section: OpportunitySection | undefined\n\nexport function configureOpportunitySection(one: OpportunitySection): void {\n section = one\n}\n\nexport function opportunitySection(): OpportunitySection | undefined {\n return section\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const opportunityStageWord: (stage?: string) => string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { i18next } from '@operato/i18n';
|
|
2
|
+
export const opportunityStageWord = (stage) => stage === 'PROPOSAL'
|
|
3
|
+
? i18next.t('text.opportunity-stage-proposal')
|
|
4
|
+
: stage === 'QUOTED'
|
|
5
|
+
? i18next.t('text.opportunity-stage-quoted')
|
|
6
|
+
: stage === 'NEGOTIATION'
|
|
7
|
+
? i18next.t('text.opportunity-stage-negotiation')
|
|
8
|
+
: stage === 'WON'
|
|
9
|
+
? i18next.t('text.opportunity-stage-won')
|
|
10
|
+
: stage === 'LOST'
|
|
11
|
+
? i18next.t('text.opportunity-stage-lost')
|
|
12
|
+
: i18next.t('text.opportunity-stage-lead');
|
|
13
|
+
//# sourceMappingURL=opportunity-words.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opportunity-words.js","sourceRoot":"","sources":["../client/opportunity-words.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAc,EAAE,EAAE,CACrD,KAAK,KAAK,UAAU;IAClB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;IAC9C,CAAC,CAAC,KAAK,KAAK,QAAQ;QAClB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,+BAA+B,CAAC;QAC5C,CAAC,CAAC,KAAK,KAAK,aAAa;YACvB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oCAAoC,CAAC;YACjD,CAAC,CAAC,KAAK,KAAK,KAAK;gBACf,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC;gBACzC,CAAC,CAAC,KAAK,KAAK,MAAM;oBAChB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;oBAC1C,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAA","sourcesContent":["import { i18next } from '@operato/i18n'\n\nexport const opportunityStageWord = (stage?: string) =>\n stage === 'PROPOSAL'\n ? i18next.t('text.opportunity-stage-proposal')\n : stage === 'QUOTED'\n ? i18next.t('text.opportunity-stage-quoted')\n : stage === 'NEGOTIATION'\n ? i18next.t('text.opportunity-stage-negotiation')\n : stage === 'WON'\n ? i18next.t('text.opportunity-stage-won')\n : stage === 'LOST'\n ? i18next.t('text.opportunity-stage-lost')\n : i18next.t('text.opportunity-stage-lead')\n"]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import '@operato/list-state/ox-page-state.js';
|
|
2
|
+
import { PageView } from '@operato/shell';
|
|
3
|
+
type Party = {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
businessNumber?: string;
|
|
7
|
+
};
|
|
8
|
+
type Picker = {
|
|
9
|
+
search: string;
|
|
10
|
+
found: Party[];
|
|
11
|
+
};
|
|
12
|
+
type Form = {
|
|
13
|
+
name: string;
|
|
14
|
+
counterparty: Party | null;
|
|
15
|
+
endCustomer: Party | null;
|
|
16
|
+
amount: string;
|
|
17
|
+
currency: string;
|
|
18
|
+
expectedCloseMonth: string;
|
|
19
|
+
stage: string;
|
|
20
|
+
probability: string;
|
|
21
|
+
ownerId: string;
|
|
22
|
+
description: string;
|
|
23
|
+
};
|
|
24
|
+
declare const OpportunityEditor_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
|
|
25
|
+
/**
|
|
26
|
+
* 영업 기회 편집 — with whom, for how much, by when and how likely.
|
|
27
|
+
*
|
|
28
|
+
* A person moves an open opportunity through the stages; changing the stage puts that stage's probability in, and the
|
|
29
|
+
* person may change it. An open one is closed as lost with the reason; a lost one is opened again by choosing an open
|
|
30
|
+
* stage. Winning is the application's: it closes the opportunity when the opportunity becomes its contract.
|
|
31
|
+
*/
|
|
32
|
+
export declare class OpportunityEditor extends OpportunityEditor_base {
|
|
33
|
+
static styles: import("lit").CSSResult[];
|
|
34
|
+
opportunity: any;
|
|
35
|
+
form: Form;
|
|
36
|
+
pickers: Record<'counterparty' | 'endCustomer', Picker>;
|
|
37
|
+
stages: {
|
|
38
|
+
stage: string;
|
|
39
|
+
probability: number;
|
|
40
|
+
open: boolean;
|
|
41
|
+
}[];
|
|
42
|
+
owners: {
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
email?: string;
|
|
46
|
+
}[];
|
|
47
|
+
events: any[];
|
|
48
|
+
reason: string;
|
|
49
|
+
loading: boolean;
|
|
50
|
+
error: unknown;
|
|
51
|
+
busy: boolean;
|
|
52
|
+
private isOpen;
|
|
53
|
+
/** Won is final; a lost one is changed only by being opened again. */
|
|
54
|
+
get editable(): boolean;
|
|
55
|
+
get context(): {
|
|
56
|
+
frame: string;
|
|
57
|
+
menu: string;
|
|
58
|
+
actions: any[];
|
|
59
|
+
description?: string | undefined;
|
|
60
|
+
title: string;
|
|
61
|
+
};
|
|
62
|
+
pageUpdated(changes: any, lifecycle: any): Promise<void>;
|
|
63
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
64
|
+
/** A counterparty of the domain, found by name or business number. */
|
|
65
|
+
private renderParty;
|
|
66
|
+
private renderLose;
|
|
67
|
+
private renderEvents;
|
|
68
|
+
private setPicker;
|
|
69
|
+
private chooseParty;
|
|
70
|
+
/** The stage's own probability comes in with it; the person may change it afterwards. */
|
|
71
|
+
private chooseStage;
|
|
72
|
+
private readChoices;
|
|
73
|
+
private findParties;
|
|
74
|
+
private load;
|
|
75
|
+
private show;
|
|
76
|
+
private run;
|
|
77
|
+
private input;
|
|
78
|
+
private save;
|
|
79
|
+
private lose;
|
|
80
|
+
}
|
|
81
|
+
export {};
|