@things-factory/sales 10.1.223 → 10.1.227

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist-client/index.d.ts +1 -0
  2. package/dist-client/index.js +1 -0
  3. package/dist-client/index.js.map +1 -1
  4. package/dist-client/pages/quotation-editor.d.ts +50 -6
  5. package/dist-client/pages/quotation-editor.js +303 -33
  6. package/dist-client/pages/quotation-editor.js.map +1 -1
  7. package/dist-client/pages/sales-product-list.d.ts +54 -0
  8. package/dist-client/pages/sales-product-list.js +202 -0
  9. package/dist-client/pages/sales-product-list.js.map +1 -0
  10. package/dist-client/route.d.ts +1 -1
  11. package/dist-client/route.js +3 -0
  12. package/dist-client/route.js.map +1 -1
  13. package/dist-client/sales-product-pick.d.ts +51 -0
  14. package/dist-client/sales-product-pick.js +210 -0
  15. package/dist-client/sales-product-pick.js.map +1 -0
  16. package/dist-client/sales-product-words.d.ts +2 -0
  17. package/dist-client/sales-product-words.js +8 -0
  18. package/dist-client/sales-product-words.js.map +1 -0
  19. package/dist-client/tsconfig.tsbuildinfo +1 -1
  20. package/dist-server/service/index.d.ts +6 -2
  21. package/dist-server/service/index.js +8 -3
  22. package/dist-server/service/index.js.map +1 -1
  23. package/dist-server/service/quotation/quotation-query.d.ts +3 -0
  24. package/dist-server/service/quotation/quotation-query.js +36 -0
  25. package/dist-server/service/quotation/quotation-query.js.map +1 -1
  26. package/dist-server/service/quotation/quotation-service.d.ts +1 -0
  27. package/dist-server/service/quotation/quotation-service.js +5 -4
  28. package/dist-server/service/quotation/quotation-service.js.map +1 -1
  29. package/dist-server/service/sales-product/index.d.ts +6 -0
  30. package/dist-server/service/sales-product/index.js +10 -0
  31. package/dist-server/service/sales-product/index.js.map +1 -0
  32. package/dist-server/service/sales-product/sales-product-mutation.d.ts +6 -0
  33. package/dist-server/service/sales-product/sales-product-mutation.js +46 -0
  34. package/dist-server/service/sales-product/sales-product-mutation.js.map +1 -0
  35. package/dist-server/service/sales-product/sales-product-query.d.ts +11 -0
  36. package/dist-server/service/sales-product/sales-product-query.js +78 -0
  37. package/dist-server/service/sales-product/sales-product-query.js.map +1 -0
  38. package/dist-server/service/sales-product/sales-product-rules.d.ts +8 -0
  39. package/dist-server/service/sales-product/sales-product-rules.js +26 -0
  40. package/dist-server/service/sales-product/sales-product-rules.js.map +1 -0
  41. package/dist-server/service/sales-product/sales-product-service.d.ts +10 -0
  42. package/dist-server/service/sales-product/sales-product-service.js +86 -0
  43. package/dist-server/service/sales-product/sales-product-service.js.map +1 -0
  44. package/dist-server/service/sales-product/sales-product-type.d.ts +22 -0
  45. package/dist-server/service/sales-product/sales-product-type.js +81 -0
  46. package/dist-server/service/sales-product/sales-product-type.js.map +1 -0
  47. package/dist-server/service/sales-product/sales-product.d.ts +32 -0
  48. package/dist-server/service/sales-product/sales-product.js +126 -0
  49. package/dist-server/service/sales-product/sales-product.js.map +1 -0
  50. package/dist-server/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +7 -7
  52. package/things-factory.config.js +2 -1
  53. package/translations/en.json +33 -3
  54. package/translations/es.json +33 -3
  55. package/translations/ja.json +33 -3
  56. package/translations/ko.json +34 -4
  57. package/translations/ms.json +33 -3
  58. package/translations/zh.json +33 -3
@@ -9,9 +9,13 @@ export * from './opportunity/opportunity-event';
9
9
  export * from './opportunity/opportunity-rules';
10
10
  export * from './opportunity/opportunity-service';
11
11
  export * from './opportunity/opportunity-type';
12
+ export * from './sales-product/sales-product';
13
+ export * from './sales-product/sales-product-rules';
14
+ export * from './sales-product/sales-product-service';
15
+ export * from './sales-product/sales-product-type';
12
16
  export * from './sales-read';
13
- export declare const entities: (typeof import("./opportunity/opportunity").Opportunity | typeof import("./quotation/quotation-item").QuotationItem | typeof import("./quotation/quotation").Quotation | typeof import("./quotation/quotation-event").QuotationEvent | typeof import("./opportunity/opportunity-event").OpportunityEvent)[];
17
+ export declare const entities: (typeof import("./opportunity/opportunity").Opportunity | typeof import("./quotation/quotation-item").QuotationItem | typeof import("./quotation/quotation").Quotation | typeof import("./quotation/quotation-event").QuotationEvent | typeof import("./opportunity/opportunity-event").OpportunityEvent | typeof import("./sales-product/sales-product").SalesProduct)[];
14
18
  export declare const subscribers: any[];
15
19
  export declare const schema: {
16
- resolverClasses: (typeof import("./opportunity/opportunity-event-query").OpportunityEventQuery | typeof import("./opportunity/opportunity-mutation").OpportunityMutation | typeof import("./opportunity/opportunity-query").OpportunityQuery | typeof import("./quotation/quotation-event-query").QuotationEventQuery | typeof import("./quotation/quotation-item-query").QuotationItemQuery | typeof import("./quotation/quotation-mutation").QuotationMutation | typeof import("./quotation/quotation-query").QuotationQuery)[];
20
+ resolverClasses: (typeof import("./opportunity/opportunity-event-query").OpportunityEventQuery | typeof import("./opportunity/opportunity-mutation").OpportunityMutation | typeof import("./opportunity/opportunity-query").OpportunityQuery | typeof import("./quotation/quotation-event-query").QuotationEventQuery | typeof import("./quotation/quotation-item-query").QuotationItemQuery | typeof import("./quotation/quotation-mutation").QuotationMutation | typeof import("./quotation/quotation-query").QuotationQuery | typeof import("./sales-product/sales-product-mutation").SalesProductMutation | typeof import("./sales-product/sales-product-query").SalesProductQuery)[];
17
21
  };
@@ -13,10 +13,15 @@ tslib_1.__exportStar(require("./opportunity/opportunity-event"), exports);
13
13
  tslib_1.__exportStar(require("./opportunity/opportunity-rules"), exports);
14
14
  tslib_1.__exportStar(require("./opportunity/opportunity-service"), exports);
15
15
  tslib_1.__exportStar(require("./opportunity/opportunity-type"), exports);
16
+ tslib_1.__exportStar(require("./sales-product/sales-product"), exports);
17
+ tslib_1.__exportStar(require("./sales-product/sales-product-rules"), exports);
18
+ tslib_1.__exportStar(require("./sales-product/sales-product-service"), exports);
19
+ tslib_1.__exportStar(require("./sales-product/sales-product-type"), exports);
16
20
  tslib_1.__exportStar(require("./sales-read"), exports);
17
21
  const opportunity = tslib_1.__importStar(require("./opportunity"));
18
22
  const quotation = tslib_1.__importStar(require("./quotation"));
