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.
 
 

1048 line
27 KiB

  1. "use server";
  2. import { cache } from 'react';
  3. import { Pageable, serverFetchBlob, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
  4. import { JobOrder, JoStatus, Machine, Operator } from ".";
  5. import { BASE_API_URL } from "@/config/api";
  6. import { revalidateTag } from "next/cache";
  7. import { convertObjToURLSearchParams } from "@/app/utils/commonUtil";
  8. import { FileResponse } from "@/app/api/pdf/actions";
  9. export interface SaveJo {
  10. bomId: number;
  11. planStart: string;
  12. planEnd: string;
  13. reqQty: number;
  14. type: string;
  15. //jobType?: string;
  16. jobTypeId?: number;
  17. }
  18. export interface SaveJoResponse {
  19. id: number;
  20. }
  21. export interface SearchJoResultRequest extends Pageable {
  22. code: string;
  23. itemName?: string;
  24. planStart?: string;
  25. planStartTo?: string;
  26. jobTypeName?: string;
  27. }
  28. export interface productProcessLineQtyRequest {
  29. productProcessLineId: number;
  30. outputFromProcessQty: number;
  31. outputFromProcessUom: string;
  32. defectQty: number;
  33. defectUom: string;
  34. scrapQty: number;
  35. scrapUom: string;
  36. }
  37. export interface SearchJoResultResponse {
  38. records: JobOrder[];
  39. total: number;
  40. }
  41. // DEPRECIATED
  42. export interface SearchJoResult {
  43. id: number;
  44. code: string;
  45. itemCode: string;
  46. name: string;
  47. reqQty: number;
  48. uom: string;
  49. status: JoStatus;
  50. }
  51. export interface UpdateJoRequest {
  52. id: number;
  53. status: string;
  54. }
  55. // For Jo Button Actions
  56. export interface CommonActionJoRequest {
  57. id: number;
  58. }
  59. export interface CommonActionJoResponse {
  60. id: number;
  61. entity: { status: JoStatus }
  62. }
  63. // For Jo Process
  64. export interface IsOperatorExistResponse<T> {
  65. id: number | null;
  66. name: string;
  67. code: string;
  68. type?: string;
  69. message: string | null;
  70. errorPosition: string | keyof T;
  71. entity: T;
  72. }
  73. export interface isCorrectMachineUsedResponse<T> {
  74. id: number | null;
  75. name: string;
  76. code: string;
  77. type?: string;
  78. message: string | null;
  79. errorPosition: string | keyof T;
  80. entity: T;
  81. }
  82. export interface JobOrderDetail {
  83. id: number;
  84. code: string;
  85. name: string;
  86. reqQty: number;
  87. uom: string;
  88. pickLines: any[];
  89. jobTypeName: string;
  90. status: string;
  91. }
  92. export interface UnassignedJobOrderPickOrder {
  93. pickOrderId: number;
  94. pickOrderCode: string;
  95. pickOrderConsoCode: string;
  96. pickOrderTargetDate: string;
  97. pickOrderStatus: string;
  98. jobOrderId: number;
  99. jobOrderCode: string;
  100. jobOrderName: string;
  101. reqQty: number;
  102. uom: string;
  103. planStart: string;
  104. planEnd: string;
  105. }
  106. export interface AssignJobOrderResponse {
  107. id: number | null;
  108. code: string | null;
  109. name: string | null;
  110. type: string | null;
  111. message: string | null;
  112. errorPosition: string | null;
  113. }
  114. export interface PrintPickRecordRequest{
  115. pickOrderId: number;
  116. printerId: number;
  117. printQty: number;
  118. }
  119. export interface PrintPickRecordResponse{
  120. success: boolean;
  121. message?: string
  122. }
  123. export interface PrintFGStockInLabelRequest {
  124. stockInLineId: number;
  125. printerId: number;
  126. printQty?: number;
  127. }
  128. export const printFGStockInLabel = cache(async(data: PrintFGStockInLabelRequest) => {
  129. const params = new URLSearchParams();
  130. if (data.stockInLineId) {
  131. params.append('stockInLineId', data.stockInLineId.toString());
  132. }
  133. params.append('printerId', data.printerId.toString());
  134. if (data.printQty !== undefined && data.printQty !== null) {
  135. params.append('printQty', data.printQty.toString());
  136. }
  137. return serverFetchWithNoContent(
  138. `${BASE_API_URL}/jo/print-FGStockInLabel?${params.toString()}`,
  139. {
  140. method: "GET",
  141. next: {
  142. tags: ["printFGStockInLabel"],
  143. },
  144. }
  145. );
  146. });
  147. export const recordSecondScanIssue = cache(async (
  148. pickOrderId: number,
  149. itemId: number,
  150. data: {
  151. qty: number; // verified qty (actual pick qty)
  152. missQty?: number; // 添加:miss qty
  153. badItemQty?: number; // 添加:bad item qty
  154. isMissing: boolean;
  155. isBad: boolean;
  156. reason: string;
  157. createdBy: number;
  158. type?: string; // type 也应该是可选的
  159. }
  160. ) => {
  161. return serverFetchJson<any>(
  162. `${BASE_API_URL}/jo/second-scan-issue/${pickOrderId}/${itemId}`,
  163. {
  164. method: "POST",
  165. headers: { "Content-Type": "application/json" },
  166. body: JSON.stringify(data),
  167. next: { tags: ["jo-second-scan"] },
  168. },
  169. );
  170. });
  171. export interface ProductProcessResponse {
  172. id: number;
  173. productProcessCode: string;
  174. status: string;
  175. startTime?: string;
  176. endTime?: string;
  177. date: string;
  178. bomId?: number;
  179. jobOrderId?: number;
  180. }
  181. export interface ProductProcessLineResponse {
  182. id: number,
  183. bomprocessId: number,
  184. operatorId: number,
  185. operatorName: string,
  186. equipmentId: number,
  187. handlerId: number,
  188. seqNo: number,
  189. name: string,
  190. description: string,
  191. equipment_name: string,
  192. equipmentDetailCode: string,
  193. status: string,
  194. byproductId: number,
  195. byproductName: string,
  196. byproductQty: number,
  197. byproductUom: string,
  198. scrapQty: number,
  199. defectQty: number,
  200. defectUom: string,
  201. outputFromProcessQty: number,
  202. outputFromProcessUom: string,
  203. durationInMinutes: number,
  204. prepTimeInMinutes: number,
  205. postProdTimeInMinutes: number,
  206. startTime: string,
  207. endTime: string,
  208. }
  209. export interface ProductProcessWithLinesResponse {
  210. id: number;
  211. productProcessCode: string;
  212. status: string;
  213. startTime?: string;
  214. endTime?: string;
  215. date: string;
  216. bomId?: number;
  217. jobOrderId?: number;
  218. jobOrderCode: string;
  219. jobOrderStatus: string;
  220. jobType: string;
  221. isDark: string;
  222. isDense: number;
  223. isFloat: string;
  224. timeSequence: number;
  225. complexity: number;
  226. scrapRate: number;
  227. allergicSubstance: string;
  228. itemId: number;
  229. itemCode: string;
  230. itemName: string;
  231. outputQty: number;
  232. outputQtyUom: string;
  233. productionPriority: number;
  234. jobOrderLines: JobOrderLineInfo[];
  235. productProcessLines: ProductProcessLineResponse[];
  236. }
  237. export interface UpdateProductProcessLineQtyRequest {
  238. productProcessLineId: number;
  239. outputFromProcessQty: number;
  240. outputFromProcessUom: string;
  241. byproductName: string;
  242. byproductQty: number;
  243. byproductUom: string;
  244. defectQty: number;
  245. defectUom: string;
  246. defect2Qty: number;
  247. defect2Uom: string;
  248. defect3Qty: number;
  249. defect3Uom: string;
  250. defectDescription: string;
  251. defectDescription2: string;
  252. defectDescription3: string;
  253. scrapQty: number;
  254. scrapUom: string;
  255. }
  256. export interface UpdateProductProcessLineQtyResponse {
  257. id: number;
  258. outputFromProcessQty: number;
  259. outputFromProcessUom: string;
  260. defectQty: number;
  261. defectUom: string;
  262. defect2Qty: number;
  263. defect2Uom: string;
  264. defect3Qty: number;
  265. defect3Uom: string;
  266. defectDescription: string;
  267. defectDescription2: string;
  268. defectDescription3: string;
  269. scrapQty: number;
  270. scrapUom: string;
  271. byproductName: string;
  272. byproductQty: number;
  273. byproductUom: string;
  274. }
  275. export interface AllProductProcessResponse {
  276. id: number;
  277. productProcessCode: string;
  278. status: string;
  279. startTime?: string;
  280. endTime?: string;
  281. date: string;
  282. bomId?: number;
  283. }
  284. export interface AllJoborderProductProcessInfoResponse {
  285. id: number;
  286. productProcessCode: string;
  287. status: string;
  288. startTime?: string;
  289. endTime?: string;
  290. date: string;
  291. matchStatus: string;
  292. bomId?: number;
  293. assignedTo: number;
  294. pickOrderId: number;
  295. itemName: string;
  296. requiredQty: number;
  297. jobOrderId: number;
  298. stockInLineId: number;
  299. jobOrderCode: string;
  300. productProcessLineCount: number;
  301. FinishedProductProcessLineCount: number;
  302. lines: ProductProcessInfoResponse[];
  303. }
  304. export interface ProductProcessInfoResponse {
  305. id: number;
  306. operatorId?: number;
  307. operatorName?: string;
  308. equipmentId?: number;
  309. equipmentName?: string;
  310. startTime?: string;
  311. endTime?: string;
  312. status: string;
  313. }
  314. export interface ProductProcessLineQrscanUpadteRequest {
  315. productProcessLineId: number;
  316. //operatorId?: number;
  317. //equipmentId?: number;
  318. equipmentTypeSubTypeEquipmentNo?: string;
  319. staffNo?: string;
  320. }
  321. export interface ProductProcessLineDetailResponse {
  322. id: number,
  323. productProcessId: number,
  324. bomProcessId: number,
  325. operatorId: number,
  326. equipmentType: string,
  327. operatorName: string,
  328. handlerId: number,
  329. seqNo: number,
  330. isDark: string,
  331. isDense: number,
  332. isFloat: string,
  333. outputQtyUom: string,
  334. outputQty: number,
  335. pickOrderId: number,
  336. jobOrderCode: string,
  337. jobOrderId: number,
  338. name: string,
  339. description: string,
  340. equipment: string,
  341. startTime: string,
  342. endTime: string,
  343. defectQty: number,
  344. defectUom: string,
  345. scrapQty: number,
  346. scrapUom: string,
  347. byproductId: number,
  348. byproductName: string,
  349. byproductQty: number,
  350. byproductUom: string | undefined,
  351. totalStockQty: number,
  352. insufficientStockQty: number,
  353. sufficientStockQty: number,
  354. productionPriority: number,
  355. productProcessLines: ProductProcessLineInfoResponse[],
  356. jobOrderLineInfo: JobOrderLineInfo[],
  357. }
  358. export interface JobOrderProcessLineDetailResponse {
  359. id: number;
  360. productProcessId: number;
  361. bomProcessId: number;
  362. operatorId: number;
  363. equipmentType: string | null;
  364. operatorName: string;
  365. handlerId: number;
  366. seqNo: number;
  367. durationInMinutes: number;
  368. name: string;
  369. description: string;
  370. equipmentId: number;
  371. startTime: string | number[]; // API 返回的是数组格式
  372. endTime: string | number[]; // API 返回的是数组格式
  373. status: string;
  374. outputFromProcessQty: number;
  375. outputFromProcessUom: string;
  376. defectQty: number;
  377. defectUom: string;
  378. defectDescription: string;
  379. defectQty2: number;
  380. defectUom2: string;
  381. defectDescription2: string;
  382. defectQty3: number;
  383. defectUom3: string;
  384. defectDescription3: string;
  385. scrapQty: number;
  386. scrapUom: string;
  387. byproductId: number;
  388. byproductName: string;
  389. byproductQty: number;
  390. byproductUom: string;
  391. productProcessIssueId: number;
  392. productProcessIssueStatus: string;
  393. }
  394. export interface JobOrderLineInfo {
  395. id: number,
  396. jobOrderId: number,
  397. jobOrderCode: string,
  398. itemId: number,
  399. itemCode: string,
  400. itemName: string,
  401. reqQty: number,
  402. stockQty: number,
  403. uom: string,
  404. shortUom: string,
  405. availableStatus: string,
  406. bomProcessId: number,
  407. bomProcessSeqNo: number,
  408. }
  409. export interface ProductProcessLineInfoResponse {
  410. id: number,
  411. bomprocessId: number,
  412. operatorId: number,
  413. operatorName: string,
  414. equipmentId: number,
  415. handlerId: number,
  416. seqNo: number,
  417. name: string,
  418. description: string,
  419. equipment_name: string,
  420. equipmentDetailCode: string,
  421. status: string,
  422. byproductId: number,
  423. byproductName: string,
  424. byproductQty: number,
  425. byproductUom: string,
  426. scrapQty: number,
  427. defectQty: number,
  428. defectUom: string,
  429. durationInMinutes: number,
  430. prepTimeInMinutes: number,
  431. postProdTimeInMinutes: number,
  432. outputFromProcessQty: number,
  433. outputFromProcessUom: string,
  434. startTime: string,
  435. endTime: string
  436. }
  437. export interface AllJoPickOrderResponse {
  438. id: number;
  439. pickOrderId: number | null;
  440. pickOrderCode: string | null;
  441. jobOrderId: number | null;
  442. jobOrderCode: string | null;
  443. jobOrderTypeId: number | null;
  444. jobOrderType: string | null;
  445. itemId: number;
  446. itemName: string;
  447. reqQty: number;
  448. uomId: number;
  449. uomName: string;
  450. jobOrderStatus: string;
  451. finishedPickOLineCount: number;
  452. }
  453. export interface UpdateJoPickOrderHandledByRequest {
  454. pickOrderId: number;
  455. itemId: number;
  456. userId: number;
  457. }
  458. export interface JobTypeResponse {
  459. id: number;
  460. name: string;
  461. }
  462. export interface SaveProductProcessIssueTimeRequest {
  463. productProcessLineId: number;
  464. reason: string;
  465. }
  466. export interface JobOrderLotsHierarchicalResponse {
  467. pickOrder: PickOrderInfoResponse;
  468. pickOrderLines: PickOrderLineWithLotsResponse[];
  469. }
  470. export interface PickOrderInfoResponse {
  471. id: number | null;
  472. code: string | null;
  473. consoCode: string | null;
  474. targetDate: string | null;
  475. type: string | null;
  476. status: string | null;
  477. assignTo: number | null;
  478. jobOrder: JobOrderBasicInfoResponse;
  479. }
  480. export interface JobOrderBasicInfoResponse {
  481. id: number;
  482. code: string;
  483. name: string;
  484. }
  485. export interface PickOrderLineWithLotsResponse {
  486. id: number;
  487. itemId: number | null;
  488. itemCode: string | null;
  489. itemName: string | null;
  490. requiredQty: number | null;
  491. uomCode: string | null;
  492. uomDesc: string | null;
  493. status: string | null;
  494. handler: string | null;
  495. lots: LotDetailResponse[];
  496. }
  497. export interface LotDetailResponse {
  498. lotId: number | null;
  499. lotNo: string | null;
  500. expiryDate: string | null;
  501. location: string | null;
  502. availableQty: number | null;
  503. requiredQty: number | null;
  504. actualPickQty: number | null;
  505. processingStatus: string | null;
  506. lotAvailability: string | null;
  507. pickOrderId: number | null;
  508. pickOrderCode: string | null;
  509. pickOrderConsoCode: string | null;
  510. pickOrderLineId: number | null;
  511. stockOutLineId: number | null;
  512. suggestedPickLotId: number | null;
  513. stockOutLineQty: number | null;
  514. stockOutLineStatus: string | null;
  515. routerIndex: number | null;
  516. routerArea: string | null;
  517. routerRoute: string | null;
  518. uomShortDesc: string | null;
  519. matchStatus?: string | null;
  520. matchBy?: number | null;
  521. matchQty?: number | null;
  522. }
  523. export const saveProductProcessIssueTime = cache(async (request: SaveProductProcessIssueTimeRequest) => {
  524. return serverFetchJson<any>(
  525. `${BASE_API_URL}/product-process/Demo/ProcessLine/issue`,
  526. {
  527. method: "POST",
  528. headers: { "Content-Type": "application/json" },
  529. body: JSON.stringify(request),
  530. }
  531. );
  532. });
  533. export const saveProductProcessResumeTime = cache(async (productProcessIssueId: number) => {
  534. return serverFetchJson<any>(
  535. `${BASE_API_URL}/product-process/Demo/ProcessLine/resume/${productProcessIssueId}`,
  536. {
  537. method: "POST",
  538. }
  539. );
  540. });
  541. export const deleteJobOrder=cache(async (jobOrderId: number) => {
  542. return serverFetchJson<any>(
  543. `${BASE_API_URL}/jo/demo/deleteJobOrder/${jobOrderId}`,
  544. {
  545. method: "POST",
  546. }
  547. );
  548. });
  549. export const fetchAllJobTypes = cache(async () => {
  550. return serverFetchJson<JobTypeResponse[]>(
  551. `${BASE_API_URL}/jo/jobTypes`,
  552. {
  553. method: "GET",
  554. }
  555. );
  556. });
  557. export const updateJoPickOrderHandledBy = cache(async (request: UpdateJoPickOrderHandledByRequest) => {
  558. return serverFetchJson<any>(
  559. `${BASE_API_URL}/jo/update-jo-pick-order-handled-by`,
  560. {
  561. method: "POST",
  562. body: JSON.stringify(request),
  563. headers: { "Content-Type": "application/json" },
  564. },
  565. );
  566. });
  567. export const fetchJobOrderLotsHierarchicalByPickOrderId = cache(async (pickOrderId: number) => {
  568. return serverFetchJson<JobOrderLotsHierarchicalResponse>(
  569. `${BASE_API_URL}/jo/all-lots-hierarchical-by-pick-order/${pickOrderId}`,
  570. {
  571. method: "GET",
  572. next: { tags: ["jo-hierarchical"] },
  573. },
  574. );
  575. });
  576. export const fetchAllJoPickOrders = cache(async () => {
  577. return serverFetchJson<AllJoPickOrderResponse[]>(
  578. `${BASE_API_URL}/jo/AllJoPickOrder`,
  579. {
  580. method: "GET",
  581. }
  582. );
  583. });
  584. export const fetchProductProcessLineDetail = cache(async (lineId: number) => {
  585. return serverFetchJson<JobOrderProcessLineDetailResponse>(
  586. `${BASE_API_URL}/product-process/Demo/ProcessLine/detail/${lineId}`,
  587. {
  588. method: "GET",
  589. }
  590. );
  591. });
  592. export const updateProductProcessLineQty = cache(async (request: UpdateProductProcessLineQtyRequest) => {
  593. return serverFetchJson<UpdateProductProcessLineQtyResponse>(
  594. `${BASE_API_URL}/product-process/Demo/ProcessLine/update/qty/${request.productProcessLineId}`,
  595. {
  596. method: "POST",
  597. headers: { "Content-Type": "application/json" },
  598. body: JSON.stringify(request),
  599. }
  600. );
  601. });
  602. export const updateProductProcessLineQrscan = cache(async (request: ProductProcessLineQrscanUpadteRequest) => {
  603. const requestBody: any = {
  604. productProcessLineId: request.productProcessLineId,
  605. //operatorId: request.operatorId,
  606. //equipmentId: request.equipmentId,
  607. equipmentTypeSubTypeEquipmentNo: request.equipmentTypeSubTypeEquipmentNo,
  608. staffNo: request.staffNo,
  609. };
  610. if (request.equipmentTypeSubTypeEquipmentNo !== undefined) {
  611. requestBody["EquipmentType-SubType-EquipmentNo"] = request.equipmentTypeSubTypeEquipmentNo;
  612. }
  613. return serverFetchJson<any>(
  614. `${BASE_API_URL}/product-process/Demo/update`,
  615. {
  616. method: "POST",
  617. headers: { "Content-Type": "application/json" },
  618. body: JSON.stringify(requestBody),
  619. }
  620. );
  621. });
  622. export const fetchAllJoborderProductProcessInfo = cache(async () => {
  623. return serverFetchJson<AllJoborderProductProcessInfoResponse[]>(
  624. `${BASE_API_URL}/product-process/Demo/Process/all`,
  625. {
  626. method: "GET",
  627. next: { tags: ["productProcess"] },
  628. }
  629. );
  630. });
  631. /*
  632. export const updateProductProcessLineQty = async (request: UpdateProductProcessLineQtyRequest) => {
  633. return serverFetchJson<UpdateProductProcessLineQtyResponse>(
  634. `${BASE_API_URL}/product-process/lines/${request.productProcessLineId}/update/qty`,
  635. {
  636. method: "POST",
  637. headers: { "Content-Type": "application/json" },
  638. body: JSON.stringify(request),
  639. }
  640. );
  641. };
  642. */
  643. export const startProductProcessLine = async (lineId: number) => {
  644. return serverFetchJson<any>(
  645. `${BASE_API_URL}/product-process/Demo/ProcessLine/start/${lineId}`,
  646. {
  647. method: "POST",
  648. headers: { "Content-Type": "application/json" },
  649. }
  650. );
  651. };
  652. export const completeProductProcessLine = async (lineId: number) => {
  653. return serverFetchJson<any>(
  654. `${BASE_API_URL}/product-process/Demo/ProcessLine/complete/${lineId}`,
  655. {
  656. method: "POST",
  657. headers: { "Content-Type": "application/json" },
  658. }
  659. );
  660. };
  661. // 查询所有 production processes
  662. export const fetchProductProcesses = cache(async () => {
  663. return serverFetchJson<{ content: ProductProcessResponse[] }>(
  664. `${BASE_API_URL}/product-process`,
  665. {
  666. method: "GET",
  667. next: { tags: ["productProcess"] },
  668. }
  669. );
  670. });
  671. // 根据 ID 查询
  672. export const fetchProductProcessById = cache(async (id: number) => {
  673. return serverFetchJson<ProductProcessResponse>(
  674. `${BASE_API_URL}/product-process/${id}`,
  675. {
  676. method: "GET",
  677. next: { tags: ["productProcess"] },
  678. }
  679. );
  680. });
  681. export const updateProductProcessPriority = cache(async (productProcessId: number, productionPriority: number) => {
  682. return serverFetchJson<any>(
  683. `${BASE_API_URL}/product-process/Demo/Process/update/priority/${productProcessId}/${productionPriority}`,
  684. {
  685. method: "POST",
  686. }
  687. );
  688. });
  689. // 根据 Job Order ID 查询
  690. export const fetchProductProcessesByJobOrderId = cache(async (jobOrderId: number) => {
  691. return serverFetchJson<ProductProcessWithLinesResponse[]>(
  692. `${BASE_API_URL}/product-process/demo/joid/${jobOrderId}`,
  693. {
  694. method: "GET",
  695. next: { tags: ["productProcess"] },
  696. }
  697. );
  698. });
  699. // 获取 process 的所有 lines
  700. export const fetchProductProcessLines = cache(async (processId: number) => {
  701. return serverFetchJson<ProductProcessLineResponse[]>(
  702. `${BASE_API_URL}/product-process/${processId}/lines`,
  703. {
  704. method: "GET",
  705. next: { tags: ["productProcessLines"] },
  706. }
  707. );
  708. });
  709. // 创建 production process
  710. export const createProductProcess = async (data: {
  711. bomId: number;
  712. jobOrderId?: number;
  713. date?: string;
  714. }) => {
  715. return serverFetchJson<{ id: number; productProcessCode: string; linesCreated: number }>(
  716. `${BASE_API_URL}/product-process`,
  717. {
  718. method: "POST",
  719. headers: { "Content-Type": "application/json" },
  720. body: JSON.stringify(data),
  721. }
  722. );
  723. };
  724. // 更新 line 产出数据
  725. export const updateLineOutput = async (lineId: number, data: {
  726. outputQty?: number;
  727. outputUom?: string;
  728. defectQty?: number;
  729. defectUom?: string;
  730. scrapQty?: number;
  731. scrapUom?: string;
  732. byproductName?: string;
  733. byproductQty?: number;
  734. byproductUom?: string;
  735. }) => {
  736. return serverFetchJson<ProductProcessLineResponse>(
  737. `${BASE_API_URL}/product-process/lines/${lineId}/output`,
  738. {
  739. method: "PUT",
  740. headers: { "Content-Type": "application/json" },
  741. body: JSON.stringify(data),
  742. }
  743. );
  744. };
  745. export const updateSecondQrScanStatus = cache(async (pickOrderId: number, itemId: number, userId: number, qty: number) => {
  746. return serverFetchJson<any>(
  747. `${BASE_API_URL}/jo/update-match-status`,
  748. {
  749. method: "POST",
  750. body: JSON.stringify({
  751. pickOrderId,
  752. itemId,
  753. userId,
  754. qty
  755. }),
  756. headers: {
  757. 'Content-Type': 'application/json',
  758. },
  759. next: { tags: ["update-match-status"] },
  760. },
  761. );
  762. });
  763. export const submitSecondScanQuantity = cache(async (
  764. pickOrderId: number,
  765. itemId: number,
  766. data: { qty: number; isMissing?: boolean; isBad?: boolean; reason?: string }
  767. ) => {
  768. return serverFetchJson<any>(
  769. `${BASE_API_URL}/jo/second-scan-submit/${pickOrderId}/${itemId}`,
  770. {
  771. method: "POST",
  772. headers: { "Content-Type": "application/json" },
  773. body: JSON.stringify(data),
  774. next: { tags: ["jo-second-scan"] },
  775. },
  776. );
  777. });
  778. // 获取未分配的 Job Order pick orders
  779. export const fetchUnassignedJobOrderPickOrders = cache(async () => {
  780. return serverFetchJson<UnassignedJobOrderPickOrder[]>(
  781. `${BASE_API_URL}/jo/unassigned-job-order-pick-orders`,
  782. {
  783. method: "GET",
  784. next: { tags: ["jo-unassigned"] },
  785. },
  786. );
  787. });
  788. // 分配 Job Order pick order 给用户
  789. export const assignJobOrderPickOrder = async (pickOrderId: number, userId: number) => {
  790. return serverFetchJson<AssignJobOrderResponse>(
  791. `${BASE_API_URL}/jo/assign-job-order-pick-order/${pickOrderId}/${userId}`,
  792. {
  793. method: "POST",
  794. headers: { "Content-Type": "application/json" },
  795. }
  796. );
  797. };
  798. export const unAssignJobOrderPickOrder = async (pickOrderId: number) => {
  799. return serverFetchJson<AssignJobOrderResponse>(
  800. `${BASE_API_URL}/jo/unassign-job-order-pick-order/${pickOrderId}`,
  801. {
  802. method: "POST",
  803. headers: { "Content-Type": "application/json" },
  804. }
  805. );
  806. };
  807. // 获取 Job Order 分层数据
  808. export const fetchJobOrderLotsHierarchical = cache(async (userId: number) => {
  809. return serverFetchJson<JobOrderLotsHierarchicalResponse>(
  810. `${BASE_API_URL}/jo/all-lots-hierarchical/${userId}`,
  811. {
  812. method: "GET",
  813. next: { tags: ["jo-hierarchical"] },
  814. },
  815. );
  816. });
  817. export const fetchCompletedJobOrderPickOrders = cache(async (userId: number) => {
  818. return serverFetchJson<any>(
  819. `${BASE_API_URL}/jo/completed-job-order-pick-orders/${userId}`,
  820. {
  821. method: "GET",
  822. next: { tags: ["jo-completed"] },
  823. },
  824. );
  825. });
  826. // 获取已完成的 Job Order pick orders
  827. export const fetchCompletedJobOrderPickOrdersrecords = cache(async () => {
  828. return serverFetchJson<any>(
  829. `${BASE_API_URL}/jo/completed-job-order-pick-orders-only`,
  830. {
  831. method: "GET",
  832. next: { tags: ["jo-completed"] },
  833. },
  834. );
  835. });
  836. // 获取已完成的 Job Order pick order records
  837. export const fetchCompletedJobOrderPickOrderRecords = cache(async (userId: number) => {
  838. return serverFetchJson<any[]>(
  839. `${BASE_API_URL}/jo/completed-job-order-pick-order-records/${userId}`,
  840. {
  841. method: "GET",
  842. next: { tags: ["jo-records"] },
  843. },
  844. );
  845. });
  846. export const fetchJobOrderDetailByCode = cache(async (code: string) => {
  847. return serverFetchJson<JobOrderDetail>(
  848. `${BASE_API_URL}/jo/detailByCode/${code}`,
  849. {
  850. method: "GET",
  851. next: { tags: ["jo"] },
  852. },
  853. );
  854. });
  855. export const isOperatorExist = async (username: string) => {
  856. const isExist = await serverFetchJson<IsOperatorExistResponse<Operator>>(
  857. `${BASE_API_URL}/jop/isOperatorExist`,
  858. {
  859. method: "POST",
  860. body: JSON.stringify({ username }),
  861. headers: { "Content-Type": "application/json" },
  862. },
  863. );
  864. revalidateTag("po");
  865. return isExist;
  866. };
  867. export const isCorrectMachineUsed = async (machineCode: string) => {
  868. const isExist = await serverFetchJson<isCorrectMachineUsedResponse<Machine>>(
  869. `${BASE_API_URL}/jop/isCorrectMachineUsed`,
  870. {
  871. method: "POST",
  872. body: JSON.stringify({ machineCode }),
  873. headers: { "Content-Type": "application/json" },
  874. },
  875. );
  876. revalidateTag("po");
  877. return isExist;
  878. };
  879. export const fetchJos = cache(async (data?: SearchJoResultRequest) => {
  880. const queryStr = convertObjToURLSearchParams(data)
  881. console.log("queryStr", queryStr)
  882. const fullUrl = `${BASE_API_URL}/jo/getRecordByPage?${queryStr}`;
  883. console.log("fetchJos full URL:", fullUrl);
  884. console.log("fetchJos BASE_API_URL:", BASE_API_URL);
  885. const response = await serverFetchJson<SearchJoResultResponse>(
  886. `${BASE_API_URL}/jo/getRecordByPage?${queryStr}`,
  887. {
  888. method: "GET",
  889. headers: { "Content-Type": "application/json" },
  890. next: {
  891. tags: ["jos"]
  892. }
  893. }
  894. )
  895. console.log("fetchJos response:", response)
  896. return response
  897. })
  898. export const updateJo = cache(async (data: UpdateJoRequest) => {
  899. return serverFetchJson<SaveJoResponse>(`${BASE_API_URL}/jo/update`,
  900. {
  901. method: "POST",
  902. body: JSON.stringify(data),
  903. headers: { "Content-Type": "application/json" },
  904. })
  905. })
  906. export const releaseJo = cache(async (data: CommonActionJoRequest) => {
  907. const response = serverFetchJson<CommonActionJoResponse>(`${BASE_API_URL}/jo/release`,
  908. {
  909. method: "POST",
  910. body: JSON.stringify(data),
  911. headers: { "Content-Type": "application/json" },
  912. })
  913. // Invalidate the cache after releasing
  914. revalidateTag("jo");
  915. return response;
  916. })
  917. export const startJo = cache(async (data: CommonActionJoRequest) => {
  918. const response = serverFetchJson<CommonActionJoResponse>(`${BASE_API_URL}/jo/start`,
  919. {
  920. method: "POST",
  921. body: JSON.stringify(data),
  922. headers: { "Content-Type": "application/json" },
  923. })
  924. // Invalidate the cache after starting
  925. revalidateTag("jo");
  926. return response;
  927. })
  928. export const manualCreateJo = cache(async (data: SaveJo) => {
  929. return serverFetchJson<SaveJoResponse>(`${BASE_API_URL}/jo/manualCreate`, {
  930. method: "POST",
  931. body: JSON.stringify(data),
  932. headers: { "Content-Type": "application/json" }
  933. })
  934. })
  935. export const fetchCompletedJobOrderPickOrdersWithCompletedSecondScan = cache(async (userId: number) => {
  936. return serverFetchJson<any[]>(`${BASE_API_URL}/jo/completed-job-order-pick-orders-with-completed-second-scan/${userId}`, {
  937. method: "GET",
  938. headers: { "Content-Type": "application/json" }
  939. })
  940. })
  941. export const fetchCompletedJobOrderPickOrderLotDetails = cache(async (pickOrderId: number) => {
  942. return serverFetchJson<any[]>(`${BASE_API_URL}/jo/completed-job-order-pick-order-lot-details/${pickOrderId}`, {
  943. method: "GET",
  944. headers: { "Content-Type": "application/json" }
  945. })
  946. })
  947. export const fetchCompletedJobOrderPickOrderLotDetailsForCompletedPick = cache(async (pickOrderId: number) => {
  948. return serverFetchJson<any[]>(`${BASE_API_URL}/jo/completed-job-order-pick-order-lot-details-completed-pick/${pickOrderId}`, {
  949. method: "GET",
  950. headers: { "Content-Type": "application/json" }
  951. })
  952. })
  953. export async function PrintPickRecord(request: PrintPickRecordRequest){
  954. const params = new URLSearchParams();
  955. params.append('pickOrderId', request.pickOrderId.toString())
  956. params.append('printerId', request.printerId.toString())
  957. if (request.printQty !== null && request.printQty !== undefined) {
  958. params.append('printQty', request.printQty.toString());
  959. }
  960. //const response = await serverFetchWithNoContent(`${BASE_API_URL}/jo/print-PickRecord?${params.toString()}`,{
  961. const response = await serverFetchWithNoContent(`${BASE_API_URL}/jo/print-PickRecord?${params.toString()}`,{
  962. method: "GET"
  963. });
  964. return { success: true, message: "Print job sent successfully (Pick Record)" } as PrintPickRecordResponse;
  965. }
  966. export interface ExportFGStockInLabelRequest {
  967. stockInLineId: number;
  968. }
  969. export const fetchFGStockInLabel = async (data: ExportFGStockInLabelRequest): Promise<FileResponse> => {
  970. const reportBlob = await serverFetchBlob<FileResponse>(
  971. `${BASE_API_URL}/jo/FGStockInLabel`,
  972. {
  973. method: "POST",
  974. body: JSON.stringify(data),
  975. headers: { "Content-Type": "application/json" },
  976. },
  977. );
  978. return reportBlob;
  979. };