@things-factory/ops-master 10.1.33 β†’ 10.1.35

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 (150) 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/master-change-approval.d.ts +14 -0
  5. package/dist-client/master-change-approval.js +36 -0
  6. package/dist-client/master-change-approval.js.map +1 -0
  7. package/dist-client/pages/master/material-definition.d.ts +4 -11
  8. package/dist-client/pages/master/material-definition.js +5 -53
  9. package/dist-client/pages/master/material-definition.js.map +1 -1
  10. package/dist-client/pages/master/material-revision-fields.d.ts +2 -0
  11. package/dist-client/pages/master/material-revision-fields.js +43 -0
  12. package/dist-client/pages/master/material-revision-fields.js.map +1 -0
  13. package/dist-client/pages/master/recipe-definition.d.ts +4 -135
  14. package/dist-client/pages/master/recipe-definition.js +7 -397
  15. package/dist-client/pages/master/recipe-definition.js.map +1 -1
  16. package/dist-client/pages/master/revision-comparison.d.ts +48 -0
  17. package/dist-client/pages/master/revision-comparison.js +553 -0
  18. package/dist-client/pages/master/revision-comparison.js.map +1 -0
  19. package/dist-client/pages/master/revision-view.d.ts +19 -0
  20. package/dist-client/pages/master/revision-view.js +133 -0
  21. package/dist-client/pages/master/revision-view.js.map +1 -0
  22. package/dist-client/pages/master/revision-workspace.d.ts +50 -0
  23. package/dist-client/pages/master/revision-workspace.js +752 -0
  24. package/dist-client/pages/master/revision-workspace.js.map +1 -0
  25. package/dist-client/pages/master/test-specification.d.ts +4 -92
  26. package/dist-client/pages/master/test-specification.js +5 -440
  27. package/dist-client/pages/master/test-specification.js.map +1 -1
  28. package/dist-client/tsconfig.tsbuildinfo +1 -1
  29. package/dist-server/service/asset/asset-master-resolver.js +38 -34
  30. package/dist-server/service/asset/asset-master-resolver.js.map +1 -1
  31. package/dist-server/service/asset/index.d.ts +2 -2
  32. package/dist-server/service/equipment/equipment-master-resolver.js +54 -49
  33. package/dist-server/service/equipment/equipment-master-resolver.js.map +1 -1
  34. package/dist-server/service/equipment/index.d.ts +2 -2
  35. package/dist-server/service/index.d.ts +18 -2
  36. package/dist-server/service/index.js +18 -0
  37. package/dist-server/service/index.js.map +1 -1
  38. package/dist-server/service/location/index.d.ts +1 -1
  39. package/dist-server/service/location/location-master-resolver.js +34 -31
  40. package/dist-server/service/location/location-master-resolver.js.map +1 -1
  41. package/dist-server/service/master-axis.js +1 -1
  42. package/dist-server/service/master-axis.js.map +1 -1
  43. package/dist-server/service/master-change-policy.d.ts +23 -0
  44. package/dist-server/service/master-change-policy.js +134 -0
  45. package/dist-server/service/master-change-policy.js.map +1 -0
  46. package/dist-server/service/master-conformance-resolver.js +11 -1
  47. package/dist-server/service/master-conformance-resolver.js.map +1 -1
  48. package/dist-server/service/master-crud.js +9 -0
  49. package/dist-server/service/master-crud.js.map +1 -1
  50. package/dist-server/service/master-list.js +6 -0
  51. package/dist-server/service/master-list.js.map +1 -1
  52. package/dist-server/service/material/index.d.ts +3 -2
  53. package/dist-server/service/material/index.js +4 -2
  54. package/dist-server/service/material/index.js.map +1 -1
  55. package/dist-server/service/material/material-axis-status.d.ts +8 -0
  56. package/dist-server/service/material/material-axis-status.js +19 -0
  57. package/dist-server/service/material/material-axis-status.js.map +1 -0
  58. package/dist-server/service/material/material-definition.d.ts +3 -0
  59. package/dist-server/service/material/material-definition.js +13 -0
  60. package/dist-server/service/material/material-definition.js.map +1 -1
  61. package/dist-server/service/material/material-effective-list.d.ts +39 -0
  62. package/dist-server/service/material/material-effective-list.js +54 -0
  63. package/dist-server/service/material/material-effective-list.js.map +1 -0
  64. package/dist-server/service/material/material-master-resolver.js +59 -61
  65. package/dist-server/service/material/material-master-resolver.js.map +1 -1
  66. package/dist-server/service/material/material-query.js +9 -2
  67. package/dist-server/service/material/material-query.js.map +1 -1
  68. package/dist-server/service/material/material-revision-content.d.ts +10 -0
  69. package/dist-server/service/material/material-revision-content.js +92 -0
  70. package/dist-server/service/material/material-revision-content.js.map +1 -0
  71. package/dist-server/service/material/material-revision-resolver.d.ts +54 -0
  72. package/dist-server/service/material/material-revision-resolver.js +76 -0
  73. package/dist-server/service/material/material-revision-resolver.js.map +1 -0
  74. package/dist-server/service/material/material-revision-service.d.ts +144 -0
  75. package/dist-server/service/material/material-revision-service.js +534 -0
  76. package/dist-server/service/material/material-revision-service.js.map +1 -0
  77. package/dist-server/service/material/material-revision.d.ts +84 -0
  78. package/dist-server/service/material/material-revision.js +339 -0
  79. package/dist-server/service/material/material-revision.js.map +1 -0
  80. package/dist-server/service/operation/index.d.ts +1 -1
  81. package/dist-server/service/operation/operation-definition.js +1 -0
  82. package/dist-server/service/operation/operation-definition.js.map +1 -1
  83. package/dist-server/service/operation/operation-master-resolver.js +30 -30
  84. package/dist-server/service/operation/operation-master-resolver.js.map +1 -1
  85. package/dist-server/service/personnel/index.d.ts +2 -2
  86. package/dist-server/service/personnel/personnel-master-resolver.js +38 -34
  87. package/dist-server/service/personnel/personnel-master-resolver.js.map +1 -1
  88. package/dist-server/service/quality/nonconformance-cause-resolver.js +17 -14
  89. package/dist-server/service/quality/nonconformance-cause-resolver.js.map +1 -1
  90. package/dist-server/service/recipe/index.d.ts +3 -2
  91. package/dist-server/service/recipe/index.js +4 -2
  92. package/dist-server/service/recipe/index.js.map +1 -1
  93. package/dist-server/service/recipe/recipe-definition.d.ts +4 -0
  94. package/dist-server/service/recipe/recipe-definition.js +14 -1
  95. package/dist-server/service/recipe/recipe-definition.js.map +1 -1
  96. package/dist-server/service/recipe/recipe-effective-list.d.ts +49 -0
  97. package/dist-server/service/recipe/recipe-effective-list.js +96 -0
  98. package/dist-server/service/recipe/recipe-effective-list.js.map +1 -0
  99. package/dist-server/service/recipe/recipe-master-resolver.js +32 -28
  100. package/dist-server/service/recipe/recipe-master-resolver.js.map +1 -1
  101. package/dist-server/service/recipe/recipe-query.js +9 -2
  102. package/dist-server/service/recipe/recipe-query.js.map +1 -1
  103. package/dist-server/service/recipe/recipe-revision-content.d.ts +32 -0
  104. package/dist-server/service/recipe/recipe-revision-content.js +65 -0
  105. package/dist-server/service/recipe/recipe-revision-content.js.map +1 -0
  106. package/dist-server/service/recipe/recipe-revision-line.d.ts +30 -0
  107. package/dist-server/service/recipe/recipe-revision-line.js +95 -0
  108. package/dist-server/service/recipe/recipe-revision-line.js.map +1 -0
  109. package/dist-server/service/recipe/recipe-revision-resolver.d.ts +59 -0
  110. package/dist-server/service/recipe/recipe-revision-resolver.js +76 -0
  111. package/dist-server/service/recipe/recipe-revision-resolver.js.map +1 -0
  112. package/dist-server/service/recipe/recipe-revision-service.d.ts +147 -0
  113. package/dist-server/service/recipe/recipe-revision-service.js +591 -0
  114. package/dist-server/service/recipe/recipe-revision-service.js.map +1 -0
  115. package/dist-server/service/recipe/recipe-revision.d.ts +100 -0
  116. package/dist-server/service/recipe/recipe-revision.js +373 -0
  117. package/dist-server/service/recipe/recipe-revision.js.map +1 -0
  118. package/dist-server/service/recipe/route-definition.js +1 -0
  119. package/dist-server/service/recipe/route-definition.js.map +1 -1
  120. package/dist-server/service/resource/class-members.js +9 -0
  121. package/dist-server/service/resource/class-members.js.map +1 -1
  122. package/dist-server/service/status/master-status.js +2 -1
  123. package/dist-server/service/status/master-status.js.map +1 -1
  124. package/dist-server/service/test-spec/index.d.ts +3 -2
  125. package/dist-server/service/test-spec/index.js +4 -2
  126. package/dist-server/service/test-spec/index.js.map +1 -1
  127. package/dist-server/service/test-spec/test-spec-effective-list.d.ts +34 -0
  128. package/dist-server/service/test-spec/test-spec-effective-list.js +42 -0
  129. package/dist-server/service/test-spec/test-spec-effective-list.js.map +1 -0
  130. package/dist-server/service/test-spec/test-spec-master-resolver.d.ts +4 -14
  131. package/dist-server/service/test-spec/test-spec-master-resolver.js +12 -83
  132. package/dist-server/service/test-spec/test-spec-master-resolver.js.map +1 -1
  133. package/dist-server/service/test-spec/test-spec-query.js +7 -1
  134. package/dist-server/service/test-spec/test-spec-query.js.map +1 -1
  135. package/dist-server/service/test-spec/test-spec-revision-resolver.d.ts +53 -0
  136. package/dist-server/service/test-spec/test-spec-revision-resolver.js +76 -0
  137. package/dist-server/service/test-spec/test-spec-revision-resolver.js.map +1 -0
  138. package/dist-server/service/test-spec/test-spec-revision-service.d.ts +138 -0
  139. package/dist-server/service/test-spec/test-spec-revision-service.js +538 -0
  140. package/dist-server/service/test-spec/test-spec-revision-service.js.map +1 -0
  141. package/dist-server/service/test-spec/test-spec-revision.d.ts +84 -0
  142. package/dist-server/service/test-spec/test-spec-revision.js +334 -0
  143. package/dist-server/service/test-spec/test-spec-revision.js.map +1 -0
  144. package/dist-server/service/test-spec/test-specification.d.ts +6 -0
  145. package/dist-server/service/test-spec/test-specification.js +15 -2
  146. package/dist-server/service/test-spec/test-specification.js.map +1 -1
  147. package/dist-server/tsconfig.tsbuildinfo +1 -1
  148. package/package.json +10 -6
  149. package/translations/en.json +148 -0
  150. package/translations/ko.json +148 -0