19
- exports.entities = [...quotation.entities, ...opportunity.entities];
20
- exports.subscribers = [...quotation.subscribers, ...opportunity.subscribers];
21
- exports.schema = { resolverClasses: [...quotation.resolvers, ...opportunity.resolvers] };
23
+ const salesProduct = tslib_1.__importStar(require("./sales-product"));
24
+ exports.entities = [...quotation.entities, ...opportunity.entities, ...salesProduct.entities];
25
+ exports.subscribers = [...quotation.subscribers, ...opportunity.subscribers, ...salesProduct.subscribers];
26
+ exports.schema = { resolverClasses: [...quotation.resolvers, ...opportunity.resolvers, ...salesProduct.resolvers] };
22
27
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,gEAAqC;AACrC,qEAA0C;AAC1C,sEAA2C;AAC3C,sEAA2C;AAC3C,wEAA6C;AAC7C,qEAA0C;AAC1C,oEAAyC;AACzC,0EAA+C;AAC/C,0EAA+C;AAC/C,4EAAiD;AACjD,yEAA8C;AAC9C,uDAA4B;AAE5B,mEAA4C;AAC5C,+DAAwC;AAE3B,QAAA,QAAQ,GAAG,CAAC,GAAG,SAAS,CAAC,QAAQ,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAC3D,QAAA,WAAW,GAAG,CAAC,GAAG,SAAS,CAAC,WAAW,EAAE,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;AACpE,QAAA,MAAM,GAAG,EAAE,eAAe,EAAE,CAAC,GAAG,SAAS,CAAC,SAAS,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,EAAE,CAAA","sourcesContent":["export * from './quotation/quotation'\nexport * from './quotation/quotation-item'\nexport * from './quotation/quotation-event'\nexport * from './quotation/quotation-rules'\nexport * from './quotation/quotation-service'\nexport * from './quotation/quotation-type'\nexport * from './opportunity/opportunity'\nexport * from './opportunity/opportunity-event'\nexport * from './opportunity/opportunity-rules'\nexport * from './opportunity/opportunity-service'\nexport * from './opportunity/opportunity-type'\nexport * from './sales-read'\n\nimport * as opportunity from './opportunity'\nimport * as quotation from './quotation'\n\nexport const entities = [...quotation.entities, ...opportunity.entities]\nexport const subscribers = [...quotation.subscribers, ...opportunity.subscribers]\nexport const schema = { resolverClasses: [...quotation.resolvers, ...opportunity.resolvers] }\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,gEAAqC;AACrC,qEAA0C;AAC1C,sEAA2C;AAC3C,sEAA2C;AAC3C,wEAA6C;AAC7C,qEAA0C;AAC1C,oEAAyC;AACzC,0EAA+C;AAC/C,0EAA+C;AAC/C,4EAAiD;AACjD,yEAA8C;AAC9C,wEAA6C;AAC7C,8EAAmD;AACnD,gFAAqD;AACrD,6EAAkD;AAClD,uDAA4B;AAE5B,mEAA4C;AAC5C,+DAAwC;AACxC,sEAA+C;AAElC,QAAA,QAAQ,GAAG,CAAC,GAAG,SAAS,CAAC,QAAQ,EAAE,GAAG,WAAW,CAAC,QAAQ,EAAE,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;AACrF,QAAA,WAAW,GAAG,CAAC,GAAG,SAAS,CAAC,WAAW,EAAE,GAAG,WAAW,CAAC,WAAW,EAAE,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;AACjG,QAAA,MAAM,GAAG,EAAE,eAAe,EAAE,CAAC,GAAG,SAAS,CAAC,SAAS,EAAE,GAAG,WAAW,CAAC,SAAS,EAAE,GAAG,YAAY,CAAC,SAAS,CAAC,EAAE,CAAA","sourcesContent":["export * from './quotation/quotation'\nexport * from './quotation/quotation-item'\nexport * from './quotation/quotation-event'\nexport * from './quotation/quotation-rules'\nexport * from './quotation/quotation-service'\nexport * from './quotation/quotation-type'\nexport * from './opportunity/opportunity'\nexport * from './opportunity/opportunity-event'\nexport * from './opportunity/opportunity-rules'\nexport * from './opportunity/opportunity-service'\nexport * from './opportunity/opportunity-type'\nexport * from './sales-product/sales-product'\nexport * from './sales-product/sales-product-rules'\nexport * from './sales-product/sales-product-service'\nexport * from './sales-product/sales-product-type'\nexport * from './sales-read'\n\nimport * as opportunity from './opportunity'\nimport * as quotation from './quotation'\nimport * as salesProduct from './sales-product'\n\nexport const entities = [...quotation.entities, ...opportunity.entities, ...salesProduct.entities]\nexport const subscribers = [...quotation.subscribers, ...opportunity.subscribers, ...salesProduct.subscribers]\nexport const schema = { resolverClasses: [...quotation.resolvers, ...opportunity.resolvers, ...salesProduct.resolvers] }\n"]}
@@ -1,4 +1,5 @@
1
1
  import { User } from '@things-factory/auth-base';
2
+ import { DocumentFile, DocumentFileFormat } from '@things-factory/invoice';
2
3
  import { Domain, ListParam } from '@things-factory/shell';
3
4
  import { Opportunity } from '../opportunity/opportunity';
4
5
  import { Quotation } from './quotation';
