FPSMS-frontend
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

220 rivejä
6.7 KiB

  1. import { z } from "zod";
  2. const nullableStr = z.string().nullable().optional();
  3. const nullableNum = z.number().nullable().optional();
  4. const ItemLotTraceOriginSchema = z
  5. .object({
  6. stockInLineId: z.number(),
  7. type: z.string(),
  8. refCode: z.string(),
  9. refId: nullableNum,
  10. supplierCode: z.string(),
  11. supplierName: z.string(),
  12. dnNo: z.string(),
  13. receiptDate: nullableStr,
  14. acceptedQty: z.number(),
  15. status: z.string(),
  16. })
  17. .passthrough();
  18. const ItemLotTraceQcResultSchema = z
  19. .object({
  20. stockInLineId: z.number(),
  21. qcPassed: z.boolean(),
  22. failQty: z.number(),
  23. acceptedQty: z.number(),
  24. remarks: z.string(),
  25. handledBy: z.string(),
  26. created: nullableStr,
  27. })
  28. .passthrough();
  29. const ItemLotTracePutawayEventSchema = z
  30. .object({
  31. inventoryLotLineId: z.number(),
  32. stockInLineId: nullableNum,
  33. warehouseCode: z.string(),
  34. qty: z.number(),
  35. handledBy: z.string(),
  36. timestamp: nullableStr,
  37. refType: z.string(),
  38. refCode: z.string(),
  39. refId: nullableNum,
  40. status: z.string().optional(),
  41. })
  42. .passthrough();
  43. const ItemLotTraceProductionStepSchema = z
  44. .object({
  45. processLineId: z.number(),
  46. stepName: z.string(),
  47. description: z.string(),
  48. equipmentCode: z.string(),
  49. equipmentName: z.string(),
  50. operatorName: z.string(),
  51. startTime: nullableStr,
  52. endTime: nullableStr,
  53. outputQty: z.number(),
  54. scrapQty: z.number(),
  55. defectQty: z.number(),
  56. status: z.string(),
  57. seqNo: nullableNum,
  58. bomProcessId: nullableNum,
  59. })
  60. .passthrough();
  61. const ItemLotTraceMaterialInputSchema: z.ZodType<Record<string, unknown>> = z.lazy(() =>
  62. z
  63. .object({
  64. jobOrderCode: z.string(),
  65. jobOrderId: nullableNum,
  66. materialItemCode: z.string(),
  67. materialItemName: z.string(),
  68. materialLotNo: z.string(),
  69. materialStockInLineId: nullableNum,
  70. materialInventoryLotId: nullableNum,
  71. materialQty: z.number(),
  72. materialUom: z.string().optional(),
  73. bomQtyPerUnit: nullableNum,
  74. bomProcessId: nullableNum,
  75. bomProcessSeqNo: nullableNum,
  76. assignedStepName: z.string().optional(),
  77. pickOrderCode: z.string(),
  78. pickOrderId: nullableNum,
  79. consoCode: z.string(),
  80. pickedAt: nullableStr,
  81. stockInOrigin: ItemLotTraceOriginSchema.nullable().optional(),
  82. purchaseEvents: z.array(z.record(z.unknown())).optional(),
  83. qcResults: z.array(ItemLotTraceQcResultSchema),
  84. putawayEvents: z.array(ItemLotTracePutawayEventSchema).optional(),
  85. nestedJoPrelude: ItemLotTraceJoPreludeSchema.nullable().optional(),
  86. productionSteps: z.array(ItemLotTraceProductionStepSchema).optional(),
  87. })
  88. .passthrough(),
  89. );
  90. const ItemLotTraceJoPreludeSchema: z.ZodType<Record<string, unknown>> = z.lazy(() =>
  91. z
  92. .object({
  93. jobOrder: z
  94. .object({
  95. jobOrderId: z.number(),
  96. jobOrderCode: z.string(),
  97. planStart: nullableStr,
  98. createdAt: nullableStr.optional(),
  99. reqQty: z.number(),
  100. status: z.string(),
  101. })
  102. .passthrough(),
  103. pickOrders: z.array(z.record(z.unknown())),
  104. materialInputs: z.array(ItemLotTraceMaterialInputSchema),
  105. })
  106. .passthrough(),
  107. );
  108. const ItemLotTraceGraphEdgeSchema = z
  109. .object({
  110. fromKey: z.string(),
  111. toKey: z.string(),
  112. kind: z.string(),
  113. })
  114. .passthrough();
  115. const ItemLotTraceGraphNodeRefSchema = z
  116. .object({
  117. key: z.string(),
  118. kind: z.string(),
  119. scopeKey: nullableStr,
  120. refCode: nullableStr,
  121. traceLotNo: nullableStr,
  122. traceItemCode: nullableStr,
  123. warehouseCode: nullableStr,
  124. })
  125. .passthrough();
  126. const ItemLotTraceGraphSchema = z
  127. .object({
  128. nodes: z.array(ItemLotTraceGraphNodeRefSchema),
  129. edges: z.array(ItemLotTraceGraphEdgeSchema),
  130. })
  131. .passthrough()
  132. .nullable()
  133. .optional();
  134. export const ItemLotTraceResponseSchema = z
  135. .object({
  136. lot: z
  137. .object({
  138. inventoryLotId: z.number(),
  139. lotNo: z.string(),
  140. itemId: z.number(),
  141. itemCode: z.string(),
  142. itemName: z.string(),
  143. expiryDate: nullableStr,
  144. productionDate: nullableStr,
  145. stockInDate: nullableStr,
  146. uom: z.string(),
  147. primaryStockInLineId: nullableNum,
  148. })
  149. .passthrough(),
  150. warehouseLines: z.array(z.record(z.unknown())),
  151. origins: z.array(ItemLotTraceOriginSchema),
  152. purchaseEvents: z.array(z.record(z.unknown())).optional(),
  153. qcResults: z.array(ItemLotTraceQcResultSchema),
  154. putawayEvents: z.array(ItemLotTracePutawayEventSchema),
  155. movements: z.array(z.record(z.unknown())),
  156. outboundUsage: z.array(z.record(z.unknown())),
  157. stockTakeEvents: z.array(z.record(z.unknown())),
  158. adjustments: z.array(z.record(z.unknown())),
  159. transfers: z.array(z.record(z.unknown())),
  160. bomTrace: z.record(z.unknown()),
  161. joPrelude: ItemLotTraceJoPreludeSchema.nullable(),
  162. productionSteps: z.array(ItemLotTraceProductionStepSchema),
  163. byproductLots: z.array(z.record(z.unknown())),
  164. openMovements: z.array(z.record(z.unknown())),
  165. failEvents: z.array(z.record(z.unknown())),
  166. doDeliveries: z.array(z.record(z.unknown())),
  167. replenishmentEvents: z.array(z.record(z.unknown())).optional(),
  168. returnEvents: z.array(z.record(z.unknown())),
  169. lotRelations: z.array(z.record(z.unknown())),
  170. alternateLocations: z.array(z.record(z.unknown())),
  171. locationBlocks: z.array(z.record(z.unknown())).optional(),
  172. traceGraph: ItemLotTraceGraphSchema,
  173. issueTrace: z
  174. .object({
  175. whereUsed: z.array(z.record(z.unknown())).optional(),
  176. downstreamDeliveries: z.array(z.record(z.unknown())).optional(),
  177. downstreamReplenishments: z.array(z.record(z.unknown())).optional(),
  178. })
  179. .passthrough()
  180. .optional(),
  181. })
  182. .passthrough();
  183. export type ItemLotTraceResponseParsed = z.infer<typeof ItemLotTraceResponseSchema>;
  184. export const parseItemLotTraceResponse = (data: unknown): ItemLotTraceResponseParsed =>
  185. ItemLotTraceResponseSchema.parse(data);
  186. /** Collect dot-path keys for contract snapshot tests. */
  187. export const collectObjectPaths = (
  188. obj: unknown,
  189. prefix = "",
  190. depth = 0,
  191. maxDepth = 6,
  192. ): string[] => {
  193. if (obj == null || depth > maxDepth) return prefix ? [prefix] : [];
  194. if (Array.isArray(obj)) {
  195. if (obj.length === 0) return prefix ? [prefix] : [];
  196. return collectObjectPaths(obj[0], prefix ? `${prefix}[]` : "[]", depth + 1, maxDepth);
  197. }
  198. if (typeof obj !== "object") return prefix ? [prefix] : [];
  199. const paths: string[] = prefix ? [prefix] : [];
  200. Object.keys(obj as Record<string, unknown>).sort().forEach((key) => {
  201. const next = prefix ? `${prefix}.${key}` : key;
  202. paths.push(...collectObjectPaths((obj as Record<string, unknown>)[key], next, depth + 1, maxDepth));
  203. });
  204. return paths;
  205. };