@@ -19,6 +19,8 @@ const recipe_definition_1 = require("./recipe/recipe-definition");
19
19
  const route_definition_1 = require("./recipe/route-definition");
20
20
  const test_specification_1 = require("./test-spec/test-specification");
21
21
  const master_conformance_1 = require("./master-conformance");
22
+ const recipe_effective_list_1 = require("./recipe/recipe-effective-list");
23
+ const material_effective_list_1 = require("./material/material-effective-list");
22
24
  /**
23
25
  * λ§ˆμŠ€ν„° μ •ν•©μ„± β€” **μ‚¬λžŒμ΄ λˆŒλŸ¬μ„œ λ„λŠ” 검사.**
24
26
  *
@@ -108,7 +110,15 @@ exports.MasterConformance = MasterConformance = tslib_1.__decorate([
108
110
  let MasterConformanceResolver = class MasterConformanceResolver {
109
111
  async masterConformance(context) {
110
112
  const { domain } = context.state;
111
- const snapshot = await (0, master_conformance_1.readMasterSnapshot)(domain, shell_1.getRepository, {
113
+ const snapshot = await (0, master_conformance_1.readMasterSnapshot)(domain, (entity) => entity === recipe_definition_1.RecipeDefinition
114
+ ? { find: async () => (await (0, recipe_effective_list_1.listEffectiveRecipes)((0, shell_1.getRepository)(recipe_definition_1.RecipeDefinition).manager, domain, {
115
+ filters: [{ name: 'materialDefinitionName', operator: 'is_not_null', value: true }]
116
+ })).items }
117
+ : entity === material_definition_1.MaterialDefinition
118
+ ? { find: async () => (await (0, material_effective_list_1.listEffectiveMaterialDefinitions)((0, shell_1.getRepository)(material_definition_1.MaterialDefinition).manager, domain, {
119
+ filters: [{ name: 'revisionNumber', operator: 'is_not_null', value: true }]
120
+ })).items }
121
+ : (0, shell_1.getRepository)(entity), {
112
122
  Person: person_1.Person,
113
123
  PersonnelClass: personnel_class_1.PersonnelClass,
114
124
  Equipment: equipment_1.Equipment,
@@ -1 +1 @@
1
- {"version":3,"file":"master-conformance-resolver.js","sourceRoot":"","sources":["../../server/service/master-conformance-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Ctx, Directive, Field, Int, ObjectType, Query, Resolver } from 'type-graphql'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { PhysicalAsset } from './asset/physical-asset'\nimport { PhysicalAssetClass } from './asset/physical-asset-class'\nimport { Equipment } from './equipment/equipment'\nimport { EquipmentClass } from './equipment/equipment-class'\nimport { StopReason } from './equipment/stop-reason'\nimport { OperationalLocation } from './location/operational-location'\nimport { MaterialClass } from './material/material-class'\nimport { MaterialDefinition } from './material/material-definition'\nimport { OperationDefinition } from './operation/operation-definition'\nimport { Person } from './personnel/person'\nimport { PersonnelClass } from './personnel/personnel-class'\nimport { RecipeDefinition } from './recipe/recipe-definition'\nimport { RouteDefinition } from './recipe/route-definition'\nimport { TestSpecification } from './test-spec/test-specification'\nimport { checkMaster, readMasterSnapshot, scannedCounts, summarize } from './master-conformance'\n\n/**\n * λ§ˆμŠ€ν„° μ •ν•©μ„± β€” **μ‚¬λžŒμ΄ λˆŒλŸ¬μ„œ λ„λŠ” 검사.**\n *\n * λͺ©λ‘ 화면이 맀번 λΆ€λ₯΄λŠ” 것이 μ•„λ‹ˆλ‹€. ν‘œλ₯Ό ν†΅μ§Έλ‘œ 읽어야 닡이 λ‚˜μ˜€κ³ , μƒν•œμ„ 두면 γ€Œμ–΄κΈ‹λ‚¨ 0건」이\n * 거짓이 되기 λ•Œλ¬Έμ΄λ‹€. 정합성은 γ€Œμ „λΆ€ λ΄€λ‚˜γ€κ°€ κ³§ 닡이닀.\n */\n\n@ObjectType({ description: 'One master data conformance finding' })\nexport class MasterFinding {\n @Field()\n axis: string\n\n @Field({ nullable: true })\n subject?: string\n\n @Field()\n kind: string\n\n @Field()\n field: string\n\n @Field({ nullable: true })\n value?: string\n}\n\n@ObjectType({ description: 'How many findings per axis and kind' })\nexport class MasterFindingCount {\n @Field()\n axis: string\n\n @Field()\n kind: string\n\n @Field(type => Int)\n count: number\n}\n\n@ObjectType({ description: 'How many rows were scanned per axis' })\nexport class MasterScanned {\n @Field()\n axis: string\n\n @Field(type => Int)\n rows: number\n}\n\n@ObjectType({ description: 'Master data conformance report' })\nexport class MasterConformance {\n /**\n * 무엇을 λͺ‡ 개 λ΄€λ‚˜. **어긋남 0건이 γ€Œλ©€μ©‘ν•˜λ‹€γ€μΈμ§€ γ€Œμ•ˆ λŒμ•˜λ‹€γ€μΈμ§€λŠ” μ΄κ²ƒμœΌλ‘œλ§Œ κ°ˆλ¦°λ‹€.**\n */\n @Field(type => [MasterScanned])\n scanned: MasterScanned[]\n\n @Field(type => Int, { description: 'How many findings in total' })\n total: number\n\n @Field(type => [MasterFindingCount])\n counts: MasterFindingCount[]\n\n @Field(type => [MasterFinding])\n findings: MasterFinding[]\n}\n\n@Resolver()\nexport class MasterConformanceResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => MasterConformance, { description: 'Check master data for missing fields and dangling references' })\n async masterConformance(@Ctx() context: ResolverContext): Promise<MasterConformance> {\n const { domain } = context.state\n\n const snapshot = await readMasterSnapshot(domain, getRepository, {\n Person,\n PersonnelClass,\n Equipment,\n EquipmentClass,\n PhysicalAsset,\n PhysicalAssetClass,\n MaterialDefinition,\n MaterialClass,\n OperationDefinition,\n RouteDefinition,\n RecipeDefinition,\n OperationalLocation,\n StopReason,\n TestSpecification\n })\n\n const findings = checkMaster(snapshot)\n\n return { scanned: scannedCounts(snapshot), total: findings.length, counts: summarize(findings), findings }\n }\n}\n"]}
1
+ {"version":3,"file":"master-conformance-resolver.js","sourceRoot":"","sources":["../../server/service/master-conformance-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Ctx, Directive, Field, Int, ObjectType, Query, Resolver } from 'type-graphql'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { PhysicalAsset } from './asset/physical-asset'\nimport { PhysicalAssetClass } from './asset/physical-asset-class'\nimport { Equipment } from './equipment/equipment'\nimport { EquipmentClass } from './equipment/equipment-class'\nimport { StopReason } from './equipment/stop-reason'\nimport { OperationalLocation } from './location/operational-location'\nimport { MaterialClass } from './material/material-class'\nimport { MaterialDefinition } from './material/material-definition'\nimport { OperationDefinition } from './operation/operation-definition'\nimport { Person } from './personnel/person'\nimport { PersonnelClass } from './personnel/personnel-class'\nimport { RecipeDefinition } from './recipe/recipe-definition'\nimport { RouteDefinition } from './recipe/route-definition'\nimport { TestSpecification } from './test-spec/test-specification'\nimport { checkMaster, readMasterSnapshot, scannedCounts, summarize } from './master-conformance'\nimport { listEffectiveRecipes } from './recipe/recipe-effective-list'\nimport { listEffectiveMaterialDefinitions } from './material/material-effective-list'\n\n/**\n * λ§ˆμŠ€ν„° μ •ν•©μ„± β€” **μ‚¬λžŒμ΄ λˆŒλŸ¬μ„œ λ„λŠ” 검사.**\n *\n * λͺ©λ‘ 화면이 맀번 λΆ€λ₯΄λŠ” 것이 μ•„λ‹ˆλ‹€. ν‘œλ₯Ό ν†΅μ§Έλ‘œ 읽어야 닡이 λ‚˜μ˜€κ³ , μƒν•œμ„ 두면 γ€Œμ–΄κΈ‹λ‚¨ 0건」이\n * 거짓이 되기 λ•Œλ¬Έμ΄λ‹€. 정합성은 γ€Œμ „λΆ€ λ΄€λ‚˜γ€κ°€ κ³§ 닡이닀.\n */\n\n@ObjectType({ description: 'One master data conformance finding' })\nexport class MasterFinding {\n @Field()\n axis: string\n\n @Field({ nullable: true })\n subject?: string\n\n @Field()\n kind: string\n\n @Field()\n field: string\n\n @Field({ nullable: true })\n value?: string\n}\n\n@ObjectType({ description: 'How many findings per axis and kind' })\nexport class MasterFindingCount {\n @Field()\n axis: string\n\n @Field()\n kind: string\n\n @Field(type => Int)\n count: number\n}\n\n@ObjectType({ description: 'How many rows were scanned per axis' })\nexport class MasterScanned {\n @Field()\n axis: string\n\n @Field(type => Int)\n rows: number\n}\n\n@ObjectType({ description: 'Master data conformance report' })\nexport class MasterConformance {\n /**\n * 무엇을 λͺ‡ 개 λ΄€λ‚˜. **어긋남 0건이 γ€Œλ©€μ©‘ν•˜λ‹€γ€μΈμ§€ γ€Œμ•ˆ λŒμ•˜λ‹€γ€μΈμ§€λŠ” μ΄κ²ƒμœΌλ‘œλ§Œ κ°ˆλ¦°λ‹€.**\n */\n @Field(type => [MasterScanned])\n scanned: MasterScanned[]\n\n @Field(type => Int, { description: 'How many findings in total' })\n total: number\n\n @Field(type => [MasterFindingCount])\n counts: MasterFindingCount[]\n\n @Field(type => [MasterFinding])\n findings: MasterFinding[]\n}\n\n@Resolver()\nexport class MasterConformanceResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => MasterConformance, { description: 'Check master data for missing fields and dangling references' })\n async masterConformance(@Ctx() context: ResolverContext): Promise<MasterConformance> {\n const { domain } = context.state\n\n const snapshot = await readMasterSnapshot(domain, (entity: any) => entity === RecipeDefinition\n ? { find: async () => (await listEffectiveRecipes(getRepository(RecipeDefinition).manager, domain, {\n filters: [{ name: 'materialDefinitionName', operator: 'is_not_null', value: true }]\n } as any)).items }\n : entity === MaterialDefinition\n ? { find: async () => (await listEffectiveMaterialDefinitions(getRepository(MaterialDefinition).manager, domain, {\n filters: [{ name: 'revisionNumber', operator: 'is_not_null', value: true }]\n } as any)).items }\n : getRepository(entity), {\n Person,\n PersonnelClass,\n Equipment,\n EquipmentClass,\n PhysicalAsset,\n PhysicalAssetClass,\n MaterialDefinition,\n MaterialClass,\n OperationDefinition,\n RouteDefinition,\n RecipeDefinition,\n OperationalLocation,\n StopReason,\n TestSpecification\n })\n\n const findings = checkMaster(snapshot)\n\n return { scanned: scannedCounts(snapshot), total: findings.length, counts: summarize(findings), findings }\n }\n}\n"]}
@@ -2,12 +2,21 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.saveMasterPatches = saveMasterPatches;
4
4
  const typeorm_1 = require("typeorm");
