FPSMS-frontend
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 

1286 satır
34 KiB

  1. "use server";
  2. import { BASE_API_URL } from "@/config/api";
  3. // import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
  4. import { revalidateTag } from "next/cache";
  5. import { cache } from "react";
  6. import { serverFetchJson } from "@/app/utils/fetchUtil";
  7. import { QcItemResult } from "../settings/qcItem";
  8. import { RecordsRes } from "../utils";
  9. import {
  10. ConsoPickOrderResult,
  11. PickOrderLineWithSuggestedLot,
  12. PickOrderResult,
  13. PreReleasePickOrderSummary,
  14. StockOutLine,
  15. } from ".";
  16. import { PurchaseQcResult } from "../po/actions";
  17. import { StringNullableChain } from "lodash";
  18. // import { BASE_API_URL } from "@/config/api";
  19. import dayjs from "dayjs";
  20. export interface SavePickOrderLineRequest {
  21. itemId: number
  22. qty: number
  23. uomId: number
  24. }
  25. export interface SavePickOrderRequest {
  26. type: string
  27. targetDate: string
  28. pickOrderLine: SavePickOrderLineRequest[]
  29. }
  30. export interface PostPickOrderResponse<T = null> {
  31. id: number | null;
  32. name: string;
  33. code: string;
  34. type?: string;
  35. message: string | null;
  36. errorPosition: string
  37. entity?: T | T[];
  38. consoCode?: string;
  39. }
  40. export interface PostStockOutLiineResponse<T> {
  41. id: number | null;
  42. name: string;
  43. code: string;
  44. type?: string;
  45. message: string | null;
  46. errorPosition: string | keyof T;
  47. entity: T | T[] | null;
  48. }
  49. export interface ReleasePickOrderInputs {
  50. consoCode: string;
  51. assignTo: number;
  52. }
  53. export interface CreateStockOutLine {
  54. consoCode: string;
  55. pickOrderLineId: number;
  56. inventoryLotLineId: number;
  57. qty: number;
  58. }
  59. export interface UpdateStockOutLine {
  60. id: number;
  61. // consoCode: String,
  62. itemId: number;
  63. qty: number;
  64. pickOrderLineId: number;
  65. inventoryLotLineId?: number;
  66. status: string;
  67. pickTime?: string;
  68. // pickerId: number?
  69. }
  70. export interface PickOrderQcInput {
  71. qty: number;
  72. status: string;
  73. qcResult: PurchaseQcResult[];
  74. }
  75. export interface PickOrderApprovalInput {
  76. allowQty: number;
  77. rejectQty: number;
  78. status: string;
  79. }
  80. export interface GetPickOrderInfoResponse {
  81. consoCode: string | null;
  82. pickOrders: GetPickOrderInfo[];
  83. items: CurrentInventoryItemInfo[];
  84. }
  85. export interface GetPickOrderInfo {
  86. id: number;
  87. code: string;
  88. consoCode: string | null; // 添加 consoCode 属性
  89. targetDate: string | number[]; // Support both formats
  90. type: string;
  91. status: string;
  92. assignTo: number;
  93. groupName: string; // Add this field
  94. pickOrderLines: GetPickOrderLineInfo[];
  95. }
  96. export interface GetPickOrderLineInfo {
  97. id: number;
  98. itemId: number;
  99. itemCode: string;
  100. itemName: string;
  101. availableQty: number| null;
  102. requiredQty: number;
  103. uomShortDesc: string;
  104. uomDesc: string;
  105. suggestedList: any[];
  106. pickedQty: number;
  107. noLotLines: NoLotLineDto[];
  108. }
  109. export interface NoLotLineDto {
  110. stockOutLineId: number;
  111. status: string;
  112. qty: number;
  113. created: string;
  114. modified: string;
  115. }
  116. export interface CurrentInventoryItemInfo {
  117. id: number;
  118. code: string;
  119. name: string;
  120. uomDesc: string;
  121. availableQty: number;
  122. requiredQty: number;
  123. }
  124. export interface SavePickOrderGroupRequest {
  125. groupIds?: number[];
  126. names?: string[];
  127. targetDate?: string;
  128. pickOrderId?: number | null;
  129. }
  130. export interface PickOrderGroupInfo {
  131. id: number;
  132. name: string;
  133. targetDate: string | null;
  134. pickOrderId: number | null;
  135. }
  136. export interface AssignPickOrderInputs {
  137. pickOrderIds: number[];
  138. assignTo: number;
  139. }
  140. export interface LotDetailWithStockOutLine {
  141. lotId: number;
  142. lotNo: string;
  143. expiryDate: string;
  144. location: string;
  145. stockUnit: string;
  146. availableQty: number;
  147. requiredQty: number;
  148. actualPickQty: number;
  149. suggestedPickLotId: number;
  150. lotStatus: string;
  151. lotAvailability: string;
  152. stockOutLineId?: number;
  153. stockOutLineStatus?: string;
  154. stockOutLineQty?: number;
  155. }
  156. export interface PickAnotherLotFormData {
  157. pickOrderLineId: number;
  158. lotId: number;
  159. qty: number;
  160. type: string;
  161. handlerId?: number;
  162. category?: string;
  163. releasedBy?: number;
  164. recordDate?: string;
  165. }
  166. export const recordFailLot = async (data: PickAnotherLotFormData) => {
  167. const result = await serverFetchJson<PostPickOrderResponse>(
  168. `${BASE_API_URL}/suggestedPickLot/recordFailLot`,
  169. {
  170. method: "POST",
  171. body: JSON.stringify(data),
  172. headers: { "Content-Type": "application/json" },
  173. },
  174. );
  175. revalidateTag("pickorder");
  176. return result;
  177. };
  178. export interface PickExecutionIssueData {
  179. type: string;
  180. pickOrderId: number;
  181. pickOrderCode: string;
  182. pickOrderCreateDate: string;
  183. pickExecutionDate: string;
  184. pickOrderLineId: number;
  185. itemId: number;
  186. itemCode: string;
  187. itemDescription: string;
  188. lotId: number|null;
  189. lotNo: string|null;
  190. storeLocation: string;
  191. requiredQty: number;
  192. actualPickQty: number;
  193. missQty: number;
  194. badItemQty: number;
  195. issueRemark: string;
  196. pickerName: string;
  197. handledBy?: number;
  198. }
  199. export type AutoAssignReleaseResponse = {
  200. id: number | null;
  201. name?: string | null;
  202. code?: string | null;
  203. type?: string | null;
  204. message?: string | null;
  205. errorPosition?: string | null;
  206. entity?: any;
  207. };
  208. export interface PickOrderCompletionResponse {
  209. id: number | null;
  210. name: string;
  211. code: string;
  212. type?: string;
  213. message: string | null;
  214. errorPosition: string;
  215. entity?: {
  216. hasCompletedOrders: boolean;
  217. completedOrders: Array<{
  218. pickOrderId: number;
  219. pickOrderCode: string;
  220. consoCode: string;
  221. isCompleted: boolean;
  222. stockOutStatus: string;
  223. totalLines: number;
  224. unfinishedLines: number;
  225. }>;
  226. allOrders: Array<{
  227. pickOrderId: number;
  228. pickOrderCode: string;
  229. consoCode: string;
  230. isCompleted: boolean;
  231. stockOutStatus: string;
  232. totalLines: number;
  233. unfinishedLines: number;
  234. }>;
  235. };
  236. }
  237. export interface UpdateSuggestedLotLineIdRequest {
  238. newLotLineId: number;
  239. }
  240. export interface stockReponse{
  241. id: number;
  242. status: string;
  243. qty: number;
  244. lotId: number;
  245. lotNo: string;
  246. location: string;
  247. availableQty: number;
  248. noLot: boolean;
  249. }
  250. export interface FGPickOrderResponse {
  251. // 新增:支持多个 pick orders
  252. doPickOrderId: number;
  253. pickOrderIds?: number[];
  254. pickOrderCodes?: string[]; // 改为数组
  255. deliveryOrderIds?: number[];
  256. deliveryNos?: string[]; // 改为数组
  257. numberOfPickOrders?: number;
  258. lineCountsPerPickOrder?: number[];// 新增:pick order 数量
  259. // 保留原有字段用于向后兼容(显示第一个 pick order)
  260. pickOrderId: number;
  261. pickOrderCode: string;
  262. pickOrderConsoCode: string;
  263. pickOrderTargetDate: string;
  264. pickOrderStatus: string;
  265. deliveryOrderId: number;
  266. deliveryNo: string;
  267. deliveryDate: string;
  268. shopId: number;
  269. shopCode: string;
  270. shopName: string;
  271. shopAddress: string;
  272. ticketNo: string;
  273. shopPoNo: string;
  274. numberOfCartons: number;
  275. DepartureTime: string;
  276. truckLanceCode: string;
  277. storeId: string;
  278. qrCodeData: number;
  279. }
  280. export interface DoPickOrderDetail {
  281. doPickOrder: {
  282. id: number;
  283. store_id: string;
  284. ticket_no: string;
  285. ticket_status: string;
  286. truck_id: number;
  287. truck_departure_time: string;
  288. shop_id: number;
  289. handled_by: number | null;
  290. loading_sequence: number;
  291. ticket_release_time: string | null;
  292. TruckLanceCode: string;
  293. ShopCode: string;
  294. ShopName: string;
  295. RequiredDeliveryDate: string;
  296. };
  297. pickOrders: Array<{
  298. pick_order_id: number;
  299. pick_order_code: string;
  300. do_order_id: number;
  301. delivery_order_code: string;
  302. consoCode: string;
  303. status: string;
  304. targetDate: string;
  305. }>;
  306. selectedPickOrderId: number;
  307. lotDetails: any[]; // 使用现有的 lot detail 结构
  308. pickOrderCodes?: string;
  309. deliveryNos?: string;
  310. }
  311. export interface AutoAssignReleaseByStoreRequest {
  312. userId: number;
  313. storeId: string; // "2/F" | "4/F"
  314. }
  315. export interface UpdateDoPickOrderHideStatusRequest {
  316. id: number;
  317. name: string;
  318. code: string;
  319. type: string;
  320. message: string;
  321. errorPosition: string;
  322. }
  323. export interface CompletedDoPickOrderResponse {
  324. id: number;
  325. doPickOrderRecordId: number; // ✅ 新增
  326. recordId: number | null;
  327. pickOrderId: number;
  328. pickOrderIds: number[]; // 新增:所有 pick order IDs
  329. pickOrderCode: string;
  330. pickOrderCodes: string; // 新增:所有 pick order codes (逗号分隔)
  331. pickOrderConsoCode: string;
  332. pickOrderStatus: string;
  333. deliveryOrderId: number;
  334. deliveryOrderIds: number[]; // 新增:所有 delivery order IDs
  335. deliveryNo: string;
  336. deliveryNos: string; // 新增:所有 delivery order codes (逗号分隔)
  337. deliveryDate: string;
  338. shopId: number;
  339. shopCode: string;
  340. shopName: string;
  341. shopAddress: string;
  342. ticketNo: string;
  343. shopPoNo: string;
  344. numberOfCartons: number;
  345. truckLanceCode: string;
  346. DepartureTime: string; // 新增
  347. storeId: string;
  348. completedDate: string;
  349. fgPickOrders: FGPickOrderResponse[];
  350. deliveryNoteCode: number;
  351. }
  352. // 新增:搜索参数接口
  353. export interface CompletedDoPickOrderSearchParams {
  354. targetDate?: string;
  355. shopName?: string;
  356. deliveryNoteCode?: string;
  357. }
  358. export interface PickExecutionIssue {
  359. id: number;
  360. pickOrderId: number;
  361. pickOrderCode: string;
  362. pickOrderCreateDate: string;
  363. pickExecutionDate: string;
  364. pickOrderLineId: number;
  365. issueNo: string;
  366. joPickOrderId?: number;
  367. doPickOrderId?: number;
  368. issueCategory: string;
  369. itemId: number;
  370. itemCode: string;
  371. itemDescription: string;
  372. lotId?: number;
  373. lotNo?: string;
  374. storeLocation?: string;
  375. requiredQty: number;
  376. actualPickQty?: number;
  377. missQty?: number;
  378. badItemQty?: number;
  379. issueRemark?: string;
  380. pickerName?: string;
  381. handleStatus: string;
  382. handleDate?: string;
  383. handledBy?: string;
  384. created: string;
  385. createdBy: string;
  386. modified: string;
  387. modifiedBy: string;
  388. }
  389. export interface FetchPickExecutionIssuesParams {
  390. type?: "jo" | "do" | "material";
  391. }
  392. export const fetchAllPickExecutionIssues = cache(
  393. async (params?: FetchPickExecutionIssuesParams): Promise<PickExecutionIssue[]> => {
  394. const queryParams = new URLSearchParams();
  395. if (params?.type) {
  396. queryParams.append("type", params.type);
  397. }
  398. const url = `${BASE_API_URL}/pickExecution/issues/all${
  399. queryParams.toString() ? `?${queryParams.toString()}` : ""
  400. }`;
  401. const result = await serverFetchJson<PickExecutionIssue[]>(url, {
  402. method: "GET",
  403. headers: { "Content-Type": "application/json" },
  404. });
  405. return result ?? [];
  406. }
  407. );
  408. export interface UpdatePickExecutionIssueRequest {
  409. issueId: number;
  410. handleStatus: string;
  411. handleDate?: string;
  412. handledBy?: string;
  413. handleRemark?: string;
  414. }
  415. export interface StoreLaneSummary {
  416. storeId: string;
  417. rows: LaneRow[];
  418. }
  419. export interface LaneRow {
  420. truckDepartureTime: string;
  421. lanes: LaneBtn[];
  422. }
  423. export interface LaneBtn {
  424. truckLanceCode: string;
  425. unassigned: number;
  426. total: number;
  427. }
  428. export const fetchDoPickOrderDetail = async (
  429. doPickOrderId: number,
  430. selectedPickOrderId?: number
  431. ): Promise<DoPickOrderDetail> => {
  432. const url = selectedPickOrderId
  433. ? `${BASE_API_URL}/pickOrder/do-pick-order-detail/${doPickOrderId}?selectedPickOrderId=${selectedPickOrderId}`
  434. : `${BASE_API_URL}/pickOrder/do-pick-order-detail/${doPickOrderId}`;
  435. const response = await serverFetchJson<DoPickOrderDetail>(url, {
  436. method: "GET",
  437. });
  438. return response;
  439. };
  440. export const updatePickExecutionIssueStatus = async (
  441. data: UpdatePickExecutionIssueRequest
  442. ): Promise<PostPickOrderResponse> => {
  443. const result = await serverFetchJson<PostPickOrderResponse>(
  444. `${BASE_API_URL}/pickExecution/updateIssueStatus`,
  445. {
  446. method: "POST",
  447. body: JSON.stringify(data),
  448. headers: { "Content-Type": "application/json" },
  449. }
  450. );
  451. revalidateTag("pickExecutionIssues");
  452. return result;
  453. };
  454. export async function fetchStoreLaneSummary(storeId: string, requiredDate?: string): Promise<StoreLaneSummary> {
  455. const dateToUse = requiredDate || dayjs().format('YYYY-MM-DD');
  456. const url = `${BASE_API_URL}/doPickOrder/summary-by-store?storeId=${encodeURIComponent(storeId)}&requiredDate=${encodeURIComponent(dateToUse)}`;
  457. const response = await serverFetchJson<StoreLaneSummary>(
  458. url,
  459. {
  460. method: "GET",
  461. cache: "no-store",
  462. next: { revalidate: 0 }
  463. }
  464. );
  465. return response;
  466. }
  467. // 按车道分配订单
  468. export async function assignByLane(
  469. userId: number,
  470. storeId: string,
  471. truckLanceCode: string,
  472. truckDepartureTime?: string,
  473. requiredDate?: string
  474. ): Promise<any> {
  475. const response = await serverFetchJson(
  476. `${BASE_API_URL}/doPickOrder/assign-by-lane`,
  477. {
  478. method: "POST",
  479. headers: {
  480. "Content-Type": "application/json",
  481. },
  482. body: JSON.stringify({
  483. userId,
  484. storeId,
  485. truckLanceCode,
  486. truckDepartureTime,
  487. requiredDate,
  488. }),
  489. }
  490. );
  491. return response;
  492. }
  493. // 新增:获取已完成的 DO Pick Orders API
  494. export const fetchCompletedDoPickOrders = async (
  495. userId: number,
  496. searchParams?: CompletedDoPickOrderSearchParams
  497. ): Promise<CompletedDoPickOrderResponse[]> => {
  498. const params = new URLSearchParams();
  499. if (searchParams?.deliveryNoteCode) {
  500. params.append('deliveryNoteCode', searchParams.deliveryNoteCode);
  501. }
  502. if (searchParams?.shopName) {
  503. params.append('shopName', searchParams.shopName);
  504. }
  505. if (searchParams?.targetDate) {
  506. params.append('targetDate', searchParams.targetDate);
  507. }
  508. const queryString = params.toString();
  509. const url = `${BASE_API_URL}/pickOrder/completed-do-pick-orders/${userId}${queryString ? `?${queryString}` : ''}`;
  510. const response = await serverFetchJson<CompletedDoPickOrderResponse[]>(url, {
  511. method: "GET",
  512. });
  513. return response;
  514. };
  515. export const updatePickOrderHideStatus = async (pickOrderId: number, hide: boolean) => {
  516. const response = await serverFetchJson<UpdateDoPickOrderHideStatusRequest>(
  517. `${BASE_API_URL}/pickOrder/update-hide-status/${pickOrderId}?hide=${hide}`,
  518. {
  519. method: "POST",
  520. headers: { "Content-Type": "application/json" },
  521. },
  522. );
  523. revalidateTag("pickorder");
  524. return response;
  525. };
  526. export const fetchFGPickOrders = async (pickOrderId: number) => {
  527. const response = await serverFetchJson<FGPickOrderResponse>(
  528. `${BASE_API_URL}/pickOrder/fg-pick-orders/${pickOrderId}`,
  529. {
  530. method: "GET",
  531. },
  532. );
  533. return response;
  534. };
  535. export const fetchFGPickOrdersByUserId = async (userId: number) => {
  536. const response = await serverFetchJson<FGPickOrderResponse[]>(
  537. `${BASE_API_URL}/pickOrder/fg-pick-orders/${userId}`,
  538. {
  539. method: "GET",
  540. },
  541. );
  542. return response;
  543. };
  544. export const updateSuggestedLotLineId = async (suggestedPickLotId: number, newLotLineId: number) => {
  545. const response = await serverFetchJson<PostPickOrderResponse<UpdateSuggestedLotLineIdRequest>>(
  546. `${BASE_API_URL}/suggestedPickLot/update-suggested-lot/${suggestedPickLotId}`,
  547. {
  548. method: "POST",
  549. body: JSON.stringify({ newLotLineId }),
  550. headers: { "Content-Type": "application/json" },
  551. },
  552. );
  553. revalidateTag("pickorder");
  554. return response;
  555. };
  556. export const autoAssignAndReleasePickOrder = async (userId: number): Promise<AutoAssignReleaseResponse> => {
  557. const response = await serverFetchJson<AutoAssignReleaseResponse>(
  558. `${BASE_API_URL}/pickOrder/auto-assign-release/${userId}`,
  559. {
  560. method: "POST",
  561. headers: { "Content-Type": "application/json" },
  562. },
  563. );
  564. revalidateTag("pickorder");
  565. return response;
  566. };
  567. export const autoAssignAndReleasePickOrderByStore = async (
  568. userId: number,
  569. storeId: string
  570. ): Promise<AutoAssignReleaseResponse> => {
  571. const url = `${BASE_API_URL}/pickOrder/auto-assign-release-by-store?userId=${userId}&storeId=${encodeURIComponent(storeId)}`;
  572. const response = await serverFetchJson<AutoAssignReleaseResponse>(url, {
  573. method: "POST",
  574. headers: { "Content-Type": "application/json" },
  575. // no body
  576. next: { tags: ["pickorder"] },
  577. });
  578. revalidateTag("pickorder");
  579. return response;
  580. };
  581. export const checkPickOrderCompletion = async (userId: number): Promise<PickOrderCompletionResponse> => {
  582. const response = await serverFetchJson<PickOrderCompletionResponse>(
  583. `${BASE_API_URL}/pickOrder/check-pick-completion/${userId}`,
  584. {
  585. method: "GET",
  586. headers: { "Content-Type": "application/json" },
  587. },
  588. );
  589. return response;
  590. };
  591. export const recordPickExecutionIssue = async (data: PickExecutionIssueData) => {
  592. const result = await serverFetchJson<PostPickOrderResponse>(
  593. `${BASE_API_URL}/pickExecution/recordIssue`,
  594. {
  595. method: "POST",
  596. body: JSON.stringify(data),
  597. headers: { "Content-Type": "application/json" },
  598. },
  599. );
  600. revalidateTag("pickorder");
  601. return result;
  602. };
  603. export const resuggestPickOrder = async (pickOrderId: number) => {
  604. console.log("Resuggesting pick order:", pickOrderId);
  605. const result = await serverFetchJson<PostPickOrderResponse>(
  606. `${BASE_API_URL}/suggestedPickLot/resuggest/${pickOrderId}`,
  607. {
  608. method: "POST",
  609. headers: { "Content-Type": "application/json" },
  610. },
  611. );
  612. revalidateTag("pickorder");
  613. return result;
  614. };
  615. export const updateStockOutLineStatus = async (data: {
  616. id: number;
  617. status: string;
  618. qty?: number;
  619. remarks?: string;
  620. }) => {
  621. console.log("Updating stock out line status:", data);
  622. const result = await serverFetchJson<PostStockOutLiineResponse<StockOutLine>>(
  623. `${BASE_API_URL}/stockOutLine/updateStatus`,
  624. {
  625. method: "POST",
  626. body: JSON.stringify(data),
  627. headers: { "Content-Type": "application/json" },
  628. },
  629. );
  630. revalidateTag("pickorder");
  631. return result;
  632. };
  633. // Missing function 1: newassignPickOrder
  634. export const newassignPickOrder = async (data: AssignPickOrderInputs) => {
  635. const response = await serverFetchJson<PostPickOrderResponse>(
  636. `${BASE_API_URL}/pickOrder/assign`,
  637. {
  638. method: "POST",
  639. body: JSON.stringify(data),
  640. headers: { "Content-Type": "application/json" },
  641. },
  642. );
  643. revalidateTag("pickorder");
  644. return response;
  645. };
  646. // Missing function 2: releaseAssignedPickOrders
  647. export const releaseAssignedPickOrders = async (data: AssignPickOrderInputs) => {
  648. const response = await serverFetchJson<PostPickOrderResponse>(
  649. `${BASE_API_URL}/pickOrder/release-assigned`,
  650. {
  651. method: "POST",
  652. body: JSON.stringify(data),
  653. headers: { "Content-Type": "application/json" },
  654. },
  655. );
  656. revalidateTag("pickorder");
  657. return response;
  658. };
  659. // Get latest group name and create it automatically
  660. export const getLatestGroupNameAndCreate = async () => {
  661. return serverFetchJson<PostPickOrderResponse>(
  662. `${BASE_API_URL}/pickOrder/groups/latest`,
  663. {
  664. method: "GET",
  665. next: { tags: ["pickorder"] },
  666. },
  667. );
  668. };
  669. // Get all groups
  670. export const fetchAllGroups = cache(async () => {
  671. return serverFetchJson<PickOrderGroupInfo[]>(
  672. `${BASE_API_URL}/pickOrder/groups/list`,
  673. {
  674. method: "GET",
  675. next: { tags: ["pickorder"] },
  676. },
  677. );
  678. });
  679. // Create or update groups (flexible - can handle both cases)
  680. export const createOrUpdateGroups = async (data: SavePickOrderGroupRequest) => {
  681. const response = await serverFetchJson<PostPickOrderResponse>(
  682. `${BASE_API_URL}/pickOrder/groups/create`,
  683. {
  684. method: "POST",
  685. body: JSON.stringify(data),
  686. headers: { "Content-Type": "application/json" },
  687. },
  688. );
  689. revalidateTag("pickorder");
  690. return response;
  691. };
  692. // Get groups by pick order ID
  693. export const fetchGroupsByPickOrderId = cache(async (pickOrderId: number) => {
  694. return serverFetchJson<PickOrderGroupInfo[]>(
  695. `${BASE_API_URL}/pickOrder/groups/${pickOrderId}`,
  696. {
  697. method: "GET",
  698. next: { tags: ["pickorder"] },
  699. },
  700. );
  701. });
  702. export const fetchPickOrderDetails = cache(async (ids: string) => {
  703. return serverFetchJson<GetPickOrderInfoResponse>(
  704. `${BASE_API_URL}/pickOrder/detail/${ids}`,
  705. {
  706. method: "GET",
  707. next: { tags: ["pickorder"] },
  708. },
  709. );
  710. });
  711. export interface PickOrderLotDetailResponse {
  712. lotId: number | null; // ✅ 改为可空
  713. lotNo: string | null; // ✅ 改为可空
  714. expiryDate: string | null; // ✅ 改为可空
  715. location: string | null; // ✅ 改为可空
  716. stockUnit: string | null;
  717. inQty: number | null;
  718. availableQty: number | null; // ✅ 改为可空
  719. requiredQty: number;
  720. actualPickQty: number;
  721. suggestedPickLotId: number | null;
  722. lotStatus: string | null;
  723. lotAvailability: 'available' | 'insufficient_stock' | 'expired' | 'status_unavailable' | 'rejected';
  724. stockOutLineId: number | null; // ✅ 添加
  725. stockOutLineStatus: string | null; // ✅ 添加
  726. stockOutLineQty: number | null; // ✅ 添加
  727. totalPickedByAllPickOrders: number | null; // ✅ 添加
  728. remainingAfterAllPickOrders: number | null; // ✅ 添加
  729. noLot: boolean; // ✅ 关键:添加 noLot 字段
  730. outQty?: number; // ✅ 添加
  731. holdQty?: number; // ✅ 添加
  732. }
  733. interface ALLPickOrderLotDetailResponse {
  734. // Pick Order Information
  735. pickOrderId: number;
  736. pickOrderCode: string;
  737. pickOrderTargetDate: string;
  738. pickOrderType: string;
  739. pickOrderStatus: string;
  740. pickOrderAssignTo: number;
  741. groupName: string;
  742. // Pick Order Line Information
  743. pickOrderLineId: number;
  744. pickOrderLineRequiredQty: number;
  745. pickOrderLineStatus: string;
  746. // Item Information
  747. itemId: number;
  748. itemCode: string;
  749. itemName: string;
  750. uomCode: string;
  751. uomDesc: string;
  752. // Lot Information
  753. lotId: number;
  754. lotNo: string;
  755. expiryDate: string;
  756. location: string;
  757. outQty: number;
  758. holdQty: number;
  759. stockUnit: string;
  760. availableQty: number;
  761. requiredQty: number;
  762. actualPickQty: number;
  763. totalPickedByAllPickOrders: number;
  764. suggestedPickLotId: number;
  765. lotStatus: string;
  766. stockOutLineId?: number;
  767. stockOutLineStatus?: string;
  768. stockOutLineQty?: number;
  769. lotAvailability: 'available' | 'insufficient_stock' | 'expired' | 'status_unavailable'|'rejected';
  770. processingStatus: string;
  771. }
  772. interface SuggestionWithStatus {
  773. suggestionId: number;
  774. suggestionQty: number;
  775. suggestionCreated: string;
  776. lotLineId: number;
  777. lotNo: string;
  778. expiryDate: string;
  779. location: string;
  780. stockOutLineId?: number;
  781. stockOutLineStatus?: string;
  782. stockOutLineQty?: number;
  783. suggestionStatus: 'active' | 'completed' | 'rejected' | 'in_progress' | 'unknown';
  784. }
  785. // 在 actions.ts 中修改接口定义
  786. export interface FGPickOrderHierarchicalResponse {
  787. fgInfo: {
  788. doPickOrderId: number;
  789. ticketNo: string;
  790. storeId: string;
  791. shopCode: string;
  792. shopName: string;
  793. truckLanceCode: string;
  794. departureTime: string;
  795. };
  796. pickOrders: Array<{
  797. pickOrderId: number;
  798. pickOrderCode: string;
  799. doOrderId: number;
  800. deliveryOrderCode: string;
  801. consoCode: string;
  802. status: string;
  803. targetDate: string;
  804. pickOrderLines: Array<{
  805. id: number;
  806. requiredQty: number;
  807. status: string;
  808. item: {
  809. id: number;
  810. code: string;
  811. name: string;
  812. uomCode: string;
  813. uomDesc: string;
  814. };
  815. lots: Array<any>; // 可以是空数组
  816. }>;
  817. }>;
  818. }
  819. export interface CheckCompleteResponse {
  820. id: number | null;
  821. name: string;
  822. code: string;
  823. type?: string;
  824. message: string | null;
  825. errorPosition: string;
  826. }
  827. export interface LotSubstitutionConfirmRequest {
  828. pickOrderLineId: number;
  829. stockOutLineId: number;
  830. originalSuggestedPickLotId: number;
  831. newInventoryLotLineId: number;
  832. }
  833. export const confirmLotSubstitution = async (data: LotSubstitutionConfirmRequest) => {
  834. const response = await serverFetchJson<PostPickOrderResponse>(
  835. `${BASE_API_URL}/pickOrder/lot-substitution/confirm`,
  836. {
  837. method: "POST",
  838. body: JSON.stringify(data),
  839. headers: { "Content-Type": "application/json" },
  840. },
  841. );
  842. revalidateTag("pickorder");
  843. return response;
  844. };
  845. export const checkAndCompletePickOrderByConsoCode = async (consoCode: string): Promise<CheckCompleteResponse> => {
  846. const response = await serverFetchJson<CheckCompleteResponse>(
  847. `${BASE_API_URL}/pickOrder/check-complete/${consoCode}`,
  848. {
  849. method: "POST",
  850. headers: {
  851. "Content-Type": "application/json",
  852. },
  853. },
  854. );
  855. revalidateTag("pickorder");
  856. return response;
  857. };
  858. export const fetchPickOrderDetailsOptimized = cache(async (userId?: number) => {
  859. const url = userId
  860. ? `${BASE_API_URL}/pickOrder/detail-optimized?userId=${userId}`
  861. : `${BASE_API_URL}/pickOrder/detail-optimized`;
  862. return serverFetchJson<any[]>(
  863. url,
  864. {
  865. method: "GET",
  866. next: { tags: ["pickorder"] },
  867. },
  868. );
  869. });
  870. const fetchSuggestionsWithStatus = async (pickOrderLineId: number) => {
  871. try {
  872. const response = await fetch(`/api/suggestedPickLot/suggestions-with-status/${pickOrderLineId}`);
  873. const suggestions: SuggestionWithStatus[] = await response.json();
  874. return suggestions;
  875. } catch (error) {
  876. console.error('Error fetching suggestions with status:', error);
  877. return [];
  878. }
  879. };
  880. export const fetchAllPickOrderLotsHierarchical = cache(async (userId: number): Promise<any> => {
  881. try {
  882. console.log("🔍 Fetching hierarchical pick order lots for userId:", userId);
  883. const data = await serverFetchJson<any>(
  884. `${BASE_API_URL}/pickOrder/all-lots-hierarchical/${userId}`,
  885. {
  886. method: 'GET',
  887. next: { tags: ["pickorder"] },
  888. }
  889. );
  890. console.log(" Fetched hierarchical lot details:", data);
  891. return data;
  892. } catch (error) {
  893. console.error("❌ Error fetching hierarchical lot details:", error);
  894. return {
  895. pickOrder: null,
  896. pickOrderLines: []
  897. };
  898. }
  899. });
  900. export const fetchLotDetailsByDoPickOrderRecordId = async (doPickOrderRecordId: number): Promise<{
  901. fgInfo: any;
  902. pickOrders: any[];
  903. }> => {
  904. try {
  905. console.log("🔍 Fetching lot details for doPickOrderRecordId:", doPickOrderRecordId);
  906. const data = await serverFetchJson<{
  907. fgInfo: any;
  908. pickOrders: any[];
  909. }>(
  910. `${BASE_API_URL}/pickOrder/lot-details-by-do-pick-order-record/${doPickOrderRecordId}`,
  911. {
  912. method: 'GET',
  913. next: { tags: ["pickorder"] },
  914. }
  915. );
  916. console.log(" Fetched hierarchical lot details:", data);
  917. return data;
  918. } catch (error) {
  919. console.error("❌ Error fetching lot details:", error);
  920. return {
  921. fgInfo: null,
  922. pickOrders: []
  923. };
  924. }
  925. };
  926. // Update the existing function to use the non-auto-assign endpoint
  927. export const fetchALLPickOrderLineLotDetails = cache(async (userId: number): Promise<any[]> => {
  928. try {
  929. console.log("🔍 Fetching all pick order line lot details for userId:", userId);
  930. // Use the non-auto-assign endpoint
  931. const data = await serverFetchJson<any[]>(
  932. `${BASE_API_URL}/pickOrder/all-lots-with-details-no-auto-assign/${userId}`,
  933. {
  934. method: 'GET',
  935. next: { tags: ["pickorder"] },
  936. }
  937. );
  938. console.log(" Fetched lot details:", data);
  939. return data;
  940. } catch (error) {
  941. console.error("❌ Error fetching lot details:", error);
  942. return [];
  943. }
  944. });
  945. export const fetchAllPickOrderDetails = cache(async (userId?: number) => {
  946. if (!userId) {
  947. return {
  948. consoCode: null,
  949. pickOrders: [],
  950. items: []
  951. };
  952. }
  953. // Use the correct endpoint with userId in the path
  954. const url = `${BASE_API_URL}/pickOrder/detail-optimized/${userId}`;
  955. return serverFetchJson<GetPickOrderInfoResponse>(
  956. url,
  957. {
  958. method: "GET",
  959. next: { tags: ["pickorder"] },
  960. },
  961. );
  962. });
  963. export const fetchPickOrderLineLotDetails = cache(async (pickOrderLineId: number) => {
  964. return serverFetchJson<PickOrderLotDetailResponse[]>(
  965. `${BASE_API_URL}/pickOrder/lot-details/${pickOrderLineId}`,
  966. {
  967. method: "GET",
  968. next: { tags: ["pickorder"] },
  969. },
  970. );
  971. });
  972. export const createPickOrder = async (data: SavePickOrderRequest) => {
  973. console.log(data);
  974. const po = await serverFetchJson<PostPickOrderResponse>(
  975. `${BASE_API_URL}/pickOrder/create`,
  976. {
  977. method: "POST",
  978. body: JSON.stringify(data),
  979. headers: { "Content-Type": "application/json" },
  980. },
  981. );
  982. revalidateTag("pickorder");
  983. return po;
  984. }
  985. export const assignPickOrder = async (ids: number[]) => {
  986. const pickOrder = await serverFetchJson<any>(
  987. `${BASE_API_URL}/pickOrder/conso`,
  988. {
  989. method: "POST",
  990. body: JSON.stringify({ ids: ids }),
  991. headers: { "Content-Type": "application/json" },
  992. },
  993. );
  994. // revalidateTag("po");
  995. return pickOrder;
  996. };
  997. export const consolidatePickOrder = async (ids: number[]) => {
  998. const pickOrder = await serverFetchJson<any>(
  999. `${BASE_API_URL}/pickOrder/conso`,
  1000. {
  1001. method: "POST",
  1002. body: JSON.stringify({ ids: ids }),
  1003. headers: { "Content-Type": "application/json" },
  1004. },
  1005. );
  1006. return pickOrder;
  1007. };
  1008. export const consolidatePickOrder_revert = async (ids: number[]) => {
  1009. const pickOrder = await serverFetchJson<any>(
  1010. `${BASE_API_URL}/pickOrder/deconso`,
  1011. {
  1012. method: "POST",
  1013. body: JSON.stringify({ ids: ids }),
  1014. headers: { "Content-Type": "application/json" },
  1015. },
  1016. );
  1017. // revalidateTag("po");
  1018. return pickOrder;
  1019. };
  1020. export const fetchPickOrderClient = cache(
  1021. async (queryParams?: Record<string, any>) => {
  1022. if (queryParams) {
  1023. const queryString = new URLSearchParams(queryParams).toString();
  1024. return serverFetchJson<RecordsRes<PickOrderResult[]>>(
  1025. `${BASE_API_URL}/pickOrder/getRecordByPage?${queryString}`,
  1026. {
  1027. method: "GET",
  1028. next: { tags: ["pickorder"] },
  1029. },
  1030. );
  1031. } else {
  1032. return serverFetchJson<RecordsRes<PickOrderResult[]>>(
  1033. `${BASE_API_URL}/pickOrder/getRecordByPage`,
  1034. {
  1035. method: "GET",
  1036. next: { tags: ["pickorder"] },
  1037. },
  1038. );
  1039. }
  1040. },
  1041. );
  1042. export const fetchPickOrderWithStockClient = cache(
  1043. async (queryParams?: Record<string, any>) => {
  1044. if (queryParams) {
  1045. const queryString = new URLSearchParams(queryParams).toString();
  1046. return serverFetchJson<RecordsRes<GetPickOrderInfo[]>>(
  1047. `${BASE_API_URL}/pickOrder/getRecordByPageWithStock?${queryString}`,
  1048. {
  1049. method: "GET",
  1050. next: { tags: ["pickorder"] },
  1051. },
  1052. );
  1053. } else {
  1054. return serverFetchJson<RecordsRes<GetPickOrderInfo[]>>(
  1055. `${BASE_API_URL}/pickOrder/getRecordByPageWithStock`,
  1056. {
  1057. method: "GET",
  1058. next: { tags: ["pickorder"] },
  1059. },
  1060. );
  1061. }
  1062. },
  1063. );
  1064. export const fetchConsoPickOrderClient = cache(
  1065. async (queryParams?: Record<string, any>) => {
  1066. if (queryParams) {
  1067. const queryString = new URLSearchParams(queryParams).toString();
  1068. return serverFetchJson<RecordsRes<ConsoPickOrderResult[]>>(
  1069. `${BASE_API_URL}/pickOrder/getRecordByPage-conso?${queryString}`,
  1070. {
  1071. method: "GET",
  1072. next: { tags: ["pickorder"] },
  1073. },
  1074. );
  1075. } else {
  1076. return serverFetchJson<RecordsRes<ConsoPickOrderResult[]>>(
  1077. `${BASE_API_URL}/pickOrder/getRecordByPage-conso`,
  1078. {
  1079. method: "GET",
  1080. next: { tags: ["pickorder"] },
  1081. },
  1082. );
  1083. }
  1084. },
  1085. );
  1086. export const fetchPickOrderLineClient = cache(
  1087. async (queryParams?: Record<string, any>) => {
  1088. if (queryParams) {
  1089. const queryString = new URLSearchParams(queryParams).toString();
  1090. return serverFetchJson<RecordsRes<PickOrderLineWithSuggestedLot[]>>(
  1091. `${BASE_API_URL}/pickOrder/get-pickorder-line-byPage?${queryString}`,
  1092. {
  1093. method: "GET",
  1094. next: { tags: ["pickorder"] },
  1095. },
  1096. );
  1097. } else {
  1098. return serverFetchJson<RecordsRes<PickOrderLineWithSuggestedLot[]>>(
  1099. `${BASE_API_URL}/pickOrder/get-pickorder-line-byPage`,
  1100. {
  1101. method: "GET",
  1102. next: { tags: ["pickorder"] },
  1103. },
  1104. );
  1105. }
  1106. },
  1107. );
  1108. export const fetchStockOutLineClient = cache(
  1109. async (pickOrderLineId: number) => {
  1110. return serverFetchJson<StockOutLine[]>(
  1111. `${BASE_API_URL}/stockOutLine/getByPickOrderLineId/${pickOrderLineId}`,
  1112. {
  1113. method: "GET",
  1114. next: { tags: ["pickorder"] },
  1115. },
  1116. );
  1117. },
  1118. );
  1119. export const fetchConsoDetail = cache(async (consoCode: string) => {
  1120. return serverFetchJson<PreReleasePickOrderSummary>(
  1121. `${BASE_API_URL}/pickOrder/pre-release-info/${consoCode}`,
  1122. {
  1123. method: "GET",
  1124. next: { tags: ["pickorder"] },
  1125. },
  1126. );
  1127. });
  1128. export const releasePickOrder = async (data: ReleasePickOrderInputs) => {
  1129. console.log(data);
  1130. console.log(JSON.stringify(data));
  1131. const po = await serverFetchJson<{ consoCode: string }>(
  1132. `${BASE_API_URL}/pickOrder/releaseConso`,
  1133. {
  1134. method: "POST",
  1135. body: JSON.stringify(data),
  1136. headers: { "Content-Type": "application/json" },
  1137. },
  1138. );
  1139. revalidateTag("pickorder");
  1140. return po;
  1141. };
  1142. export const createStockOutLine = async (data: CreateStockOutLine) => {
  1143. console.log("triggering");
  1144. const po = await serverFetchJson<PostStockOutLiineResponse<StockOutLine>>(
  1145. `${BASE_API_URL}/stockOutLine/create`,
  1146. {
  1147. method: "POST",
  1148. body: JSON.stringify(data),
  1149. headers: { "Content-Type": "application/json" },
  1150. },
  1151. );
  1152. revalidateTag("pickorder");
  1153. return po;
  1154. };
  1155. export const updateStockOutLine = async (data: UpdateStockOutLine) => {
  1156. console.log(data);
  1157. const po = await serverFetchJson<PostStockOutLiineResponse<StockOutLine>>(
  1158. `${BASE_API_URL}/stockOutLine/update`,
  1159. {
  1160. method: "POST",
  1161. body: JSON.stringify(data),
  1162. headers: { "Content-Type": "application/json" },
  1163. },
  1164. );
  1165. revalidateTag("pickorder");
  1166. return po;
  1167. };
  1168. export const completeConsoPickOrder = async (consoCode: string) => {
  1169. const po = await serverFetchJson<PostStockOutLiineResponse<StockOutLine>>(
  1170. `${BASE_API_URL}/pickOrder/consoPickOrder/complete/${consoCode}`,
  1171. {
  1172. method: "POST",
  1173. headers: { "Content-Type": "application/json" },
  1174. },
  1175. );
  1176. revalidateTag("pickorder");
  1177. return po;
  1178. };
  1179. export const fetchConsoStatus = cache(async (consoCode: string) => {
  1180. return serverFetchJson<{ status: string }>(
  1181. `${BASE_API_URL}/stockOut/get-status/${consoCode}`,
  1182. {
  1183. method: "GET",
  1184. next: { tags: ["pickorder"] },
  1185. },
  1186. );
  1187. });
  1188. export interface ReleasedDoPickOrderResponse {
  1189. id: number;
  1190. storeId: string;
  1191. ticketNo: string;
  1192. pickOrderId: number;
  1193. ticketStatus: string;
  1194. doOrderId: number;
  1195. shopId: number;
  1196. handledBy: number;
  1197. ticketReleaseTime: string;
  1198. }
  1199. export const fetchReleasedDoPickOrders = async (): Promise<ReleasedDoPickOrderResponse[]> => {
  1200. const response = await serverFetchJson<ReleasedDoPickOrderResponse[]>(
  1201. `${BASE_API_URL}/doPickOrder/released`,
  1202. {
  1203. method: "GET",
  1204. },
  1205. );
  1206. return response;
  1207. };