FPSMS-frontend
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 

242 rindas
7.0 KiB

  1. "use client";
  2. import { NEXT_PUBLIC_API_URL } from "@/config/api";
  3. import { clientAuthFetch } from "@/app/utils/clientAuthFetch";
  4. import { buildItemCodePasteRequestBody } from "./parseItemCodeTokens";
  5. import {
  6. exportMultiSheetToXlsx,
  7. } from "@/app/(main)/chart/_components/exportChartToXlsx";
  8. import { reportExcelT as tx } from "./reportI18n";
  9. import type { TFunction } from "i18next";
  10. export interface BomShopSyncReportSummary {
  11. totalAttempts?: number;
  12. success?: number;
  13. skippedUnchanged?: number;
  14. failed?: number;
  15. syncDateStart?: string;
  16. syncDateEnd?: string;
  17. }
  18. export interface BomShopSyncRow {
  19. syncLogId?: number;
  20. syncDateTime?: string;
  21. bomId?: number;
  22. bomRoutingCode?: string;
  23. finishedItemCode?: string;
  24. finishedItemName?: string;
  25. m18HeaderCode?: string;
  26. version?: string;
  27. m18RecordId?: number;
  28. syncStatus?: string;
  29. synced?: boolean;
  30. m18ApiStatus?: boolean;
  31. failureReason?: string;
  32. message?: string;
  33. }
  34. export interface BomShopSyncMaterialRow {
  35. syncLogId?: number;
  36. syncDateTime?: string;
  37. bomId?: number;
  38. finishedItemCode?: string;
  39. m18HeaderCode?: string;
  40. version?: string;
  41. syncStatus?: string;
  42. lineNo?: string;
  43. materialName?: string;
  44. udfProductM18Id?: number;
  45. udfBaseUnit?: string;
  46. udfQty?: number;
  47. udfSupplierM18Id?: number;
  48. udfPurchaseUnitM18Id?: number;
  49. }
  50. export interface BomShopSyncReportResponse {
  51. summary?: BomShopSyncReportSummary;
  52. syncRows?: BomShopSyncRow[];
  53. materialRows?: BomShopSyncMaterialRow[];
  54. }
  55. function bomSyncLabels(t?: TFunction) {
  56. return {
  57. sheetSync: tx(t, "excel.bomSync.sheetSync", "BOM同步記錄"),
  58. sheetMaterials: tx(t, "excel.bomSync.sheetMaterials", "BOM物料明細"),
  59. noData: tx(t, "excel.noData", "(篩選範圍內無資料)"),
  60. syncTime: tx(t, "excel.bomSync.syncTime", "同步時間"),
  61. finishedItemCode: tx(t, "excel.bomSync.finishedItemCode", "成品貨號"),
  62. finishedItemName: tx(t, "excel.bomSync.finishedItemName", "成品名稱"),
  63. bomRoutingCode: tx(t, "excel.bomSync.bomRoutingCode", "BOM路由編號"),
  64. version: tx(t, "excel.bomSync.version", "版本"),
  65. status: tx(t, "excel.bomSync.status", "狀態"),
  66. failureReason: tx(t, "excel.bomSync.failureReason", "失敗原因"),
  67. message: tx(t, "excel.bomSync.message", "訊息"),
  68. lineNo: tx(t, "excel.bomSync.lineNo", "行號"),
  69. materialName: tx(t, "excel.bomSync.materialName", "物料名稱"),
  70. uom: tx(t, "excel.bomSync.uom", "單位"),
  71. qty: tx(t, "excel.bomSync.qty", "用量"),
  72. statusSuccess: tx(t, "excel.bomSync.statusSuccess", "成功"),
  73. statusSkipped: tx(t, "excel.bomSync.statusSkipped", "略過(內容未變)"),
  74. statusFailed: tx(t, "excel.bomSync.statusFailed", "失敗"),
  75. };
  76. }
  77. function emptySyncSheetRow(
  78. L: ReturnType<typeof bomSyncLabels>,
  79. note?: string,
  80. ): Record<string, unknown> {
  81. return {
  82. [L.syncTime]: note ?? L.noData,
  83. [L.finishedItemCode]: "",
  84. [L.finishedItemName]: "",
  85. [L.bomRoutingCode]: "",
  86. "M18 BOM Code": "",
  87. [L.version]: "",
  88. "M18 Record Id": "",
  89. [L.status]: "",
  90. [L.failureReason]: "",
  91. [L.message]: "",
  92. "BOM Id": "",
  93. "Sync Log Id": "",
  94. };
  95. }
  96. function emptyMaterialSheetRow(
  97. L: ReturnType<typeof bomSyncLabels>,
  98. note?: string,
  99. ): Record<string, unknown> {
  100. return {
  101. [L.syncTime]: note ?? L.noData,
  102. [L.finishedItemCode]: "",
  103. "M18 BOM Code": "",
  104. [L.version]: "",
  105. [L.status]: "",
  106. [L.lineNo]: "",
  107. [L.materialName]: "",
  108. "M18 Product Id": "",
  109. [L.uom]: "",
  110. [L.qty]: "",
  111. "M18 Supplier Id": "",
  112. "M18 Purchase Unit Id": "",
  113. "Sync Log Id": "",
  114. };
  115. }
  116. export async function fetchBomShopSyncReportData(
  117. criteria: Record<string, string>,
  118. ): Promise<BomShopSyncReportResponse> {
  119. const url = `${NEXT_PUBLIC_API_URL}/report/bom-shop-sync-history`;
  120. const response = await clientAuthFetch(url, {
  121. method: "POST",
  122. headers: {
  123. Accept: "application/json",
  124. "Content-Type": "application/json",
  125. },
  126. body: JSON.stringify(buildItemCodePasteRequestBody(criteria, "finishedItemCode")),
  127. });
  128. if (response.status === 401 || response.status === 403)
  129. throw new Error("Unauthorized");
  130. if (!response.ok)
  131. throw new Error(`HTTP error! status: ${response.status}`);
  132. return (await response.json()) as BomShopSyncReportResponse;
  133. }
  134. function syncStatusLabel(
  135. status: string | undefined,
  136. L: ReturnType<typeof bomSyncLabels>,
  137. ): string {
  138. switch (status) {
  139. case "SUCCESS":
  140. return L.statusSuccess;
  141. case "SKIPPED_UNCHANGED":
  142. return L.statusSkipped;
  143. case "FAILED":
  144. return L.statusFailed;
  145. default:
  146. return status ?? "";
  147. }
  148. }
  149. function toSyncExcelRow(
  150. r: BomShopSyncRow,
  151. L: ReturnType<typeof bomSyncLabels>,
  152. ): Record<string, unknown> {
  153. return {
  154. ...emptySyncSheetRow(L, ""),
  155. [L.syncTime]: r.syncDateTime ?? "",
  156. [L.finishedItemCode]: r.finishedItemCode ?? "",
  157. [L.finishedItemName]: r.finishedItemName ?? "",
  158. [L.bomRoutingCode]: r.bomRoutingCode ?? "",
  159. "M18 BOM Code": r.m18HeaderCode ?? "",
  160. [L.version]: r.version ?? "",
  161. "M18 Record Id": r.m18RecordId ?? "",
  162. [L.status]: syncStatusLabel(r.syncStatus, L),
  163. [L.failureReason]: r.failureReason ?? "",
  164. [L.message]: r.message ?? "",
  165. "BOM Id": r.bomId ?? "",
  166. "Sync Log Id": r.syncLogId ?? "",
  167. };
  168. }
  169. function toMaterialExcelRow(
  170. r: BomShopSyncMaterialRow,
  171. L: ReturnType<typeof bomSyncLabels>,
  172. ): Record<string, unknown> {
  173. return {
  174. ...emptyMaterialSheetRow(L, ""),
  175. [L.syncTime]: r.syncDateTime ?? "",
  176. [L.finishedItemCode]: r.finishedItemCode ?? "",
  177. "M18 BOM Code": r.m18HeaderCode ?? "",
  178. [L.version]: r.version ?? "",
  179. [L.status]: syncStatusLabel(r.syncStatus, L),
  180. [L.lineNo]: r.lineNo ?? "",
  181. [L.materialName]: r.materialName ?? "",
  182. "M18 Product Id": r.udfProductM18Id ?? "",
  183. [L.uom]: r.udfBaseUnit ?? "",
  184. [L.qty]: r.udfQty ?? "",
  185. "M18 Supplier Id": r.udfSupplierM18Id ?? "",
  186. "M18 Purchase Unit Id": r.udfPurchaseUnitM18Id ?? "",
  187. "Sync Log Id": r.syncLogId ?? "",
  188. };
  189. }
  190. export async function generateBomShopSyncReportExcel(
  191. criteria: Record<string, string>,
  192. reportTitle: string = "M18 BOM Shop 同步記錄",
  193. t?: TFunction,
  194. ): Promise<void> {
  195. const L = bomSyncLabels(t);
  196. const data = await fetchBomShopSyncReportData(criteria);
  197. const syncRows =
  198. (data.syncRows ?? []).length > 0
  199. ? (data.syncRows ?? []).map((r) => toSyncExcelRow(r, L))
  200. : [emptySyncSheetRow(L)];
  201. const materialRows =
  202. (data.materialRows ?? []).length > 0
  203. ? (data.materialRows ?? []).map((r) => toMaterialExcelRow(r, L))
  204. : [emptyMaterialSheetRow(L)];
  205. const start = criteria.syncDateStart;
  206. const end = criteria.syncDateEnd;
  207. let datePart: string;
  208. if (start && end && start === end) {
  209. datePart = start;
  210. } else if (start || end) {
  211. datePart = `${start || ""}_to_${end || ""}`;
  212. } else {
  213. datePart = new Date().toISOString().slice(0, 10);
  214. }
  215. const filename = `${reportTitle}_${datePart.replace(/[^\d\-_/]/g, "")}`;
  216. exportMultiSheetToXlsx(
  217. [
  218. { name: L.sheetSync, rows: syncRows },
  219. { name: L.sheetMaterials, rows: materialRows },
  220. ],
  221. filename,
  222. );
  223. }