5
+ const shell_1 = require("@things-factory/shell");
6
+ const master_axis_1 = require("./master-axis");
7
+ const master_change_policy_1 = require("./master-change-policy");
5
8
  /**
6
9
  * κ·Έλ¦¬λ“œκ°€ 보낸 변경을 ν•œ λ²ˆμ— μ μš©ν•œλ‹€.
7
10
  *
8
11
  * ν•œ νŠΈλžœμž­μ…˜μ—μ„œ μ²˜λ¦¬ν•œλ‹€ β€” 절반만 반영되면 κ·Έλ¦¬λ“œκ°€ 보여 μ£ΌλŠ” 것과 μ €μž₯된 것이 κ°ˆλ¦°λ‹€.
9
12
  */
10
13
  async function saveMasterPatches(manager, domain, entity, patches, user, options = {}) {
14
+ const axis = master_axis_1.MASTER_AXES.find(axis => axis.entity === entity);
15
+ if (!axis)
16
+ throw new Error('saveMasterPatches: the entity must be a declared master axis');
17
+ await (0, master_change_policy_1.assertDirectMasterChange)(manager, domain.id, axis.key);
18
+ if (['recipeDefinition', 'materialDefinition'].includes(axis.key))
19
+ throw new shell_1.Refusal('REVISION_REQUIRED', { axis: axis.key }, 'Change this master through a revision draft, including non-regulated publication.');
11
20
  const repository = manager.getRepository(entity);
12
21
  const results = [];
13
22
  const created = patches.filter(patch => flagOf(patch) === '+');
@@ -1 +1 @@
1
- {"version":3,"file":"master-crud.js","sourceRoot":"","sources":["../../server/service/master-crud.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, In, ObjectLiteral, Repository } from 'typeorm'\n\nimport { Domain } from '@things-factory/shell'\n\n/**\n * λ§ˆμŠ€ν„°λ₯Ό μ±„μš°κ³  κ³ μΉ˜λŠ” **ν•œ 벌의 κ·œμΉ™** β€” 열두 좕이 같은 ν•¨μˆ˜λ₯Ό μ“΄λ‹€.\n *\n * ── μ™œ λ§ˆμŠ€ν„°λŠ” κ·Έλ¦¬λ“œμ—μ„œ κ³ μΉ  수 μžˆλ‚˜ ────────────────────────────────────\n * 업무 ν™”λ©΄(싀적 Β· 검사 Β· μ²˜λΆ„)은 쑰회 μ „μš©μ΄λ‹€. 그것은 **μΌμ–΄λ‚œ 일의 기둝**이라, κ³ μΉ  수 있으면\n * γ€Œκ·Έλ•Œ 무엇이 μžˆμ—ˆλ‚˜γ€κ°€ γ€Œμ§€κΈˆ λ¬΄μ—‡μœΌλ‘œ μ ν˜€ μžˆλ‚˜γ€λ‘œ 바뀐닀.\n *\n * λ§ˆμŠ€ν„°λŠ” λ‹€λ₯΄λ‹€. γ€Œμ΄ μ‚¬λžŒμ΄ μš©μ ‘ μžκ²©μ„ κ°–λŠ”λ‹€γ€λŠ” μΌμ–΄λ‚œ 일이 μ•„λ‹ˆλΌ **μ„ μ–Έ**이닀. 선언은 λ°”λ€Œκ³ ,\n * 바뀐 것이 μ§€κΈˆμ˜ 선언이닀. κ·Έλž˜μ„œ κ·Έλ¦¬λ“œμ—μ„œ κ³ μΉœλ‹€.\n *\n * ── μ§€μš°λŠ” κ²ƒλ§Œ λ‹€λ₯΄κ²Œ 닀룬닀 ──────────────────────────────────────────────\n * 유효 기간을 κ°€μ§„ 좕은 **행을 μ§€μš°μ§€ μ•ŠλŠ”λ‹€.** μ§€μš°λ©΄ 그것을 κ°€λ¦¬ν‚€λŠ” μ§€λ‚œ 기둝이 가리킬 것을 μžƒλŠ”λ‹€\n * (μ–΄μ œ 싀적이 κ°€λ¦¬ν‚€λ˜ μ„€λΉ„κ°€ 사라지면 κ·Έ 싀적은 μ–΄λŠ μ„€λΉ„μ˜ 것도 μ•„λ‹ˆκ²Œ λœλ‹€). λŒ€μ‹ \n * `effectiveEnd` λ₯Ό μ±„μ›Œ μ˜€λŠ˜λΆ€ν„° μœ νš¨ν•˜μ§€ μ•Šκ²Œ ν•œλ‹€.\n *\n * 유효 기간이 μ—†λŠ” μΆ•λ§Œ μ‹€μ œλ‘œ μ§€μš΄λ‹€.\n */\n\n/** κ·Έλ¦¬λ“œκ°€ λ³΄λ‚΄λŠ” ν‘œμ‹. `+` μƒˆλ‘œ λ§Œλ“  ν–‰ Β· `M` 고친 ν–‰ Β· `-` μ§€μš΄ ν–‰. */\nexport type CuFlag = '+' | 'M' | '-'\n\nexport interface MasterPatch {\n id?: string\n cuFlag?: string\n [key: string]: unknown\n}\n\ntype EntityClass = { new (): ObjectLiteral }\n\nexport interface SaveMasterOptions {\n /**\n * 유효 기간을 κ°–λŠ” 좕인가.\n *\n * 참이면 μ§€μš°κΈ°κ°€ **`effectiveEnd` λ₯Ό μ±„μš°λŠ” 것**이 λœλ‹€. 거짓이면 행을 μ§€μš΄λ‹€.\n */\n hasEffectivePeriod?: boolean\n}\n\n/**\n * κ·Έλ¦¬λ“œκ°€ 보낸 변경을 ν•œ λ²ˆμ— μ μš©ν•œλ‹€.\n *\n * ν•œ νŠΈλžœμž­μ…˜μ—μ„œ μ²˜λ¦¬ν•œλ‹€ β€” 절반만 반영되면 κ·Έλ¦¬λ“œκ°€ 보여 μ£ΌλŠ” 것과 μ €μž₯된 것이 κ°ˆλ¦°λ‹€.\n */\nexport async function saveMasterPatches(\n manager: EntityManager,\n domain: Domain,\n entity: EntityClass,\n patches: readonly MasterPatch[],\n user: unknown,\n options: SaveMasterOptions = {}\n): Promise<ObjectLiteral[]> {\n const repository = manager.getRepository(entity)\n const results: ObjectLiteral[] = []\n\n const created = patches.filter(patch => flagOf(patch) === '+')\n const updated = patches.filter(patch => flagOf(patch) === 'M')\n const removed = patches.filter(patch => flagOf(patch) === '-')\n\n for (const patch of created) {\n /* μƒˆ ν–‰μ˜ `id` λŠ” κ·Έλ¦¬λ“œκ°€ μž„μ‹œλ‘œ 뢙인 것이닀 β€” κ·ΈλŒ€λ‘œ μ €μž₯ν•˜λ©΄ 그것이 μ§„μ§œ ν‚€κ°€ λœλ‹€. */\n const { cuFlag, id, ...values } = patch\n\n results.push(await repository.save({ ...values, domain, creator: user, updater: user }))\n }\n\n for (const patch of updated) {\n const { cuFlag, id, ...values } = patch\n\n if (!id) {\n throw new Error('saveMasterPatches: a changed row must carry its id')\n }\n\n const found = await repository.findOne({ where: { domain: { id: domain.id }, id } })\n\n /*\n * μ—†λŠ” 행을 고치라고 ν•˜λ©΄ λ§Œλ“€μ§€ μ•ŠλŠ”λ‹€. λ‹€λ₯Έ μ‚¬λžŒμ΄ μ§€μ› κ±°λ‚˜ λ‹€λ₯Έ λ„λ©”μΈμ˜ 행이고, λ‘˜ λ‹€\n * 쑰용히 μƒˆ 행을 λ§Œλ“€ 일이 μ•„λ‹ˆλ‹€.\n */\n if (!found) {\n throw new Error(`saveMasterPatches: no such row to change β€” ${String(id)}`)\n }\n\n results.push(await repository.save({ ...found, ...values, updater: user }))\n }\n\n if (removed.length) {\n await retire(repository, domain, removed, user, options)\n }\n\n return results\n}\n\n/**\n * μ—†μ•€λ‹€ β€” 유효 기간이 있으면 **끝을 μ±„μš°κ³ **, μ—†μœΌλ©΄ μ§€μš΄λ‹€.\n */\nasync function retire(\n repository: Repository<ObjectLiteral>,\n domain: Domain,\n removed: readonly MasterPatch[],\n user: unknown,\n options: SaveMasterOptions\n): Promise<void> {\n const ids = removed.map(patch => patch.id).filter(Boolean) as string[]\n\n if (!ids.length) {\n return\n }\n\n if (!options.hasEffectivePeriod) {\n await repository.delete({ domain: { id: domain.id }, id: In(ids) })\n return\n }\n\n const rows = await repository.find({ where: { domain: { id: domain.id }, id: In(ids) } })\n const now = new Date()\n\n for (const row of rows) {\n /*\n * 이미 끝이 μ ν˜€ 있으면 κ·ΈλŒ€λ‘œ λ‘”λ‹€. λ‹€μ‹œ 였늘둜 λ°”κΎΈλ©΄ γ€Œμ–Έμ œλΆ€ν„° μ•ˆ μΌλ‚˜γ€κ°€ 바뀐닀.\n */\n if (row.effectiveEnd) {\n continue\n }\n\n await repository.save({ ...row, effectiveEnd: now, updater: user })\n }\n}\n\nfunction flagOf(patch: MasterPatch): CuFlag {\n const flag = String(patch.cuFlag ?? '').toUpperCase()\n\n if (flag === '+' || flag === 'M' || flag === '-') {\n return flag\n }\n\n /* ν‘œμ‹μ΄ μ—†μœΌλ©΄ 고침으둜 λ³Έλ‹€ β€” κ·Έλ¦¬λ“œκ°€ ν‘œμ‹μ„ μ•ˆ λΆ™μ΄λŠ” κ²½μš°κ°€ 있고, λ§Œλ“œλŠ” μͺ½μœΌλ‘œ 두면 행이 λŠ˜μ–΄λ‚œλ‹€. */\n return 'M'\n}\n"]}
1
+ {"version":3,"file":"master-crud.js","sourceRoot":"","sources":["../../server/service/master-crud.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, In, ObjectLiteral, Repository } from 'typeorm'\n\nimport { Domain, Refusal } from '@things-factory/shell'\nimport { MASTER_AXES } from './master-axis'\nimport { assertDirectMasterChange } from './master-change-policy'\n\n/**\n * λ§ˆμŠ€ν„°λ₯Ό μ±„μš°κ³  κ³ μΉ˜λŠ” **ν•œ 벌의 κ·œμΉ™** β€” 열두 좕이 같은 ν•¨μˆ˜λ₯Ό μ“΄λ‹€.\n *\n * ── μ™œ λ§ˆμŠ€ν„°λŠ” κ·Έλ¦¬λ“œμ—μ„œ κ³ μΉ  수 μžˆλ‚˜ ────────────────────────────────────\n * 업무 ν™”λ©΄(싀적 Β· 검사 Β· μ²˜λΆ„)은 쑰회 μ „μš©μ΄λ‹€. 그것은 **μΌμ–΄λ‚œ 일의 기둝**이라, κ³ μΉ  수 있으면\n * γ€Œκ·Έλ•Œ 무엇이 μžˆμ—ˆλ‚˜γ€κ°€ γ€Œμ§€κΈˆ λ¬΄μ—‡μœΌλ‘œ μ ν˜€ μžˆλ‚˜γ€λ‘œ 바뀐닀.\n *\n * λ§ˆμŠ€ν„°λŠ” λ‹€λ₯΄λ‹€. γ€Œμ΄ μ‚¬λžŒμ΄ μš©μ ‘ μžκ²©μ„ κ°–λŠ”λ‹€γ€λŠ” μΌμ–΄λ‚œ 일이 μ•„λ‹ˆλΌ **μ„ μ–Έ**이닀. 선언은 λ°”λ€Œκ³ ,\n * 바뀐 것이 μ§€κΈˆμ˜ 선언이닀. κ·Έλž˜μ„œ κ·Έλ¦¬λ“œμ—μ„œ κ³ μΉœλ‹€.\n *\n * ── μ§€μš°λŠ” κ²ƒλ§Œ λ‹€λ₯΄κ²Œ 닀룬닀 ──────────────────────────────────────────────\n * 유효 기간을 κ°€μ§„ 좕은 **행을 μ§€μš°μ§€ μ•ŠλŠ”λ‹€.** μ§€μš°λ©΄ 그것을 κ°€λ¦¬ν‚€λŠ” μ§€λ‚œ 기둝이 가리킬 것을 μžƒλŠ”λ‹€\n * (μ–΄μ œ 싀적이 κ°€λ¦¬ν‚€λ˜ μ„€λΉ„κ°€ 사라지면 κ·Έ 싀적은 μ–΄λŠ μ„€λΉ„μ˜ 것도 μ•„λ‹ˆκ²Œ λœλ‹€). λŒ€μ‹ \n * `effectiveEnd` λ₯Ό μ±„μ›Œ μ˜€λŠ˜λΆ€ν„° μœ νš¨ν•˜μ§€ μ•Šκ²Œ ν•œλ‹€.\n *\n * 유효 기간이 μ—†λŠ” μΆ•λ§Œ μ‹€μ œλ‘œ μ§€μš΄λ‹€.\n */\n\n/** κ·Έλ¦¬λ“œκ°€ λ³΄λ‚΄λŠ” ν‘œμ‹. `+` μƒˆλ‘œ λ§Œλ“  ν–‰ Β· `M` 고친 ν–‰ Β· `-` μ§€μš΄ ν–‰. */\nexport type CuFlag = '+' | 'M' | '-'\n\nexport interface MasterPatch {\n id?: string\n cuFlag?: string\n [key: string]: unknown\n}\n\ntype EntityClass = { new (): ObjectLiteral }\n\nexport interface SaveMasterOptions {\n /**\n * 유효 기간을 κ°–λŠ” 좕인가.\n *\n * 참이면 μ§€μš°κΈ°κ°€ **`effectiveEnd` λ₯Ό μ±„μš°λŠ” 것**이 λœλ‹€. 거짓이면 행을 μ§€μš΄λ‹€.\n */\n hasEffectivePeriod?: boolean\n}\n\n/**\n * κ·Έλ¦¬λ“œκ°€ 보낸 변경을 ν•œ λ²ˆμ— μ μš©ν•œλ‹€.\n *\n * ν•œ νŠΈλžœμž­μ…˜μ—μ„œ μ²˜λ¦¬ν•œλ‹€ β€” 절반만 반영되면 κ·Έλ¦¬λ“œκ°€ 보여 μ£ΌλŠ” 것과 μ €μž₯된 것이 κ°ˆλ¦°λ‹€.\n */\nexport async function saveMasterPatches(\n manager: EntityManager,\n domain: Domain,\n entity: EntityClass,\n patches: readonly MasterPatch[],\n user: unknown,\n options: SaveMasterOptions = {}\n): Promise<ObjectLiteral[]> {\n const axis = MASTER_AXES.find(axis => axis.entity === entity)\n if (!axis) throw new Error('saveMasterPatches: the entity must be a declared master axis')\n await assertDirectMasterChange(manager, domain.id, axis.key)\n if (['recipeDefinition', 'materialDefinition'].includes(axis.key))\n throw new Refusal('REVISION_REQUIRED', { axis: axis.key }, 'Change this master through a revision draft, including non-regulated publication.')\n const repository = manager.getRepository(entity)\n const results: ObjectLiteral[] = []\n\n const created = patches.filter(patch => flagOf(patch) === '+')\n const updated = patches.filter(patch => flagOf(patch) === 'M')\n const removed = patches.filter(patch => flagOf(patch) === '-')\n\n for (const patch of created) {\n /* μƒˆ ν–‰μ˜ `id` λŠ” κ·Έλ¦¬λ“œκ°€ μž„μ‹œλ‘œ 뢙인 것이닀 β€” κ·ΈλŒ€λ‘œ μ €μž₯ν•˜λ©΄ 그것이 μ§„μ§œ ν‚€κ°€ λœλ‹€. */\n const { cuFlag, id, ...values } = patch\n\n results.push(await repository.save({ ...values, domain, creator: user, updater: user }))\n }\n\n for (const patch of updated) {\n const { cuFlag, id, ...values } = patch\n\n if (!id) {\n throw new Error('saveMasterPatches: a changed row must carry its id')\n }\n\n const found = await repository.findOne({ where: { domain: { id: domain.id }, id } })\n\n /*\n * μ—†λŠ” 행을 고치라고 ν•˜λ©΄ λ§Œλ“€μ§€ μ•ŠλŠ”λ‹€. λ‹€λ₯Έ μ‚¬λžŒμ΄ μ§€μ› κ±°λ‚˜ λ‹€λ₯Έ λ„λ©”μΈμ˜ 행이고, λ‘˜ λ‹€\n * 쑰용히 μƒˆ 행을 λ§Œλ“€ 일이 μ•„λ‹ˆλ‹€.\n */\n if (!found) {\n throw new Error(`saveMasterPatches: no such row to change β€” ${String(id)}`)\n }\n\n results.push(await repository.save({ ...found, ...values, updater: user }))\n }\n\n if (removed.length) {\n await retire(repository, domain, removed, user, options)\n }\n\n return results\n}\n\n/**\n * μ—†μ•€λ‹€ β€” 유효 기간이 있으면 **끝을 μ±„μš°κ³ **, μ—†μœΌλ©΄ μ§€μš΄λ‹€.\n */\nasync function retire(\n repository: Repository<ObjectLiteral>,\n domain: Domain,\n removed: readonly MasterPatch[],\n user: unknown,\n options: SaveMasterOptions\n): Promise<void> {\n const ids = removed.map(patch => patch.id).filter(Boolean) as string[]\n\n if (!ids.length) {\n return\n }\n\n if (!options.hasEffectivePeriod) {\n await repository.delete({ domain: { id: domain.id }, id: In(ids) })\n return\n }\n\n const rows = await repository.find({ where: { domain: { id: domain.id }, id: In(ids) } })\n const now = new Date()\n\n for (const row of rows) {\n /*\n * 이미 끝이 μ ν˜€ 있으면 κ·ΈλŒ€λ‘œ λ‘”λ‹€. λ‹€μ‹œ 였늘둜 λ°”κΎΈλ©΄ γ€Œμ–Έμ œλΆ€ν„° μ•ˆ μΌλ‚˜γ€κ°€ 바뀐닀.\n */\n if (row.effectiveEnd) {\n continue\n }\n\n await repository.save({ ...row, effectiveEnd: now, updater: user })\n }\n}\n\nfunction flagOf(patch: MasterPatch): CuFlag {\n const flag = String(patch.cuFlag ?? '').toUpperCase()\n\n if (flag === '+' || flag === 'M' || flag === '-') {\n return flag\n }\n\n /* ν‘œμ‹μ΄ μ—†μœΌλ©΄ 고침으둜 λ³Έλ‹€ β€” κ·Έλ¦¬λ“œκ°€ ν‘œμ‹μ„ μ•ˆ λΆ™μ΄λŠ” κ²½μš°κ°€ 있고, λ§Œλ“œλŠ” μͺ½μœΌλ‘œ 두면 행이 λŠ˜μ–΄λ‚œλ‹€. */\n return 'M'\n}\n"]}
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.listMaster = listMaster;
4
4
  const shell_1 = require("@things-factory/shell");
5
5
  const master_axis_1 = require("./master-axis");
6
+ const recipe_effective_list_1 = require("./recipe/recipe-effective-list");
7
+ const material_effective_list_1 = require("./material/material-effective-list");
6
8
  /**
7
9
  * λ§ˆμŠ€ν„° ν•œ 좕을 λͺ©λ‘μœΌλ‘œ μ½λŠ”λ‹€ β€” **열두 좕이 같은 ν•¨μˆ˜λ₯Ό μ“΄λ‹€.**
8
10
  *
@@ -11,6 +13,10 @@ const master_axis_1 = require("./master-axis");
11
13
  */
12
14
  async function listMaster(axisKey, params, domain) {
13
15
  const axis = (0, master_axis_1.masterAxisOf)(axisKey);
16
+ if (axisKey === 'recipeDefinition')
17
+ return (0, recipe_effective_list_1.listEffectiveRecipes)((0, shell_1.getRepository)(axis.entity).manager, domain, params);
18
+ if (axisKey === 'materialDefinition')
19
+ return (0, material_effective_list_1.listEffectiveMaterialDefinitions)((0, shell_1.getRepository)(axis.entity).manager, domain, params);
14
20
  const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
15
21
  repository: (0, shell_1.getRepository)(axis.entity),
16
22
  params,
@@ -1 +1 @@
1
- {"version":3,"file":"master-list.js","sourceRoot":"","sources":["../../server/service/master-list.ts"],"names":[],"mappings":";;AAYA,gCAkBC;AA5BD,iDAAuG;AAEvG,+CAA4C;AAE5C;;;;;GAKG;AACI,KAAK,UAAU,UAAU,CAC9B,OAAe,EACf,MAAiB,EACjB,MAAc;IAEd,MAAM,IAAI,GAAG,IAAA,0BAAY,EAAC,OAAO,CAAC,CAAA;IAElC,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;QACjD,UAAU,EAAE,IAAA,qBAAa,EAAC,IAAI,CAAC,MAAM,CAAC;QACtC,MAAM;QACN,MAAM;QACN,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,GAAG;KACX,CAAC,CAAA;IAEF,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAA;IAE3D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;AACzB,CAAC","sourcesContent":["import { ObjectLiteral } from 'typeorm'\n\nimport { Domain, ListParam, getQueryBuilderFromListParams, getRepository } from '@things-factory/shell'\n\nimport { masterAxisOf } from './master-axis'\n\n/**\n * λ§ˆμŠ€ν„° ν•œ 좕을 λͺ©λ‘μœΌλ‘œ μ½λŠ”λ‹€ β€” **열두 좕이 같은 ν•¨μˆ˜λ₯Ό μ“΄λ‹€.**\n *\n * 총 건수λ₯Ό ν•¨κ»˜ λ‚Έλ‹€. 화면이 γ€Œλͺ‡ 건 쀑 λͺ‡ 건을 보고 μžˆλ‚˜γ€λ₯Ό λ§ν•˜λ €λ©΄ κ·Έ 값이 μžˆμ–΄μ•Ό ν•˜κ³ , μ—†μœΌλ©΄\n * 잘린 λͺ©λ‘κ³Ό γ€Œμ΄κ²Œ 전뢀」λ₯Ό ꡬ별할 수 μ—†λ‹€.\n */\nexport async function listMaster(\n axisKey: string,\n params: ListParam,\n domain: Domain\n): Promise<{ items: ObjectLiteral[]; total: number }> {\n const axis = masterAxisOf(axisKey)\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(axis.entity),\n params,\n domain,\n searchables: axis.searchables,\n alias: 'm'\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n}\n"]}
1
+ {"version":3,"file":"master-list.js","sourceRoot":"","sources":["../../server/service/master-list.ts"],"names":[],"mappings":";;AAcA,gCAoBC;AAhCD,iDAAuG;AAEvG,+CAA4C;AAC5C,0EAAqE;AACrE,gFAAqF;AAErF;;;;;GAKG;AACI,KAAK,UAAU,UAAU,CAC9B,OAAe,EACf,MAAiB,EACjB,MAAc;IAEd,MAAM,IAAI,GAAG,IAAA,0BAAY,EAAC,OAAO,CAAC,CAAA;IAClC,IAAI,OAAO,KAAK,kBAAkB;QAAE,OAAO,IAAA,4CAAoB,EAAC,IAAA,qBAAa,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACnH,IAAI,OAAO,KAAK,oBAAoB;QAAE,OAAO,IAAA,0DAAgC,EAAC,IAAA,qBAAa,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAEjI,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;QACjD,UAAU,EAAE,IAAA,qBAAa,EAAC,IAAI,CAAC,MAAM,CAAC;QACtC,MAAM;QACN,MAAM;QACN,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,GAAG;KACX,CAAC,CAAA;IAEF,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAA;IAE3D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;AACzB,CAAC","sourcesContent":["import { ObjectLiteral } from 'typeorm'\n\nimport { Domain, ListParam, getQueryBuilderFromListParams, getRepository } from '@things-factory/shell'\n\nimport { masterAxisOf } from './master-axis'\nimport { listEffectiveRecipes } from './recipe/recipe-effective-list'\nimport { listEffectiveMaterialDefinitions } from './material/material-effective-list'\n\n/**\n * λ§ˆμŠ€ν„° ν•œ 좕을 λͺ©λ‘μœΌλ‘œ μ½λŠ”λ‹€ β€” **열두 좕이 같은 ν•¨μˆ˜λ₯Ό μ“΄λ‹€.**\n *\n * 총 건수λ₯Ό ν•¨κ»˜ λ‚Έλ‹€. 화면이 γ€Œλͺ‡ 건 쀑 λͺ‡ 건을 보고 μžˆλ‚˜γ€λ₯Ό λ§ν•˜λ €λ©΄ κ·Έ 값이 μžˆμ–΄μ•Ό ν•˜κ³ , μ—†μœΌλ©΄\n * 잘린 λͺ©λ‘κ³Ό γ€Œμ΄κ²Œ 전뢀」λ₯Ό ꡬ별할 수 μ—†λ‹€.\n */\nexport async function listMaster(\n axisKey: string,\n params: ListParam,\n domain: Domain\n): Promise<{ items: ObjectLiteral[]; total: number }> {\n const axis = masterAxisOf(axisKey)\n if (axisKey === 'recipeDefinition') return listEffectiveRecipes(getRepository(axis.entity).manager, domain, params)\n if (axisKey === 'materialDefinition') return listEffectiveMaterialDefinitions(getRepository(axis.entity).manager, domain, params)\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(axis.entity),\n params,\n domain,\n searchables: axis.searchables,\n alias: 'm'\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n}\n"]}
@@ -2,5 +2,6 @@ import { MaterialClass } from './material-class';
2
2
  import { MaterialDefinition } from './material-definition';
3
3
  import { MaterialQuery } from './material-query';
4
4
  import { MaterialClassResolver, MaterialDefinitionResolver } from './material-master-resolver';
5
- export declare const entities: (typeof MaterialDefinition | typeof MaterialClass)[];
6
- export declare const resolvers: (typeof MaterialQuery | typeof MaterialClassResolver | typeof MaterialDefinitionResolver)[];
5
+ import { MaterialDefinitionRevisionResolver } from './material-revision-resolver';
6
+ export declare const entities: (typeof MaterialClass | typeof MaterialDefinition | typeof import("./material-revision").MaterialDefinitionRevision | typeof import("./material-revision").MaterialDefinitionPlan | typeof import("./material-revision").MaterialDefinitionSegment | typeof import("./material-revision").MaterialDefinitionBasis)[];
7
+ export declare const resolvers: (typeof MaterialClassResolver | typeof MaterialDefinitionResolver | typeof MaterialDefinitionRevisionResolver | typeof MaterialQuery)[];
@@ -5,6 +5,8 @@ const material_class_1 = require("./material-class");
5
5
  const material_definition_1 = require("./material-definition");
6
6
  const material_query_1 = require("./material-query");
7
7
  const material_master_resolver_1 = require("./material-master-resolver");
8
- exports.entities = [material_class_1.MaterialClass, material_definition_1.MaterialDefinition];
9
- exports.resolvers = [material_query_1.MaterialQuery, material_master_resolver_1.MaterialClassResolver, material_master_resolver_1.MaterialDefinitionResolver];
8
+ const material_revision_1 = require("./material-revision");
9
+ const material_revision_resolver_1 = require("./material-revision-resolver");
10
+ exports.entities = [material_class_1.MaterialClass, material_definition_1.MaterialDefinition, ...material_revision_1.MATERIAL_REVISION_ENTITIES];
11
+ exports.resolvers = [material_query_1.MaterialQuery, material_master_resolver_1.MaterialClassResolver, material_master_resolver_1.MaterialDefinitionResolver, material_revision_resolver_1.MaterialDefinitionRevisionResolver];
10
12
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/material/index.ts"],"names":[],"mappings":";;;AAAA,qDAAgD;AAChD,+DAA0D;AAC1D,qDAAgD;AAChD,yEAA8F;AAEjF,QAAA,QAAQ,GAAG,CAAC,8BAAa,EAAE,wCAAkB,CAAC,CAAA;AAC9C,QAAA,SAAS,GAAG,CAAC,8BAAa,EAAE,gDAAqB,EAAE,qDAA0B,CAAC,CAAA","sourcesContent":["import { MaterialClass } from './material-class'\nimport { MaterialDefinition } from './material-definition'\nimport { MaterialQuery } from './material-query'\nimport { MaterialClassResolver, MaterialDefinitionResolver } from './material-master-resolver'\n\nexport const entities = [MaterialClass, MaterialDefinition]\nexport const resolvers = [MaterialQuery, MaterialClassResolver, MaterialDefinitionResolver]\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/material/index.ts"],"names":[],"mappings":";;;AAAA,qDAAgD;AAChD,+DAA0D;AAC1D,qDAAgD;AAChD,yEAA8F;AAC9F,2DAAgE;AAChE,6EAAiF;AAEpE,QAAA,QAAQ,GAAG,CAAC,8BAAa,EAAE,wCAAkB,EAAE,GAAG,8CAA0B,CAAC,CAAA;AAC7E,QAAA,SAAS,GAAG,CAAC,8BAAa,EAAE,gDAAqB,EAAE,qDAA0B,EAAE,+DAAkC,CAAC,CAAA","sourcesContent":["import { MaterialClass } from './material-class'\nimport { MaterialDefinition } from './material-definition'\nimport { MaterialQuery } from './material-query'\nimport { MaterialClassResolver, MaterialDefinitionResolver } from './material-master-resolver'\nimport { MATERIAL_REVISION_ENTITIES } from './material-revision'\nimport { MaterialDefinitionRevisionResolver } from './material-revision-resolver'\n\nexport const entities = [MaterialClass, MaterialDefinition, ...MATERIAL_REVISION_ENTITIES]\nexport const resolvers = [MaterialQuery, MaterialClassResolver, MaterialDefinitionResolver, MaterialDefinitionRevisionResolver]\n"]}
@@ -0,0 +1,8 @@
1
+ import { EntityManager } from 'typeorm';
2
+ /** Future activation changes the stamp without rewriting identity rows or running a midnight job. */
3
+ export declare function materialAxisStatus(manager: EntityManager, domainId: string, at?: Date): Promise<{
4
+ changedAt?: Date;
5
+ axis: string;
6
+ count: number;
7
+ stamp: string;
8
+ }>;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.materialAxisStatus = materialAxisStatus;
4
+ const material_definition_1 = require("./material-definition");
5
+ const material_revision_1 = require("./material-revision");
6
+ /** Future activation changes the stamp without rewriting identity rows or running a midnight job. */
7
+ async function materialAxisStatus(manager, domainId, at = new Date()) {
8
+ const row = await manager.createQueryBuilder(material_definition_1.MaterialDefinition, 'm')
9
+ .leftJoin(material_revision_1.MaterialDefinitionPlan, 'p', 'p.material_id = m.id AND p.domain_id = m.domain_id AND p.generation = m.plan_generation')
10
+ .leftJoin(material_revision_1.MaterialDefinitionSegment, 's', 's.plan_id = p.id AND s.validFrom <= :at AND (s.validTo IS NULL OR s.validTo > :at)', { at })
11
+ .leftJoin(material_revision_1.MaterialDefinitionRevision, 'r', 'r.id = s.revision_id')
12
+ .select('COUNT(r.id)', 'count').addSelect('SUM(r.revisionNumber)', 'revisionSum')
13
+ .addSelect('SUM(m.planGeneration)', 'generationSum').addSelect('MAX(p.recordedAt)', 'changedAt')
14
+ .where('m.domain_id = :domainId', { domainId }).getRawOne();
15
+ return { axis: 'materialDefinitions', count: Number(row.count),
16
+ stamp: JSON.stringify([row.count, row.revisionSum, row.generationSum, row.changedAt]),
17
+ ...(row.changedAt ? { changedAt: new Date(row.changedAt) } : {}) };
18
+ }
19
+ //# sourceMappingURL=material-axis-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material-axis-status.js","sourceRoot":"","sources":["../../../server/service/material/material-axis-status.ts"],"names":[],"mappings":";;AAKA,gDAWC;AAfD,+DAA0D;AAC1D,2DAAmH;AAEnH,qGAAqG;AAC9F,KAAK,UAAU,kBAAkB,CAAC,OAAsB,EAAE,QAAgB,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE;IAChG,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,kBAAkB,CAAC,wCAAkB,EAAE,GAAG,CAAC;SAClE,QAAQ,CAAC,0CAAsB,EAAE,GAAG,EAAE,yFAAyF,CAAC;SAChI,QAAQ,CAAC,6CAAyB,EAAE,GAAG,EAAE,oFAAoF,EAAE,EAAE,EAAE,EAAE,CAAC;SACtI,QAAQ,CAAC,8CAA0B,EAAE,GAAG,EAAE,sBAAsB,CAAC;SACjE,MAAM,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,uBAAuB,EAAE,aAAa,CAAC;SAChF,SAAS,CAAC,uBAAuB,EAAE,eAAe,CAAC,CAAC,SAAS,CAAC,mBAAmB,EAAE,WAAW,CAAC;SAC/F,KAAK,CAAC,yBAAyB,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE,CAAA;IAC7D,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;QAC5D,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QACrF,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;AACtE,CAAC","sourcesContent":["import { EntityManager } from 'typeorm'\nimport { MaterialDefinition } from './material-definition'\nimport { MaterialDefinitionPlan, MaterialDefinitionRevision, MaterialDefinitionSegment } from './material-revision'\n\n/** Future activation changes the stamp without rewriting identity rows or running a midnight job. */\nexport async function materialAxisStatus(manager: EntityManager, domainId: string, at = new Date()) {\n const row = await manager.createQueryBuilder(MaterialDefinition, 'm')\n .leftJoin(MaterialDefinitionPlan, 'p', 'p.material_id = m.id AND p.domain_id = m.domain_id AND p.generation = m.plan_generation')\n .leftJoin(MaterialDefinitionSegment, 's', 's.plan_id = p.id AND s.validFrom <= :at AND (s.validTo IS NULL OR s.validTo > :at)', { at })\n .leftJoin(MaterialDefinitionRevision, 'r', 'r.id = s.revision_id')\n .select('COUNT(r.id)', 'count').addSelect('SUM(r.revisionNumber)', 'revisionSum')\n .addSelect('SUM(m.planGeneration)', 'generationSum').addSelect('MAX(p.recordedAt)', 'changedAt')\n .where('m.domain_id = :domainId', { domainId }).getRawOne()\n return { axis: 'materialDefinitions', count: Number(row.count),\n stamp: JSON.stringify([row.count, row.revisionSum, row.generationSum, row.changedAt]),\n ...(row.changedAt ? { changedAt: new Date(row.changedAt) } : {}) }\n}\n"]}
@@ -10,6 +10,9 @@ import { User } from '@things-factory/auth-base';
10
10
  * GTIN 을 λ§Œλ“€μ§€ μ•ŠλŠ”λ‹€.** μ§€μ–΄λ‚Έ μ‹λ³„μžλŠ” λ‚˜μ€‘μ— μ§„μ§œ μ½”λ“œκ°€ 왔을 λ•Œ 두 κ°œκ°€ λœλ‹€.
11
11
  */
12
12
  export declare class MaterialDefinition {
13
+ revisionNumber?: number;
14
+ planGeneration: number;
15
+ revisionLock: number;
13
16
  readonly id: string;
14
17
  domain?: Domain;
15
18
  domainId?: string;
@@ -18,6 +18,18 @@ const auth_base_1 = require("@things-factory/auth-base");
18
18
  let MaterialDefinition = class MaterialDefinition {
19
19
  };
20
20
  exports.MaterialDefinition = MaterialDefinition;
21
+ tslib_1.__decorate([
22
+ (0, type_graphql_1.Field)(() => type_graphql_1.Int, { nullable: true }),
23
+ tslib_1.__metadata("design:type", Number)
24
+ ], MaterialDefinition.prototype, "revisionNumber", void 0);
25
+ tslib_1.__decorate([
26
+ (0, typeorm_1.Column)('int', { default: 0 }),
27
+ tslib_1.__metadata("design:type", Number)
28
+ ], MaterialDefinition.prototype, "planGeneration", void 0);
29
+ tslib_1.__decorate([
30
+ (0, typeorm_1.Column)('int', { default: 0 }),
31
+ tslib_1.__metadata("design:type", Number)
32
+ ], MaterialDefinition.prototype, "revisionLock", void 0);
21
33
  tslib_1.__decorate([
22
34
  (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
23
35
  (0, type_graphql_1.Field)(type => type_graphql_1.ID),
@@ -104,6 +116,7 @@ tslib_1.__decorate([
104
116
  ], MaterialDefinition.prototype, "updaterId", void 0);
105
117
  exports.MaterialDefinition = MaterialDefinition = tslib_1.__decorate([
106
118
  (0, typeorm_1.Entity)({ name: 'ops_material_definition' }),
119
+ (0, typeorm_1.Index)('ix_ops_material_domain_identity', ['domain', 'id'], { unique: true }),
107
120
  (0, typeorm_1.Index)('ix_ops_material_definition_0', (material) => [material.domain, material.name], {
108
121
  unique: true
109
122
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"material-definition.js","sourceRoot":"","sources":["../../../server/service/material/material-definition.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\nimport { Field, ID, ObjectType } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\n\n/**\n * ν’ˆλͺ© μ •μ˜ β€” **ISA-95 `MaterialDefinition`**.\n *\n * μ‹λ³„μžλŠ” **GTIN** 이닀(`urn:epc:idpat:sgtin:…`). μ •μ²΄μ„±μ˜ 기쀀이 EPCIS 이기 λ•Œλ¬Έμ΄κ³ , 사건과 λ§ˆμŠ€ν„°κ°€\n * 같은 이름을 써야 γ€Œμ΄ λ‘œνŠΈκ°€ 무엇인가」λ₯Ό 이을 수 μžˆλ‹€.\n *\n * GTIN 이 아직 μ—†λŠ” ν’ˆλͺ©μ€ λΉ„μ›Œ 두지 μ•Šκ³  사내 μ½”λ“œλ₯Ό `name` 에 적되, **νšŒμ‚¬ ν”„λ¦¬ν”½μŠ€λ₯Ό μ§€μ–΄λ‚΄\n * GTIN 을 λ§Œλ“€μ§€ μ•ŠλŠ”λ‹€.** μ§€μ–΄λ‚Έ μ‹λ³„μžλŠ” λ‚˜μ€‘μ— μ§„μ§œ μ½”λ“œκ°€ 왔을 λ•Œ 두 κ°œκ°€ λœλ‹€.\n */\n@Entity({ name: 'ops_material_definition' })\n@Index('ix_ops_material_definition_0', (material: MaterialDefinition) => [material.domain, material.name], {\n unique: true\n})\n@ObjectType({ description: 'ISA-95 MaterialDefinition β€” what a material is' })\nexport class MaterialDefinition {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain)\n domain?: Domain\n\n @RelationId((material: MaterialDefinition) => material.domain)\n domainId?: string\n\n /** ν‘œμ€€ `ID` β€” GTIN 이 있으면 GTIN 이닀. 트윈으둜 λ‚˜κ°ˆ λ•Œ `materialDefinitions[].id` κ°€ λœλ‹€. */\n @Column()\n @Field()\n name: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n /** μ†ν•œ λ“±κΈ‰λ“€ β€” ν‘œμ€€ `MaterialClassID`(볡수). */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => [String], { nullable: true })\n materialClassIds?: string[]\n\n /**\n * ν’ˆλͺ© 속성 β€” ν‘œμ€€ `MaterialDefinitionProperty`. **ν™˜μ‚° κ³„μˆ˜κ°€ μ—¬κΈ° λ“€μ–΄κ°„λ‹€.**\n *\n * 계약이 μ •ν•œ 이름은 `perBaseUnit` 이고, 값은 κΈ°μ€€ λ‹¨μœ„ ν•˜λ‚˜λ‹Ή κ·Έ λ‹¨μœ„μ˜ 양이닀.\n * ν•œ 개(EA)κ°€ 2.5 kg 이면 `{ id: 'perBaseUnit', value: 2.5, uom: 'KGM' }`.\n */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'ResourceProperty[]' })\n properties?: Record<string, unknown>[]\n\n /** 적격을 κ²€μ¦ν•˜λŠ” `TestSpecification` μ°Έμ‘°λ“€ β€” μž…κ³  검사가 이 λͺ¨μ–‘에 λ§žλŠ”λ‹€. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => [String], { nullable: true })\n testSpecificationIds?: string[]\n\n /** `TestResult` β€” 참쑰만 있으면 γ€Œλ¬΄μ—‡μœΌλ‘œ κ²€μ¦ν•œλ‹€γ€κΉŒμ§€κ³ , κ²°κ³Όκ°€ μžˆμ–΄μ•Ό 적격이 μ„±λ¦½ν•œλ‹€. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'TestResult[]' })\n testResults?: Record<string, unknown>[]\n\n /** μ–Έμ œλΆ€ν„° 이 ν’ˆλͺ©μ„ μ“°λ‚˜ β€” ν‘œμ€€ `EffectiveStartDate`. 단쒅 μ˜ˆμ • ν’ˆλͺ©μ„ 미리 적을 수 μžˆλ‹€. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveStart?: Date\n\n /** μ–Έμ œκΉŒμ§€ β€” ν‘œμ€€ `EffectiveEndDate`. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveEnd?: Date\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((material: MaterialDefinition) => material.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((material: MaterialDefinition) => material.updater)\n updaterId?: string\n}\n"]}
1
+ {"version":3,"file":"material-definition.js","sourceRoot":"","sources":["../../../server/service/material/material-definition.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\nimport { Field, ID, Int, ObjectType } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\n\n/**\n * ν’ˆλͺ© μ •μ˜ β€” **ISA-95 `MaterialDefinition`**.\n *\n * μ‹λ³„μžλŠ” **GTIN** 이닀(`urn:epc:idpat:sgtin:…`). μ •μ²΄μ„±μ˜ 기쀀이 EPCIS 이기 λ•Œλ¬Έμ΄κ³ , 사건과 λ§ˆμŠ€ν„°κ°€\n * 같은 이름을 써야 γ€Œμ΄ λ‘œνŠΈκ°€ 무엇인가」λ₯Ό 이을 수 μžˆλ‹€.\n *\n * GTIN 이 아직 μ—†λŠ” ν’ˆλͺ©μ€ λΉ„μ›Œ 두지 μ•Šκ³  사내 μ½”λ“œλ₯Ό `name` 에 적되, **νšŒμ‚¬ ν”„λ¦¬ν”½μŠ€λ₯Ό μ§€μ–΄λ‚΄\n * GTIN 을 λ§Œλ“€μ§€ μ•ŠλŠ”λ‹€.** μ§€μ–΄λ‚Έ μ‹λ³„μžλŠ” λ‚˜μ€‘μ— μ§„μ§œ μ½”λ“œκ°€ 왔을 λ•Œ 두 κ°œκ°€ λœλ‹€.\n */\n@Entity({ name: 'ops_material_definition' })\n@Index('ix_ops_material_domain_identity', ['domain', 'id'], { unique: true })\n@Index('ix_ops_material_definition_0', (material: MaterialDefinition) => [material.domain, material.name], {\n unique: true\n})\n@ObjectType({ description: 'ISA-95 MaterialDefinition β€” what a material is' })\nexport class MaterialDefinition {\n @Field(() => Int, { nullable: true })\n revisionNumber?: number\n\n @Column('int', { default: 0 })\n planGeneration: number\n\n @Column('int', { default: 0 })\n revisionLock: number\n\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain)\n domain?: Domain\n\n @RelationId((material: MaterialDefinition) => material.domain)\n domainId?: string\n\n /** ν‘œμ€€ `ID` β€” GTIN 이 있으면 GTIN 이닀. 트윈으둜 λ‚˜κ°ˆ λ•Œ `materialDefinitions[].id` κ°€ λœλ‹€. */\n @Column()\n @Field()\n name: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n /** μ†ν•œ λ“±κΈ‰λ“€ β€” ν‘œμ€€ `MaterialClassID`(볡수). */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => [String], { nullable: true })\n materialClassIds?: string[]\n\n /**\n * ν’ˆλͺ© 속성 β€” ν‘œμ€€ `MaterialDefinitionProperty`. **ν™˜μ‚° κ³„μˆ˜κ°€ μ—¬κΈ° λ“€μ–΄κ°„λ‹€.**\n *\n * 계약이 μ •ν•œ 이름은 `perBaseUnit` 이고, 값은 κΈ°μ€€ λ‹¨μœ„ ν•˜λ‚˜λ‹Ή κ·Έ λ‹¨μœ„μ˜ 양이닀.\n * ν•œ 개(EA)κ°€ 2.5 kg 이면 `{ id: 'perBaseUnit', value: 2.5, uom: 'KGM' }`.\n */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'ResourceProperty[]' })\n properties?: Record<string, unknown>[]\n\n /** 적격을 κ²€μ¦ν•˜λŠ” `TestSpecification` μ°Έμ‘°λ“€ β€” μž…κ³  검사가 이 λͺ¨μ–‘에 λ§žλŠ”λ‹€. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => [String], { nullable: true })\n testSpecificationIds?: string[]\n\n /** `TestResult` β€” 참쑰만 있으면 γ€Œλ¬΄μ—‡μœΌλ‘œ κ²€μ¦ν•œλ‹€γ€κΉŒμ§€κ³ , κ²°κ³Όκ°€ μžˆμ–΄μ•Ό 적격이 μ„±λ¦½ν•œλ‹€. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'TestResult[]' })\n testResults?: Record<string, unknown>[]\n\n /** μ–Έμ œλΆ€ν„° 이 ν’ˆλͺ©μ„ μ“°λ‚˜ β€” ν‘œμ€€ `EffectiveStartDate`. 단쒅 μ˜ˆμ • ν’ˆλͺ©μ„ 미리 적을 수 μžˆλ‹€. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveStart?: Date\n\n /** μ–Έμ œκΉŒμ§€ β€” ν‘œμ€€ `EffectiveEndDate`. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveEnd?: Date\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((material: MaterialDefinition) => material.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((material: MaterialDefinition) => material.updater)\n updaterId?: string\n}\n"]}
@@ -0,0 +1,39 @@
1
+ import { EntityManager } from 'typeorm';
2
+ import { Domain, ListParam } from '@things-factory/shell';
3
+ import { MaterialDefinition } from './material-definition';
4
+ /** Filter, sort, paginate and display the same time projection. No per-row resolution queries. */
5
+ export declare function listEffectiveMaterialDefinitions(manager: EntityManager, domain: Domain, params: ListParam, at?: Date): Promise<{
6
+ items: (MaterialDefinition & {
7
+ revisionNumber?: number;
8
+ planGeneration: number;
9
+ revisionLock: number;
10
+ id: string;
11
+ domain?: Domain;
12
+ domainId?: string;
13
+ name: string;
14
+ description?: string;
15
+ materialClassIds?: string[];
16
+ properties?: Record<string, unknown>[];
17
+ testSpecificationIds?: string[];
18
+ testResults?: Record<string, unknown>[];
19
+ effectiveStart?: Date;
20
+ effectiveEnd?: Date;
21
+ createdAt?: Date;
22
+ updatedAt?: Date;
23
+ creator?: import("@things-factory/auth-base").User;
24
+ creatorId?: string;
25
+ updater?: import("@things-factory/auth-base").User;
26
+ updaterId?: string;
27
+ } & {
28
+ description: string;
29
+ revisionNumber: number;
30
+ materialClassIds: string[];
31
+ properties: Record<string, unknown>[];
32
+ testSpecificationIds: string[];
33
+ effectiveStart: Date;
34
+ effectiveEnd: Date;
35
+ })[];
36
+ total: number;
37
+ }>;
38
+ /** Bounded name selection for planning/readiness, without projecting every material row. */
39
+ export declare function effectiveMaterialNames(manager: EntityManager, domainId: string, names: string[], at?: Date): Promise<string[]>;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listEffectiveMaterialDefinitions = listEffectiveMaterialDefinitions;
4
+ exports.effectiveMaterialNames = effectiveMaterialNames;
5
+ const shell_1 = require("@things-factory/shell");
6
+ const material_definition_1 = require("./material-definition");
7
+ const material_revision_1 = require("./material-revision");
8
+ /** Filter, sort, paginate and display the same time projection. No per-row resolution queries. */
9
+ async function listEffectiveMaterialDefinitions(manager, domain, params, at = new Date()) {
10
+ const query = (0, shell_1.getQueryBuilderFromListParams)({
11
+ repository: manager.getRepository(material_definition_1.MaterialDefinition),
12
+ domain,
13
+ params,
14
+ alias: 'material',
15
+ searchables: ['name', 'description'],
16
+ sortables: ['id', 'name', 'revisionNumber', 'description', 'effectiveStart', 'effectiveEnd', 'createdAt', 'updatedAt'],
17
+ columnExpressions: {
18
+ revisionNumber: 'revision.revisionNumber',
19
+ description: 'revision.description',
20
+ effectiveStart: 'segment.validFrom',
21
+ effectiveEnd: 'segment.validTo'
22
+ }
23
+ });
24
+ query
25
+ .leftJoin(material_revision_1.MaterialDefinitionPlan, 'plan', 'plan.material_id = material.id AND plan.domain_id = material.domain_id AND plan.generation = material.plan_generation')
26
+ .leftJoinAndMapOne('material.selectedSegment', material_revision_1.MaterialDefinitionSegment, 'segment', 'segment.plan_id = plan.id AND segment.validFrom <= :at AND (segment.validTo IS NULL OR segment.validTo > :at)', { at })
27
+ .leftJoinAndMapOne('material.selectedRevision', material_revision_1.MaterialDefinitionRevision, 'revision', 'revision.id = segment.revision_id');
28
+ const [rows, total] = await query.getManyAndCount();
29
+ const items = rows.map(row => {
30
+ const { selectedRevision, selectedSegment, ...identity } = row;
31
+ return Object.assign(new material_definition_1.MaterialDefinition(), identity, {
32
+ description: selectedRevision?.description ?? null,
33
+ revisionNumber: selectedRevision?.revisionNumber ?? null,
34
+ materialClassIds: selectedRevision?.materialClassIds ?? [],
35
+ properties: selectedRevision?.properties ?? [],
36
+ testSpecificationIds: selectedRevision?.testSpecificationIds ?? [],
37
+ effectiveStart: selectedSegment?.validFrom ?? null,
38
+ effectiveEnd: selectedSegment?.validTo ?? null
39
+ });
40
+ });
41
+ return { items, total };
42
+ }
43
+ /** Bounded name selection for planning/readiness, without projecting every material row. */
44
+ async function effectiveMaterialNames(manager, domainId, names, at = new Date()) {
45
+ if (!names.length)
46
+ return [];
47
+ const rows = await manager.createQueryBuilder(material_definition_1.MaterialDefinition, 'm')
48
+ .innerJoin(material_revision_1.MaterialDefinitionPlan, 'p', 'p.material_id = m.id AND p.domain_id = m.domain_id AND p.generation = m.plan_generation')
49
+ .innerJoin(material_revision_1.MaterialDefinitionSegment, 's', 's.plan_id = p.id AND s.validFrom <= :at AND (s.validTo IS NULL OR s.validTo > :at)', { at })
50
+ .where('m.domain_id = :domainId', { domainId }).andWhere('m.name IN (:...names)', { names })
51
+ .select('m.name', 'name').getRawMany();
52
+ return rows.map(row => row.name);
53
+ }
54
+ //# sourceMappingURL=material-effective-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material-effective-list.js","sourceRoot":"","sources":["../../../server/service/material/material-effective-list.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager } from 'typeorm'\nimport { Domain, getQueryBuilderFromListParams, ListParam } from '@things-factory/shell'\nimport { MaterialDefinition } from './material-definition'\nimport { MaterialDefinitionPlan, MaterialDefinitionRevision, MaterialDefinitionSegment } from './material-revision'\n\ntype EffectiveRow = MaterialDefinition & {\n selectedRevision?: MaterialDefinitionRevision\n selectedSegment?: MaterialDefinitionSegment\n}\n\n/** Filter, sort, paginate and display the same time projection. No per-row resolution queries. */\nexport async function listEffectiveMaterialDefinitions(\n manager: EntityManager,\n domain: Domain,\n params: ListParam,\n at = new Date()\n) {\n const query = getQueryBuilderFromListParams({\n repository: manager.getRepository(MaterialDefinition),\n domain,\n params,\n alias: 'material',\n searchables: ['name', 'description'],\n sortables: ['id', 'name', 'revisionNumber', 'description', 'effectiveStart', 'effectiveEnd', 'createdAt', 'updatedAt'],\n columnExpressions: {\n revisionNumber: 'revision.revisionNumber',\n description: 'revision.description',\n effectiveStart: 'segment.validFrom',\n effectiveEnd: 'segment.validTo'\n }\n })\n query\n .leftJoin(\n MaterialDefinitionPlan,\n 'plan',\n 'plan.material_id = material.id AND plan.domain_id = material.domain_id AND plan.generation = material.plan_generation'\n )\n .leftJoinAndMapOne(\n 'material.selectedSegment',\n MaterialDefinitionSegment,\n 'segment',\n 'segment.plan_id = plan.id AND segment.validFrom <= :at AND (segment.validTo IS NULL OR segment.validTo > :at)',\n { at }\n )\n .leftJoinAndMapOne(\n 'material.selectedRevision',\n MaterialDefinitionRevision,\n 'revision',\n 'revision.id = segment.revision_id'\n )\n const [rows, total] = await query.getManyAndCount()\n const items = (rows as EffectiveRow[]).map(row => {\n const { selectedRevision, selectedSegment, ...identity } = row\n return Object.assign(new MaterialDefinition(), identity, {\n description: selectedRevision?.description ?? null,\n revisionNumber: selectedRevision?.revisionNumber ?? null,\n materialClassIds: selectedRevision?.materialClassIds ?? [],\n properties: selectedRevision?.properties ?? [],\n testSpecificationIds: selectedRevision?.testSpecificationIds ?? [],\n effectiveStart: selectedSegment?.validFrom ?? null,\n effectiveEnd: selectedSegment?.validTo ?? null\n })\n })\n return { items, total }\n}\n\n/** Bounded name selection for planning/readiness, without projecting every material row. */\nexport async function effectiveMaterialNames(manager: EntityManager, domainId: string, names: string[], at = new Date()): Promise<string[]> {\n if (!names.length) return []\n const rows = await manager.createQueryBuilder(MaterialDefinition, 'm')\n .innerJoin(MaterialDefinitionPlan, 'p', 'p.material_id = m.id AND p.domain_id = m.domain_id AND p.generation = m.plan_generation')\n .innerJoin(MaterialDefinitionSegment, 's', 's.plan_id = p.id AND s.validFrom <= :at AND (s.validTo IS NULL OR s.validTo > :at)', { at })\n .where('m.domain_id = :domainId', { domainId }).andWhere('m.name IN (:...names)', { names })\n .select('m.name', 'name').getRawMany<{ name: string }>()\n return rows.map(row => row.name)\n}\n"]}