@@ -10,8 +11,10 @@ export declare class QuotationQuery {
10
11
  quotations(params: ListParam, context: ResolverContext): Promise<QuotationList>;
11
12
  quotationVersions(number: string, context: ResolverContext): Promise<Quotation[]>;
12
13
  quotationEvents(quotationId: string, context: ResolverContext): Promise<QuotationEvent[]>;
14
+ quotationDocumentFile(id: string, format: DocumentFileFormat, language: string, context: ResolverContext): Promise<DocumentFile>;
13
15
  items(quotation: Quotation): Promise<QuotationItem[]>;
14
16
  taxGroups(quotation: Quotation): Promise<import("@things-factory/invoice").TaxGroup[]>;
17
+ lineSupplyAmount(quotation: Quotation): Promise<number>;
15
18
  opportunity(row: Quotation): Opportunity | Promise<Opportunity>;
16
19
  domain(row: Quotation): Domain | Promise<Domain>;
17
20
  creator(row: Quotation): User | Promise<User>;
@@ -10,6 +10,7 @@ const opportunity_1 = require("../opportunity/opportunity");
10
10
  const quotation_1 = require("./quotation");
11
11
  const quotation_event_1 = require("./quotation-event");
12
12
  const quotation_item_1 = require("./quotation-item");
13
+ const quotation_service_1 = require("./quotation-service");
13
14
  const quotation_type_1 = require("./quotation-type");
14
15
  let QuotationQuery = class QuotationQuery {
15
16
  quotation(id, context) {
@@ -31,12 +32,29 @@ let QuotationQuery = class QuotationQuery {
31
32
  quotationEvents(quotationId, context) {
32
33
  return (0, shell_1.getRepository)(quotation_event_1.QuotationEvent).find({ where: { domain: { id: context.state.domain.id }, quotation: { id: quotationId } }, order: { createdAt: 'ASC' } });
33
34
  }
35
+ /* The quotation as its buyer reads it (ADR-0170 decision 10) - the page to preview and print, or the PDF to download. */
36
+ async quotationDocumentFile(id, format, language, context) {
37
+ const quotation = await (0, quotation_service_1.quotationInDomain)((0, shell_1.getRepository)(quotation_1.Quotation).manager, context.state.domain, id);
38
+ const print = (0, invoice_1.printTranslator)(context, language || quotation.language);
39
+ return (0, invoice_1.documentFileOf)(quotation, format, {
40
+ ...print,
41
+ title: print.t('title.quotation-print'),
42
+ numberLabel: 'field.quotation-number',
43
+ terms: [
44
+ { label: print.t('field.quotation-version'), value: `v${quotation.version}` },
45
+ { label: print.t('field.quotation-valid-until'), value: quotation.validUntil }
46
+ ]
47
+ });
48
+ }
34
49
  async items(quotation) {
35
50
  return quotation.items ?? (0, shell_1.getRepository)(quotation_item_1.QuotationItem).find({ where: { quotation: { id: quotation.id } }, order: { position: 'ASC' } });
36
51
  }
37
52
  async taxGroups(quotation) {
38
53
  return (0, invoice_1.taxGroupsOf)({ ...quotation, items: await this.items(quotation) });
39
54
  }
55
+ async lineSupplyAmount(quotation) {
56
+ return (0, invoice_1.lineSupplyOf)({ ...quotation, items: await this.items(quotation) });
57
+ }
40
58
  opportunity(row) {
41
59
  return row.opportunity ?? (row.opportunityId ? (0, shell_1.getRepository)(opportunity_1.Opportunity).findOneBy({ id: row.opportunityId }) : undefined);
42
60
  }
@@ -87,6 +105,17 @@ tslib_1.__decorate([
87
105
  tslib_1.__metadata("design:paramtypes", [String, Object]),
88
106
  tslib_1.__metadata("design:returntype", void 0)
89
107
  ], QuotationQuery.prototype, "quotationEvents", null);
108
+ tslib_1.__decorate([
109
+ (0, type_graphql_1.Directive)('@privilege(category: "sales", privilege: "query", domainOwnerGranted: true)'),
110
+ (0, type_graphql_1.Query)(type => invoice_1.DocumentFile, { description: 'Prints a quotation as an HTML page or a PDF, in Korean or English - its own language when none is named' }),
111
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
112
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('format', type => invoice_1.DocumentFileFormat, { description: 'An HTML page or a PDF' })),
113
+ tslib_1.__param(2, (0, type_graphql_1.Arg)('language', { nullable: true, description: 'The language of the print, ko or en - the quotation\'s own when empty' })),
114
+ tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
115
+ tslib_1.__metadata("design:type", Function),
116
+ tslib_1.__metadata("design:paramtypes", [String, String, String, Object]),
117
+ tslib_1.__metadata("design:returntype", Promise)
118
+ ], QuotationQuery.prototype, "quotationDocumentFile", null);
90
119
  tslib_1.__decorate([
91
120
  (0, type_graphql_1.FieldResolver)(type => [quotation_item_1.QuotationItem]),
92
121
  tslib_1.__param(0, (0, type_graphql_1.Root)()),
@@ -101,6 +130,13 @@ tslib_1.__decorate([
101
130
  tslib_1.__metadata("design:paramtypes", [quotation_1.Quotation]),
102
131
  tslib_1.__metadata("design:returntype", Promise)
103
132
  ], QuotationQuery.prototype, "taxGroups", null);
133
+ tslib_1.__decorate([
134
+ (0, type_graphql_1.FieldResolver)(type => type_graphql_1.Float, { description: "The lines' supply before the discount of the whole document" }),
135
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
136
+ tslib_1.__metadata("design:type", Function),
137
+ tslib_1.__metadata("design:paramtypes", [quotation_1.Quotation]),
138
+ tslib_1.__metadata("design:returntype", Promise)
139
+ ], QuotationQuery.prototype, "lineSupplyAmount", null);
104
140
  tslib_1.__decorate([
105
141
  (0, type_graphql_1.FieldResolver)(type => opportunity_1.Opportunity, { nullable: true }),
106
142
  tslib_1.__param(0, (0, type_graphql_1.Root)()),
@@ -1 +1 @@
1
- {"version":3,"file":"quotation-query.js","sourceRoot":"","sources":["../../../server/service/quotation/quotation-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { User } from '@things-factory/auth-base'\nimport { DocumentTaxGroup, taxGroupsOf } from '@things-factory/invoice'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, SpeakRefusals } from '@things-factory/shell'\nimport { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\n\nimport { Opportunity } from '../opportunity/opportunity'\nimport { Quotation } from './quotation'\nimport { QuotationEvent } from './quotation-event'\nimport { QuotationItem } from './quotation-item'\nimport { QuotationList } from './quotation-type'\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(Quotation)\nexport class QuotationQuery {\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => Quotation, { nullable: true, description: 'To fetch a quotation' })\n quotation(@Arg('id') id: string, @Ctx() context: ResolverContext) {\n return getRepository(Quotation).findOne({ where: { id, domain: { id: context.state.domain.id } } })\n }\n\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => QuotationList, { description: 'To fetch a page of quotations' })\n async quotations(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<QuotationList> {\n const query = getQueryBuilderFromListParams({\n domain: context.state.domain,\n params,\n repository: getRepository(Quotation),\n searchables: ['number', 'supplierName', 'buyerName', 'notes']\n })\n const [items, total] = await query.getManyAndCount()\n return { items, total }\n }\n\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [Quotation], { description: 'To fetch every version of a quotation number, oldest first' })\n quotationVersions(@Arg('number') number: string, @Ctx() context: ResolverContext) {\n return getRepository(Quotation).find({ where: { domain: { id: context.state.domain.id }, number }, order: { version: 'ASC' } })\n }\n\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [QuotationEvent], { description: 'To fetch what happened to a quotation, oldest first' })\n quotationEvents(@Arg('quotationId') quotationId: string, @Ctx() context: ResolverContext) {\n return getRepository(QuotationEvent).find({ where: { domain: { id: context.state.domain.id }, quotation: { id: quotationId } }, order: { createdAt: 'ASC' } })\n }\n\n @FieldResolver(type => [QuotationItem])\n async items(@Root() quotation: Quotation) {\n return quotation.items ?? getRepository(QuotationItem).find({ where: { quotation: { id: quotation.id } }, order: { position: 'ASC' } })\n }\n\n @FieldResolver(type => [DocumentTaxGroup])\n async taxGroups(@Root() quotation: Quotation) {\n return taxGroupsOf({ ...quotation, items: await this.items(quotation) })\n }\n\n @FieldResolver(type => Opportunity, { nullable: true })\n opportunity(@Root() row: Quotation) {\n return row.opportunity ?? (row.opportunityId ? getRepository(Opportunity).findOneBy({ id: row.opportunityId }) : undefined)\n }\n\n @FieldResolver(type => Domain, { nullable: true })\n domain(@Root() row: Quotation) {\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: Quotation) {\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: Quotation) {\n return row.updater ?? (row.updaterId ? getRepository(User).findOneBy({ id: row.updaterId }) : undefined)\n }\n}\n"]}
1
+ {"version":3,"file":"quotation-query.js","sourceRoot":"","sources":["../../../server/service/quotation/quotation-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { User } from '@things-factory/auth-base'\nimport { DocumentFile, DocumentFileFormat, documentFileOf, DocumentTaxGroup, lineSupplyOf, printTranslator, taxGroupsOf } from '@things-factory/invoice'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, SpeakRefusals } from '@things-factory/shell'\nimport { Arg, Args, Ctx, Directive, FieldResolver, Float, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\n\nimport { Opportunity } from '../opportunity/opportunity'\nimport { Quotation } from './quotation'\nimport { QuotationEvent } from './quotation-event'\nimport { QuotationItem } from './quotation-item'\nimport { quotationInDomain } from './quotation-service'\nimport { QuotationList } from './quotation-type'\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(Quotation)\nexport class QuotationQuery {\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => Quotation, { nullable: true, description: 'To fetch a quotation' })\n quotation(@Arg('id') id: string, @Ctx() context: ResolverContext) {\n return getRepository(Quotation).findOne({ where: { id, domain: { id: context.state.domain.id } } })\n }\n\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => QuotationList, { description: 'To fetch a page of quotations' })\n async quotations(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<QuotationList> {\n const query = getQueryBuilderFromListParams({\n domain: context.state.domain,\n params,\n repository: getRepository(Quotation),\n searchables: ['number', 'supplierName', 'buyerName', 'notes']\n })\n const [items, total] = await query.getManyAndCount()\n return { items, total }\n }\n\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [Quotation], { description: 'To fetch every version of a quotation number, oldest first' })\n quotationVersions(@Arg('number') number: string, @Ctx() context: ResolverContext) {\n return getRepository(Quotation).find({ where: { domain: { id: context.state.domain.id }, number }, order: { version: 'ASC' } })\n }\n\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [QuotationEvent], { description: 'To fetch what happened to a quotation, oldest first' })\n quotationEvents(@Arg('quotationId') quotationId: string, @Ctx() context: ResolverContext) {\n return getRepository(QuotationEvent).find({ where: { domain: { id: context.state.domain.id }, quotation: { id: quotationId } }, order: { createdAt: 'ASC' } })\n }\n\n /* The quotation as its buyer reads it (ADR-0170 decision 10) - the page to preview and print, or the PDF to download. */\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => DocumentFile, { description: 'Prints a quotation as an HTML page or a PDF, in Korean or English - its own language when none is named' })\n async quotationDocumentFile(\n @Arg('id') id: string,\n @Arg('format', type => DocumentFileFormat, { description: 'An HTML page or a PDF' }) format: DocumentFileFormat,\n @Arg('language', { nullable: true, description: 'The language of the print, ko or en - the quotation\\'s own when empty' }) language: string,\n @Ctx() context: ResolverContext\n ): Promise<DocumentFile> {\n const quotation = await quotationInDomain(getRepository(Quotation).manager, context.state.domain, id)\n const print = printTranslator(context, language || quotation.language)\n return documentFileOf(quotation, format, {\n ...print,\n title: print.t('title.quotation-print'),\n numberLabel: 'field.quotation-number',\n terms: [\n { label: print.t('field.quotation-version'), value: `v${quotation.version}` },\n { label: print.t('field.quotation-valid-until'), value: quotation.validUntil }\n ]\n })\n }\n\n @FieldResolver(type => [QuotationItem])\n async items(@Root() quotation: Quotation) {\n return quotation.items ?? getRepository(QuotationItem).find({ where: { quotation: { id: quotation.id } }, order: { position: 'ASC' } })\n }\n\n @FieldResolver(type => [DocumentTaxGroup])\n async taxGroups(@Root() quotation: Quotation) {\n return taxGroupsOf({ ...quotation, items: await this.items(quotation) })\n }\n\n @FieldResolver(type => Float, { description: \"The lines' supply before the discount of the whole document\" })\n async lineSupplyAmount(@Root() quotation: Quotation) {\n return lineSupplyOf({ ...quotation, items: await this.items(quotation) })\n }\n\n @FieldResolver(type => Opportunity, { nullable: true })\n opportunity(@Root() row: Quotation) {\n return row.opportunity ?? (row.opportunityId ? getRepository(Opportunity).findOneBy({ id: row.opportunityId }) : undefined)\n }\n\n @FieldResolver(type => Domain, { nullable: true })\n domain(@Root() row: Quotation) {\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: Quotation) {\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: Quotation) {\n return row.updater ?? (row.updaterId ? getRepository(User).findOneBy({ id: row.updaterId }) : undefined)\n }\n}\n"]}
@@ -14,6 +14,7 @@ export declare function snapshotOf(quotation: Quotation): {
14
14
  position: number;
15
15
  description: string;
16
16
  quantity: number;
17
+ unit: string;
17
18
  unitPrice: number;
18
19
  discount: number;
19
20
  taxKind: import("@things-factory/invoice").TaxKind;
@@ -40,8 +40,8 @@ async function saveQuotation(tx, domain, user, input, id) {
40
40
  const opportunity = input.opportunityId ? await tx.getRepository(opportunity_1.Opportunity).findOne({ where: { id: input.opportunityId, domain: { id: domain.id } } }) : null;
41
41
  if (input.opportunityId && !opportunity)
42
42
  throw new shell_1.Refusal('quotation-opportunity-invalid', {}, 'Choose an opportunity of this domain');
43
- const { items, supplyAmount, taxAmount, totalAmount } = (0, invoice_1.calculateDocument)(input.items, header.currency);
44
- const quotation = await repository.save(repository.create({ ...old, ...header, version, validUntil: input.validUntil, opportunity, supplyAmount, taxAmount, totalAmount, domain, creator: old?.creator ?? user, updater: user, items: undefined }));
43
+ const { items, discountAmount, supplyAmount, taxAmount, totalAmount } = (0, invoice_1.calculateDocument)(input.items, header.currency, false, input.discountAmount);
44
+ const quotation = await repository.save(repository.create({ ...old, ...header, version, validUntil: input.validUntil, opportunity, discountAmount, supplyAmount, taxAmount, totalAmount, domain, creator: old?.creator ?? user, updater: user, items: undefined }));
45
45
  const lines = tx.getRepository(quotation_item_1.QuotationItem);
46
46
  if (old)
47
47
  await lines.softDelete({ quotation: { id: quotation.id } });
@@ -104,13 +104,14 @@ function recordQuotationEvent(tx, domain, user, quotation, action, reason) {
104
104
  }
105
105
  /** The quotation as printed. */
106
106
  function snapshotOf(quotation) {
107
- const keys = ['id', ...invoice_1.HEADER_KEYS, 'version', 'status', 'validUntil', 'opportunityId', 'supplyAmount', 'taxAmount', 'totalAmount', 'taxRounding', 'currencyDigits', 'outcomeReason'];
107
+ const keys = ['id', ...invoice_1.HEADER_KEYS, 'version', 'status', 'validUntil', 'opportunityId', 'discountAmount', 'supplyAmount', 'taxAmount', 'totalAmount', 'taxRounding', 'currencyDigits', 'outcomeReason'];
108
108
  return {
109
109
  ...Object.fromEntries(keys.map(key => [key, quotation[key] ?? null])),
110
- items: quotation.items.map(({ position, description, quantity, unitPrice, discount, taxKind, taxRate, supplyAmount }) => ({
110
+ items: quotation.items.map(({ position, description, quantity, unit, unitPrice, discount, taxKind, taxRate, supplyAmount }) => ({
111
111
  position,
112
112
  description,
113
113
  quantity,
114
+ unit: unit ?? null,
114
115
  unitPrice,
115
116
  discount,
116
117
  taxKind,
@@ -1 +1 @@
1
- {"version":3,"file":"quotation-service.js","sourceRoot":"","sources":["../../../server/service/quotation/quotation-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { calculateDocument, currencyDigits, HEADER_KEYS, lockDocumentDomain, normalizedHeader, TAX_ROUNDING, validDay } from '@things-factory/invoice'\nimport { Domain, getRepository, Refusal, calendarDay } from '@things-factory/shell'\nimport { EntityManager } from 'typeorm'\n\nimport { Opportunity } from '../opportunity/opportunity'\nimport { recordSalesEvent } from '../sales-event'\nimport { Quotation, QuotationStatus } from './quotation'\nimport { QuotationEvent } from './quotation-event'\nimport { QuotationItem } from './quotation-item'\nimport { QuotationAction, quotationTransition, revisable } from './quotation-rules'\nimport { NewQuotation } from './quotation-type'\n\nexport async function quotationInDomain(tx: EntityManager, domain: Domain, id: string) {\n const quotation = await tx.getRepository(Quotation).findOne({ where: { id, domain: { id: domain.id } }, relations: ['items', 'creator'] })\n if (!quotation) throw new Refusal('quotation-not-found', {}, 'Quotation not found')\n quotation.items.sort((a, b) => a.position - b.position)\n return quotation\n}\n\nexport async function saveQuotation(tx: EntityManager, domain: Domain, user: any, input: NewQuotation, id?: string) {\n await lockDocumentDomain(tx, domain)\n const old = id ? await quotationInDomain(tx, domain, id) : undefined\n if (old && old.status !== QuotationStatus.DRAFT) throw new Refusal('quotation-draft-required', {}, 'Revise a sent quotation to change it')\n\n const header = normalizedHeader(input)\n if (!validDay(input.validUntil)) throw new Refusal('quotation-valid-until', {}, 'A valid last day is required')\n /* A revision answers the quotation it revises: it keeps the number. */\n if (old && old.version > 1 && header.number !== old.number) throw new Refusal('quotation-revision-number', {}, 'A revision keeps its quotation number')\n\n const repository = tx.getRepository(Quotation)\n const version = old?.version ?? 1\n const duplicate = await repository.findOne({ where: { domain: { id: domain.id }, number: header.number, version } })\n if (duplicate && duplicate.id !== id) throw new Refusal('quotation-number-duplicate', {}, 'Quotation number already exists')\n\n const opportunity = input.opportunityId ? await tx.getRepository(Opportunity).findOne({ where: { id: input.opportunityId, domain: { id: domain.id } } }) : null\n if (input.opportunityId && !opportunity) throw new Refusal('quotation-opportunity-invalid', {}, 'Choose an opportunity of this domain')\n\n const { items, supplyAmount, taxAmount, totalAmount } = calculateDocument(input.items, header.currency)\n const quotation = await repository.save(\n repository.create({ ...old, ...header, version, validUntil: input.validUntil, opportunity, supplyAmount, taxAmount, totalAmount, domain, creator: old?.creator ?? user, updater: user, items: undefined })\n )\n const lines = tx.getRepository(QuotationItem)\n if (old) await lines.softDelete({ quotation: { id: quotation.id } })\n await lines.save(items.map(({ receivedTaxAmount, ...item }) => lines.create({ ...item, quotation, domain, creator: user, updater: user })))\n\n const saved = await quotationInDomain(tx, domain, quotation.id)\n await recordQuotationEvent(tx, domain, user, saved, old ? 'UPDATED' : 'CREATED')\n return saved\n}\n\nexport async function transitionQuotation(tx: EntityManager, domain: Domain, user: any, id: string, action: QuotationAction, reason?: string) {\n await lockDocumentDomain(tx, domain)\n const quotation = await quotationInDomain(tx, domain, id)\n const next = quotationTransition(quotation.status, action, quotation.validUntil, calendarDay(domain.timezone))\n if (!next) throw new Refusal('quotation-transition-invalid', {}, 'The quotation status or validity does not allow this')\n if (next === QuotationStatus.REJECTED && !reason?.trim()) throw new Refusal('quotation-reason-required', {}, 'Say why the buyer declined')\n if (next === QuotationStatus.SENT) {\n if (!quotation.issueDate) throw new Refusal('quotation-issue-date-required', {}, 'A quotation is sent with its issue date')\n /* What the amounts were reckoned with stays on the quotation; a later rule never recomputes them. */\n quotation.taxRounding = TAX_ROUNDING\n quotation.currencyDigits = currencyDigits(quotation.currency)\n }\n quotation.status = next\n if (next === QuotationStatus.REJECTED) quotation.outcomeReason = reason!.trim()\n quotation.updater = user\n const { items, ...head } = quotation\n await tx.getRepository(Quotation).save(head)\n await recordQuotationEvent(tx, domain, user, quotation, action, reason)\n return quotationInDomain(tx, domain, id)\n}\n\n/** A new draft version of a sent quotation, with the same number; the version it replaces is superseded. */\nexport async function reviseQuotation(tx: EntityManager, domain: Domain, user: any, id: string) {\n await lockDocumentDomain(tx, domain)\n const old = await quotationInDomain(tx, domain, id)\n if (!revisable(old.status)) throw new Refusal('quotation-revision-invalid', {}, 'Only a sent quotation nobody accepted can be revised')\n const versions = await tx.getRepository(Quotation).find({ where: { domain: { id: domain.id }, number: old.number } })\n if (old.version !== Math.max(...versions.map(one => one.version))) throw new Refusal('quotation-latest-required', {}, 'Revise the latest version')\n\n const repository = tx.getRepository(Quotation)\n const { id: _id, items, createdAt, updatedAt, creator, updater, status, taxRounding, currencyDigits: digits, outcomeReason, opportunityId, ...document } = old\n /* A revision answers the same opportunity as the version it replaces. */\n const opportunity = opportunityId ? ({ id: opportunityId } as Opportunity) : null\n const revision = await repository.save(repository.create({ ...document, opportunity, version: old.version + 1, status: QuotationStatus.DRAFT, domain, creator: user, updater: user }))\n const lines = tx.getRepository(QuotationItem)\n await lines.save(\n items.map(({ id: _line, quotation: _parent, quotationId, createdAt, updatedAt, deletedAt, creator, updater, ...line }) =>\n lines.create({ ...line, quotation: revision, domain, creator: user, updater: user })\n )\n )\n\n old.status = QuotationStatus.SUPERSEDED\n old.updater = user\n const { items: _items, ...head } = old\n await repository.save(head)\n await recordQuotationEvent(tx, domain, user, old, 'SUPERSEDED')\n const saved = await quotationInDomain(tx, domain, revision.id)\n await recordQuotationEvent(tx, domain, user, saved, 'REVISED')\n return saved\n}\n\nfunction recordQuotationEvent(tx: EntityManager, domain: Domain, user: any, quotation: Quotation, action: string, reason?: string) {\n return recordSalesEvent(tx, QuotationEvent, { quotation }, { domain, user, action, reason, snapshot: snapshotOf(quotation) })\n}\n\n/** The quotation as printed. */\nexport function snapshotOf(quotation: Quotation) {\n const keys = ['id', ...HEADER_KEYS, 'version', 'status', 'validUntil', 'opportunityId', 'supplyAmount', 'taxAmount', 'totalAmount', 'taxRounding', 'currencyDigits', 'outcomeReason']\n return {\n ...Object.fromEntries(keys.map(key => [key, quotation[key] ?? null])),\n items: quotation.items.map(({ position, description, quantity, unitPrice, discount, taxKind, taxRate, supplyAmount }) => ({\n position,\n description,\n quantity,\n unitPrice,\n discount,\n taxKind,\n taxRate,\n supplyAmount\n }))\n }\n}\n\n/** The quotations that answer an opportunity, every version, by number then version. */\nexport function quotationsOfOpportunity(tx: EntityManager | undefined, domain: Domain, opportunityId: string) {\n const repository = tx ? tx.getRepository(Quotation) : getRepository(Quotation)\n return repository.find({ where: { domain: { id: domain.id }, opportunity: { id: opportunityId } }, order: { number: 'ASC', version: 'ASC' } })\n}\n"]}
1
+ {"version":3,"file":"quotation-service.js","sourceRoot":"","sources":["../../../server/service/quotation/quotation-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { calculateDocument, currencyDigits, HEADER_KEYS, lockDocumentDomain, normalizedHeader, TAX_ROUNDING, validDay } from '@things-factory/invoice'\nimport { Domain, getRepository, Refusal, calendarDay } from '@things-factory/shell'\nimport { EntityManager } from 'typeorm'\n\nimport { Opportunity } from '../opportunity/opportunity'\nimport { recordSalesEvent } from '../sales-event'\nimport { Quotation, QuotationStatus } from './quotation'\nimport { QuotationEvent } from './quotation-event'\nimport { QuotationItem } from './quotation-item'\nimport { QuotationAction, quotationTransition, revisable } from './quotation-rules'\nimport { NewQuotation } from './quotation-type'\n\nexport async function quotationInDomain(tx: EntityManager, domain: Domain, id: string) {\n const quotation = await tx.getRepository(Quotation).findOne({ where: { id, domain: { id: domain.id } }, relations: ['items', 'creator'] })\n if (!quotation) throw new Refusal('quotation-not-found', {}, 'Quotation not found')\n quotation.items.sort((a, b) => a.position - b.position)\n return quotation\n}\n\nexport async function saveQuotation(tx: EntityManager, domain: Domain, user: any, input: NewQuotation, id?: string) {\n await lockDocumentDomain(tx, domain)\n const old = id ? await quotationInDomain(tx, domain, id) : undefined\n if (old && old.status !== QuotationStatus.DRAFT) throw new Refusal('quotation-draft-required', {}, 'Revise a sent quotation to change it')\n\n const header = normalizedHeader(input)\n if (!validDay(input.validUntil)) throw new Refusal('quotation-valid-until', {}, 'A valid last day is required')\n /* A revision answers the quotation it revises: it keeps the number. */\n if (old && old.version > 1 && header.number !== old.number) throw new Refusal('quotation-revision-number', {}, 'A revision keeps its quotation number')\n\n const repository = tx.getRepository(Quotation)\n const version = old?.version ?? 1\n const duplicate = await repository.findOne({ where: { domain: { id: domain.id }, number: header.number, version } })\n if (duplicate && duplicate.id !== id) throw new Refusal('quotation-number-duplicate', {}, 'Quotation number already exists')\n\n const opportunity = input.opportunityId ? await tx.getRepository(Opportunity).findOne({ where: { id: input.opportunityId, domain: { id: domain.id } } }) : null\n if (input.opportunityId && !opportunity) throw new Refusal('quotation-opportunity-invalid', {}, 'Choose an opportunity of this domain')\n\n const { items, discountAmount, supplyAmount, taxAmount, totalAmount } = calculateDocument(input.items, header.currency, false, input.discountAmount)\n const quotation = await repository.save(\n repository.create({ ...old, ...header, version, validUntil: input.validUntil, opportunity, discountAmount, supplyAmount, taxAmount, totalAmount, domain, creator: old?.creator ?? user, updater: user, items: undefined })\n )\n const lines = tx.getRepository(QuotationItem)\n if (old) await lines.softDelete({ quotation: { id: quotation.id } })\n await lines.save(items.map(({ receivedTaxAmount, ...item }) => lines.create({ ...item, quotation, domain, creator: user, updater: user })))\n\n const saved = await quotationInDomain(tx, domain, quotation.id)\n await recordQuotationEvent(tx, domain, user, saved, old ? 'UPDATED' : 'CREATED')\n return saved\n}\n\nexport async function transitionQuotation(tx: EntityManager, domain: Domain, user: any, id: string, action: QuotationAction, reason?: string) {\n await lockDocumentDomain(tx, domain)\n const quotation = await quotationInDomain(tx, domain, id)\n const next = quotationTransition(quotation.status, action, quotation.validUntil, calendarDay(domain.timezone))\n if (!next) throw new Refusal('quotation-transition-invalid', {}, 'The quotation status or validity does not allow this')\n if (next === QuotationStatus.REJECTED && !reason?.trim()) throw new Refusal('quotation-reason-required', {}, 'Say why the buyer declined')\n if (next === QuotationStatus.SENT) {\n if (!quotation.issueDate) throw new Refusal('quotation-issue-date-required', {}, 'A quotation is sent with its issue date')\n /* What the amounts were reckoned with stays on the quotation; a later rule never recomputes them. */\n quotation.taxRounding = TAX_ROUNDING\n quotation.currencyDigits = currencyDigits(quotation.currency)\n }\n quotation.status = next\n if (next === QuotationStatus.REJECTED) quotation.outcomeReason = reason!.trim()\n quotation.updater = user\n const { items, ...head } = quotation\n await tx.getRepository(Quotation).save(head)\n await recordQuotationEvent(tx, domain, user, quotation, action, reason)\n return quotationInDomain(tx, domain, id)\n}\n\n/** A new draft version of a sent quotation, with the same number; the version it replaces is superseded. */\nexport async function reviseQuotation(tx: EntityManager, domain: Domain, user: any, id: string) {\n await lockDocumentDomain(tx, domain)\n const old = await quotationInDomain(tx, domain, id)\n if (!revisable(old.status)) throw new Refusal('quotation-revision-invalid', {}, 'Only a sent quotation nobody accepted can be revised')\n const versions = await tx.getRepository(Quotation).find({ where: { domain: { id: domain.id }, number: old.number } })\n if (old.version !== Math.max(...versions.map(one => one.version))) throw new Refusal('quotation-latest-required', {}, 'Revise the latest version')\n\n const repository = tx.getRepository(Quotation)\n const { id: _id, items, createdAt, updatedAt, creator, updater, status, taxRounding, currencyDigits: digits, outcomeReason, opportunityId, ...document } = old\n /* A revision answers the same opportunity as the version it replaces. */\n const opportunity = opportunityId ? ({ id: opportunityId } as Opportunity) : null\n const revision = await repository.save(repository.create({ ...document, opportunity, version: old.version + 1, status: QuotationStatus.DRAFT, domain, creator: user, updater: user }))\n const lines = tx.getRepository(QuotationItem)\n await lines.save(\n items.map(({ id: _line, quotation: _parent, quotationId, createdAt, updatedAt, deletedAt, creator, updater, ...line }) =>\n lines.create({ ...line, quotation: revision, domain, creator: user, updater: user })\n )\n )\n\n old.status = QuotationStatus.SUPERSEDED\n old.updater = user\n const { items: _items, ...head } = old\n await repository.save(head)\n await recordQuotationEvent(tx, domain, user, old, 'SUPERSEDED')\n const saved = await quotationInDomain(tx, domain, revision.id)\n await recordQuotationEvent(tx, domain, user, saved, 'REVISED')\n return saved\n}\n\nfunction recordQuotationEvent(tx: EntityManager, domain: Domain, user: any, quotation: Quotation, action: string, reason?: string) {\n return recordSalesEvent(tx, QuotationEvent, { quotation }, { domain, user, action, reason, snapshot: snapshotOf(quotation) })\n}\n\n/** The quotation as printed. */\nexport function snapshotOf(quotation: Quotation) {\n const keys = ['id', ...HEADER_KEYS, 'version', 'status', 'validUntil', 'opportunityId', 'discountAmount', 'supplyAmount', 'taxAmount', 'totalAmount', 'taxRounding', 'currencyDigits', 'outcomeReason']\n return {\n ...Object.fromEntries(keys.map(key => [key, quotation[key] ?? null])),\n items: quotation.items.map(({ position, description, quantity, unit, unitPrice, discount, taxKind, taxRate, supplyAmount }) => ({\n position,\n description,\n quantity,\n unit: unit ?? null,\n unitPrice,\n discount,\n taxKind,\n taxRate,\n supplyAmount\n }))\n }\n}\n\n/** The quotations that answer an opportunity, every version, by number then version. */\nexport function quotationsOfOpportunity(tx: EntityManager | undefined, domain: Domain, opportunityId: string) {\n const repository = tx ? tx.getRepository(Quotation) : getRepository(Quotation)\n return repository.find({ where: { domain: { id: domain.id }, opportunity: { id: opportunityId } }, order: { number: 'ASC', version: 'ASC' } })\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import { SalesProduct } from './sales-product';
2
+ import { SalesProductMutation } from './sales-product-mutation';
3
+ import { SalesProductQuery } from './sales-product-query';
4
+ export declare const entities: (typeof SalesProduct)[];
5
+ export declare const resolvers: (typeof SalesProductMutation | typeof SalesProductQuery)[];
6
+ export declare const subscribers: any[];
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.subscribers = exports.resolvers = exports.entities = void 0;
4
+ const sales_product_1 = require("./sales-product");
5
+ const sales_product_mutation_1 = require("./sales-product-mutation");
6
+ const sales_product_query_1 = require("./sales-product-query");
7
+ exports.entities = [sales_product_1.SalesProduct];
8
+ exports.resolvers = [sales_product_query_1.SalesProductQuery, sales_product_mutation_1.SalesProductMutation];
9
+ exports.subscribers = [];
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/sales-product/index.ts"],"names":[],"mappings":";;;AAAA,mDAA8C;AAC9C,qEAA+D;AAC/D,+DAAyD;AAE5C,QAAA,QAAQ,GAAG,CAAC,4BAAY,CAAC,CAAA;AACzB,QAAA,SAAS,GAAG,CAAC,uCAAiB,EAAE,6CAAoB,CAAC,CAAA;AACrD,QAAA,WAAW,GAAG,EAAE,CAAA","sourcesContent":["import { SalesProduct } from './sales-product'\nimport { SalesProductMutation } from './sales-product-mutation'\nimport { SalesProductQuery } from './sales-product-query'\n\nexport const entities = [SalesProduct]\nexport const resolvers = [SalesProductQuery, SalesProductMutation]\nexport const subscribers = []\n"]}
@@ -0,0 +1,6 @@
1
+ import { SalesProduct } from './sales-product';
2
+ import { SalesProductPatch } from './sales-product-type';
3
+ export declare class SalesProductMutation {
4
+ updateMultipleSalesProduct(patches: SalesProductPatch[], context: ResolverContext): Promise<SalesProduct[]>;
5
+ deleteSalesProducts(ids: string[], context: ResolverContext): Promise<boolean>;
6
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SalesProductMutation = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const shell_1 = require("@things-factory/shell");
6
+ const type_graphql_1 = require("type-graphql");
7
+ const sales_product_1 = require("./sales-product");
8
+ const sales_product_service_1 = require("./sales-product-service");
9
+ const sales_product_type_1 = require("./sales-product-type");
10
+ let SalesProductMutation = class SalesProductMutation {
11
+ updateMultipleSalesProduct(patches, context) {
12
+ const { tx, domain, user } = context.state;
13
+ return (0, sales_product_service_1.saveSalesProducts)(tx, domain, user, patches);
14
+ }
15
+ async deleteSalesProducts(ids, context) {
16
+ const { tx, domain, user } = context.state;
17
+ await (0, sales_product_service_1.saveSalesProducts)(tx, domain, user, ids.map(id => ({ id, cuFlag: '-' })));
18
+ return true;
19
+ }
20
+ };
21
+ exports.SalesProductMutation = SalesProductMutation;
22
+ tslib_1.__decorate([
23
+ (0, type_graphql_1.Directive)('@transaction'),
24
+ (0, type_graphql_1.Directive)('@privilege(category: "sales", privilege: "mutation", domainOwnerGranted: true)'),
25
+ (0, type_graphql_1.Mutation)(type => [sales_product_1.SalesProduct], { description: 'To save the product grid - new, changed and deleted rows together' }),
26
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('patches', type => [sales_product_type_1.SalesProductPatch])),
27
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
28
+ tslib_1.__metadata("design:type", Function),
29
+ tslib_1.__metadata("design:paramtypes", [Array, Object]),
30
+ tslib_1.__metadata("design:returntype", void 0)
31
+ ], SalesProductMutation.prototype, "updateMultipleSalesProduct", null);
32
+ tslib_1.__decorate([
33
+ (0, type_graphql_1.Directive)('@transaction'),
34
+ (0, type_graphql_1.Directive)('@privilege(category: "sales", privilege: "mutation", domainOwnerGranted: true)'),
35
+ (0, type_graphql_1.Mutation)(type => Boolean, { description: 'To delete sales products; quotation lines written from them keep what they copied' }),
36
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('ids', type => [String])),
37
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
38
+ tslib_1.__metadata("design:type", Function),
39
+ tslib_1.__metadata("design:paramtypes", [Array, Object]),
40
+ tslib_1.__metadata("design:returntype", Promise)
41
+ ], SalesProductMutation.prototype, "deleteSalesProducts", null);
42
+ exports.SalesProductMutation = SalesProductMutation = tslib_1.__decorate([
43
+ (0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals),
44
+ (0, type_graphql_1.Resolver)(sales_product_1.SalesProduct)
45
+ ], SalesProductMutation);
46
+ //# sourceMappingURL=sales-product-mutation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sales-product-mutation.js","sourceRoot":"","sources":["../../../server/service/sales-product/sales-product-mutation.ts"],"names":[],"mappings":";;;;AAAA,iDAAqD;AACrD,+CAAqF;AAErF,mDAA8C;AAC9C,mEAA2D;AAC3D,6DAAwD;AAIjD,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAI/B,0BAA0B,CAA8C,OAA4B,EAAS,OAAwB;QACnI,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,OAAO,IAAA,yCAAiB,EAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IACrD,CAAC;IAKK,AAAN,KAAK,CAAC,mBAAmB,CAA+B,GAAa,EAAS,OAAwB;QACpG,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,MAAM,IAAA,yCAAiB,EACrB,EAAE,EACF,MAAM,EACN,IAAI,EACJ,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CACrC,CAAA;QACD,OAAO,IAAI,CAAA;IACb,CAAC;CACF,CAAA;AAtBY,oDAAoB;AAI/B;IAHC,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,gFAAgF,CAAC;IAC3F,IAAA,uBAAQ,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,4BAAY,CAAC,EAAE,EAAE,WAAW,EAAE,mEAAmE,EAAE,CAAC;IAC3F,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,sCAAiB,CAAC,CAAC,CAAA;IAAgC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;sEAG3G;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,gFAAgF,CAAC;IAC3F,IAAA,uBAAQ,EAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,mFAAmF,EAAE,CAAC;IACrG,mBAAA,IAAA,kBAAG,EAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAAiB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;+DAS5E;+BArBU,oBAAoB;IAFhC,IAAA,4BAAa,EAAC,qBAAa,CAAC;IAC5B,IAAA,uBAAQ,EAAC,4BAAY,CAAC;GACV,oBAAoB,CAsBhC","sourcesContent":["import { SpeakRefusals } from '@things-factory/shell'\nimport { Arg, Ctx, Directive, Mutation, Resolver, UseMiddleware } from 'type-graphql'\n\nimport { SalesProduct } from './sales-product'\nimport { saveSalesProducts } from './sales-product-service'\nimport { SalesProductPatch } from './sales-product-type'\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(SalesProduct)\nexport class SalesProductMutation {\n @Directive('@transaction')\n @Directive('@privilege(category: \"sales\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(type => [SalesProduct], { description: 'To save the product grid - new, changed and deleted rows together' })\n updateMultipleSalesProduct(@Arg('patches', type => [SalesProductPatch]) patches: SalesProductPatch[], @Ctx() context: ResolverContext) {\n const { tx, domain, user } = context.state\n return saveSalesProducts(tx, domain, user, patches)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"sales\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(type => Boolean, { description: 'To delete sales products; quotation lines written from them keep what they copied' })\n async deleteSalesProducts(@Arg('ids', type => [String]) ids: string[], @Ctx() context: ResolverContext) {\n const { tx, domain, user } = context.state\n await saveSalesProducts(\n tx,\n domain,\n user,\n ids.map(id => ({ id, cuFlag: '-' }))\n )\n return true\n }\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { User } from '@things-factory/auth-base';
2
+ import { Domain, ListParam } from '@things-factory/shell';
3
+ import { SalesProduct } from './sales-product';
4
+ import { SalesProductList } from './sales-product-type';
5
+ export declare class SalesProductQuery {
6
+ salesProduct(id: string, context: ResolverContext): Promise<SalesProduct>;
7
+ salesProducts(params: ListParam, context: ResolverContext): Promise<SalesProductList>;
8
+ domain(row: SalesProduct): Domain | Promise<Domain>;
9
+ creator(row: SalesProduct): User | Promise<User>;
10
+ updater(row: SalesProduct): User | Promise<User>;
11
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SalesProductQuery = 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 sales_product_1 = require("./sales-product");
9
+ const sales_product_type_1 = require("./sales-product-type");
10
+ let SalesProductQuery = class SalesProductQuery {
11
+ salesProduct(id, context) {
12
+ return (0, shell_1.getRepository)(sales_product_1.SalesProduct).findOne({ where: { id, domain: { id: context.state.domain.id } } });
13
+ }
14
+ async salesProducts(params, context) {
15
+ const query = (0, shell_1.getQueryBuilderFromListParams)({
16
+ domain: context.state.domain,
17
+ params,
18
+ repository: (0, shell_1.getRepository)(sales_product_1.SalesProduct),
19
+ searchables: ['code', 'name', 'grade', 'spec', 'description']
20
+ });
21
+ const [items, total] = await query.getManyAndCount();
22
+ return { items, total };
23
+ }
24
+ domain(row) {
25
+ return row.domain ?? (row.domainId ? (0, shell_1.getRepository)(shell_1.Domain).findOneBy({ id: row.domainId }) : undefined);
26
+ }
27
+ creator(row) {
28
+ return row.creator ?? (row.creatorId ? (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: row.creatorId }) : undefined);
29
+ }
30
+ updater(row) {
31
+ return row.updater ?? (row.updaterId ? (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: row.updaterId }) : undefined);
32
+ }
33
+ };
34
+ exports.SalesProductQuery = SalesProductQuery;
35
+ tslib_1.__decorate([
36
+ (0, type_graphql_1.Directive)('@privilege(category: "sales", privilege: "query", domainOwnerGranted: true)'),
37
+ (0, type_graphql_1.Query)(type => sales_product_1.SalesProduct, { nullable: true, description: 'To fetch a sales product' }),
38
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
39
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
40
+ tslib_1.__metadata("design:type", Function),
41
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
42
+ tslib_1.__metadata("design:returntype", void 0)
43
+ ], SalesProductQuery.prototype, "salesProduct", null);
44
+ tslib_1.__decorate([
45
+ (0, type_graphql_1.Directive)('@privilege(category: "sales", privilege: "query", domainOwnerGranted: true)'),
46
+ (0, type_graphql_1.Query)(type => sales_product_type_1.SalesProductList, { description: 'To fetch a page of sales products' }),
47
+ tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
48
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
49
+ tslib_1.__metadata("design:type", Function),
50
+ tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
51
+ tslib_1.__metadata("design:returntype", Promise)
52
+ ], SalesProductQuery.prototype, "salesProducts", null);
53
+ tslib_1.__decorate([
54
+ (0, type_graphql_1.FieldResolver)(type => shell_1.Domain, { nullable: true }),
55
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
56
+ tslib_1.__metadata("design:type", Function),
57
+ tslib_1.__metadata("design:paramtypes", [sales_product_1.SalesProduct]),
58
+ tslib_1.__metadata("design:returntype", void 0)
59
+ ], SalesProductQuery.prototype, "domain", null);
60
+ tslib_1.__decorate([
61
+ (0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true }),
62
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
63
+ tslib_1.__metadata("design:type", Function),
64
+ tslib_1.__metadata("design:paramtypes", [sales_product_1.SalesProduct]),
65
+ tslib_1.__metadata("design:returntype", void 0)
66
+ ], SalesProductQuery.prototype, "creator", null);
67
+ tslib_1.__decorate([
68
+ (0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true }),
69
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
70
+ tslib_1.__metadata("design:type", Function),
71
+ tslib_1.__metadata("design:paramtypes", [sales_product_1.SalesProduct]),
72
+ tslib_1.__metadata("design:returntype", void 0)
73
+ ], SalesProductQuery.prototype, "updater", null);
74
+ exports.SalesProductQuery = SalesProductQuery = tslib_1.__decorate([
75
+ (0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals),
76
+ (0, type_graphql_1.Resolver)(sales_product_1.SalesProduct)
77
+ ], SalesProductQuery);
78
+ //# sourceMappingURL=sales-product-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sales-product-query.js","sourceRoot":"","sources":["../../../server/service/sales-product/sales-product-query.ts"],"names":[],"mappings":";;;;AAAA,yDAAgD;AAChD,iDAAsH;AACtH,+CAA6G;AAE7G,mDAA8C;AAC9C,6DAAuD;AAIhD,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAG5B,YAAY,CAAY,EAAU,EAAS,OAAwB;QACjE,OAAO,IAAA,qBAAa,EAAC,4BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;IACxG,CAAC;IAIK,AAAN,KAAK,CAAC,aAAa,CAA0B,MAAiB,EAAS,OAAwB;QAC7F,MAAM,KAAK,GAAG,IAAA,qCAA6B,EAAC;YAC1C,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;YAC5B,MAAM;YACN,UAAU,EAAE,IAAA,qBAAa,EAAC,4BAAY,CAAC;YACvC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC;SAC9D,CAAC,CAAA;QACF,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC,eAAe,EAAE,CAAA;QACpD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;IAGD,MAAM,CAAS,GAAiB;QAC9B,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,GAAiB;QAC/B,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,GAAiB;QAC/B,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;AAlCY,8CAAiB;AAG5B;IAFC,IAAA,wBAAS,EAAC,6EAA6E,CAAC;IACxF,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,4BAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,0BAA0B,EAAE,CAAC;IAC3E,mBAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IAAc,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;qDAEzC;AAIK;IAFL,IAAA,wBAAS,EAAC,6EAA6E,CAAC;IACxF,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,qCAAgB,EAAE,EAAE,WAAW,EAAE,mCAAmC,EAAE,CAAC;IACjE,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IAAqB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAjB,iBAAS;;sDAS7D;AAGD;IADC,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1C,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAM,4BAAY;;+CAE/B;AAGD;IADC,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACvC,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAM,4BAAY;;gDAEhC;AAGD;IADC,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACvC,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAM,4BAAY;;gDAEhC;4BAjCU,iBAAiB;IAF7B,IAAA,4BAAa,EAAC,qBAAa,CAAC;IAC5B,IAAA,uBAAQ,EAAC,4BAAY,CAAC;GACV,iBAAiB,CAkC7B","sourcesContent":["import { User } from '@things-factory/auth-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, SpeakRefusals } from '@things-factory/shell'\nimport { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\n\nimport { SalesProduct } from './sales-product'\nimport { SalesProductList } from './sales-product-type'\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(SalesProduct)\nexport class SalesProductQuery {\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => SalesProduct, { nullable: true, description: 'To fetch a sales product' })\n salesProduct(@Arg('id') id: string, @Ctx() context: ResolverContext) {\n return getRepository(SalesProduct).findOne({ where: { id, domain: { id: context.state.domain.id } } })\n }\n\n @Directive('@privilege(category: \"sales\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => SalesProductList, { description: 'To fetch a page of sales products' })\n async salesProducts(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<SalesProductList> {\n const query = getQueryBuilderFromListParams({\n domain: context.state.domain,\n params,\n repository: getRepository(SalesProduct),\n searchables: ['code', 'name', 'grade', 'spec', 'description']\n })\n const [items, total] = await query.getManyAndCount()\n return { items, total }\n }\n\n @FieldResolver(type => Domain, { nullable: true })\n domain(@Root() row: SalesProduct) {\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: SalesProduct) {\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: SalesProduct) {\n return row.updater ?? (row.updaterId ? getRepository(User).findOneBy({ id: row.updaterId }) : undefined)\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ export declare enum SalesProductKind {
2
+ GOODS = "GOODS",
3
+ SERVICE = "SERVICE",
4
+ LABOR = "LABOR"
5
+ }
6
+ /** The unit a product is sold in when none is written: goods by the piece, a service as one lot, labor by man-months. */
7
+ export declare const DEFAULT_UNIT: Record<SalesProductKind, string>;
8
+ export declare function unitOf(kind: SalesProductKind | string, unit?: string | null): string;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_UNIT = exports.SalesProductKind = void 0;
4
+ exports.unitOf = unitOf;
5
+ const type_graphql_1 = require("type-graphql");
6
+ /* Apart from the entity, so what reads the kinds (the screens' words, the tests) needs no type-graphql class. */
7
+ var SalesProductKind;
8
+ (function (SalesProductKind) {
9
+ SalesProductKind["GOODS"] = "GOODS";
10
+ SalesProductKind["SERVICE"] = "SERVICE";
11
+ SalesProductKind["LABOR"] = "LABOR";
12
+ })(SalesProductKind || (exports.SalesProductKind = SalesProductKind = {}));
13
+ (0, type_graphql_1.registerEnumType)(SalesProductKind, {
14
+ name: 'SalesProductKind',
15
+ description: 'what a sales product is — goods, a service sold as a lot, or labor sold by the grade of the people'
16
+ });
17
+ /** The unit a product is sold in when none is written: goods by the piece, a service as one lot, labor by man-months. */
18
+ exports.DEFAULT_UNIT = {
19
+ [SalesProductKind.GOODS]: '개',
20
+ [SalesProductKind.SERVICE]: '식',
21
+ [SalesProductKind.LABOR]: 'M/M'
22
+ };
23
+ function unitOf(kind, unit) {
24
+ return String(unit ?? '').trim() || exports.DEFAULT_UNIT[kind] || exports.DEFAULT_UNIT[SalesProductKind.GOODS];
25
+ }
26
+ //# sourceMappingURL=sales-product-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sales-product-rules.js","sourceRoot":"","sources":["../../../server/service/sales-product/sales-product-rules.ts"],"names":[],"mappings":";;;AAoBA,wBAEC;AAtBD,+CAA+C;AAE/C,iHAAiH;AACjH,IAAY,gBAIX;AAJD,WAAY,gBAAgB;IAC1B,mCAAe,CAAA;IACf,uCAAmB,CAAA;IACnB,mCAAe,CAAA;AACjB,CAAC,EAJW,gBAAgB,gCAAhB,gBAAgB,QAI3B;AACD,IAAA,+BAAgB,EAAC,gBAAgB,EAAE;IACjC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,oGAAoG;CAClH,CAAC,CAAA;AAEF,yHAAyH;AAC5G,QAAA,YAAY,GAAqC;IAC5D,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,GAAG;IAC7B,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,GAAG;IAC/B,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK;CAChC,CAAA;AAED,SAAgB,MAAM,CAAC,IAA+B,EAAE,IAAoB;IAC1E,OAAO,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,oBAAY,CAAC,IAAwB,CAAC,IAAI,oBAAY,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAA;AACpH,CAAC","sourcesContent":["import { registerEnumType } from 'type-graphql'\n\n/* Apart from the entity, so what reads the kinds (the screens' words, the tests) needs no type-graphql class. */\nexport enum SalesProductKind {\n GOODS = 'GOODS',\n SERVICE = 'SERVICE',\n LABOR = 'LABOR'\n}\nregisterEnumType(SalesProductKind, {\n name: 'SalesProductKind',\n description: 'what a sales product is — goods, a service sold as a lot, or labor sold by the grade of the people'\n})\n\n/** The unit a product is sold in when none is written: goods by the piece, a service as one lot, labor by man-months. */\nexport const DEFAULT_UNIT: Record<SalesProductKind, string> = {\n [SalesProductKind.GOODS]: '개',\n [SalesProductKind.SERVICE]: '식',\n [SalesProductKind.LABOR]: 'M/M'\n}\n\nexport function unitOf(kind: SalesProductKind | string, unit?: string | null): string {\n return String(unit ?? '').trim() || DEFAULT_UNIT[kind as SalesProductKind] || DEFAULT_UNIT[SalesProductKind.GOODS]\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import { Domain } from '@things-factory/shell';
2
+ import { EntityManager } from 'typeorm';
3
+ import { SalesProduct } from './sales-product';
4
+ import { SalesProductPatch } from './sales-product-type';
5
+ /**
6
+ * Apply grid rows to a domain's products: `+` (or no id) registers, `M` changes, `-` deletes (softly). A code is the
7
+ * domain's once among the products not deleted. Nothing names a product - a quotation line copies what it says - so a
8
+ * product is deleted freely.
9
+ */
10
+ export declare function saveSalesProducts(tx: EntityManager, domain: Domain, user: any, patches: SalesProductPatch[]): Promise<SalesProduct[]>;