FPSMS-frontend
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 

674 Zeilen
20 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 { serverFetch, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
  7. import { QcItemResult } from "../settings/qcItem";
  8. import { RecordsRes } from "../utils";
  9. import { DoResult } from ".";
  10. import { GridRowId, GridRowSelectionModel } from "@mui/x-data-grid";
  11. import { GET } from "../auth/[...nextauth]/route";
  12. import { stringify } from "querystring";
  13. import { convertObjToURLSearchParams } from "@/app/utils/commonUtil";
  14. export interface CreateConsoDoInput {
  15. ids: GridRowSelectionModel;
  16. }
  17. export interface DoDetail {
  18. id: number;
  19. code: string;
  20. supplierCode: string;
  21. shopCode: string;
  22. shopName: string;
  23. currencyCode: string;
  24. orderDate: string;
  25. estimatedArrivalDate: string;
  26. completeDate: string;
  27. status: string;
  28. /** 加單 DO */
  29. isExtra?: boolean;
  30. /** 揀貨員名稱(delivery_order_pick_order.handlerName) */
  31. handlerName?: string | null;
  32. deliveryOrderLines: DoDetailLine[];
  33. }
  34. export interface DoDetailLine {
  35. id: number;
  36. itemNo: string;
  37. qty: number;
  38. price: number;
  39. status: string;
  40. itemName?: string;
  41. uomCode?: string;
  42. uom?: string;
  43. shortUom?: string;
  44. /** AVAILABLE lot lines: sum(in - out - hold), same unit as DO line qty. */
  45. stockQty?: number;
  46. /** `available` | `insufficient` */
  47. availableStatus?: string;
  48. }
  49. export interface DoSearchAll {
  50. id: number;
  51. code: string;
  52. status: string;
  53. estimatedArrivalDate: number[];
  54. orderDate: number[];
  55. supplierName: string;
  56. shopName: string;
  57. shopAddress?: string;
  58. isExtra?: boolean;
  59. truckLanceCode?: string | null;
  60. }
  61. export interface DoSearchLiteResponse {
  62. records: DoSearchAll[];
  63. total: number;
  64. }
  65. export interface ReleaseDoRequest {
  66. id: number;
  67. }
  68. export interface ReleaseDoResponse {
  69. id: number;
  70. entity: { status: string }
  71. }
  72. export interface AssignByStoreRequest {
  73. storeId: string; // "2/F" or "4/F"
  74. assignTo: number;
  75. }
  76. export interface AssignByStoreResponse {
  77. id: number;
  78. code: string;
  79. name: string;
  80. type: string;
  81. message: string;
  82. errorPosition: string;
  83. entity: any;
  84. }
  85. export interface PrintDeliveryNoteRequest{
  86. doPickOrderId: number;
  87. printerId: number;
  88. printQty: number;
  89. numOfCarton: number;
  90. isDraft: boolean;
  91. }
  92. export interface PrintDeliveryNoteResponse{
  93. success: boolean;
  94. message?: string
  95. }
  96. export interface PrintDNLabelsRequest{
  97. doPickOrderId: number;
  98. printerId: number;
  99. printQty: number;
  100. numOfCarton: number;
  101. }
  102. export interface PrintDNLabelsReprintRequest{
  103. doPickOrderId: number;
  104. printerId: number;
  105. printQty: number;
  106. fromCarton: number;
  107. toCarton: number;
  108. totalCartonsOnShipment: number;
  109. }
  110. export interface PrintDNLabelsRespone{
  111. success: boolean;
  112. message?: string
  113. }
  114. export interface BatchReleaseRequest {
  115. ids: number[];
  116. }
  117. export interface BatchReleaseResponse {
  118. success: boolean;
  119. message?: string
  120. }
  121. export interface getTicketReleaseTable {
  122. id: number;
  123. storeId: string | null;
  124. ticketNo: string | null;
  125. pickOrderId: number | null;
  126. doOrderId: number | null;
  127. pickOrderCode: string | null;
  128. deliveryOrderCode: string | null;
  129. loadingSequence: number | null;
  130. ticketStatus: string | null;
  131. truckId: number | null;
  132. truckDepartureTime: string | null;
  133. shopId: number | null;
  134. handledBy: number | null;
  135. ticketReleaseTime: string | null;
  136. ticketCompleteDateTime: string | null;
  137. truckLanceCode: string | null;
  138. shopCode: string | null;
  139. shopName: string | null;
  140. requiredDeliveryDate: string | null;
  141. handlerName: string | null;
  142. numberOfFGItems: number;
  143. /** 進行中 do_pick_order 為 true,才可呼叫 force-complete / revert-assignment(id 為 do_pick_order 主鍵) */
  144. isActiveDoPickOrder?: boolean;
  145. }
  146. export interface WorkbenchTicketReleaseTable {
  147. deliveryOrderPickOrderId: number;
  148. storeId: string | null;
  149. ticketNo: string | null;
  150. loadingSequence: number | null;
  151. ticketStatus: string | null;
  152. truckDepartureTime: string | null;
  153. handledBy: number | null;
  154. ticketReleaseTime: string | null;
  155. ticketCompleteDateTime: string | null;
  156. truckLanceCode: string | null;
  157. shopCode: string | null;
  158. shopName: string | null;
  159. requiredDeliveryDate: string | null;
  160. handlerName: string | null;
  161. numberOfFGItems: number;
  162. isActiveWorkbenchTicket?: boolean;
  163. }
  164. export interface WorkbenchTicketOpResponse {
  165. id: number | null;
  166. name: string | null;
  167. code: string;
  168. type: string | null;
  169. message: string | null;
  170. errorPosition: string | null;
  171. entity?: any;
  172. }
  173. export interface TruckScheduleDashboardItem {
  174. storeId: string | null;
  175. truckId: number | null;
  176. truckLanceCode: string | null;
  177. truckDepartureTime: string | number[] | null;
  178. numberOfShopsToServe: number;
  179. numberOfPickTickets: number;
  180. totalItemsToPick: number;
  181. numberOfTicketsReleased: number;
  182. firstTicketStartTime: string | number[] | null;
  183. numberOfTicketsCompleted: number;
  184. lastTicketEndTime: string | number[] | null;
  185. pickTimeTakenMinutes: number | null;
  186. }
  187. export interface SearchDeliveryOrderInfoRequest {
  188. code: string;
  189. shopName: string;
  190. status: string;
  191. orderStartDate: string;
  192. orderEndDate: string;
  193. estArrStartDate: string;
  194. estArrEndDate: string;
  195. pageSize: number;
  196. pageNum: number;
  197. }
  198. export interface SearchDeliveryOrderInfoResponse {
  199. records: DeliveryOrderInfo[];
  200. total: number;
  201. }
  202. export interface DeliveryOrderInfo {
  203. id: number;
  204. code: string;
  205. shopName: string;
  206. supplierName: string; // 改为必需字段
  207. status: string;
  208. orderDate: string;
  209. estimatedArrivalDate: string;
  210. deliveryOrderLines: DoDetailLine[];
  211. }
  212. export const fetchDoRecordByPage = cache(async (data?: SearchDeliveryOrderInfoRequest) => {
  213. const queryStr = convertObjToURLSearchParams(data)
  214. console.log("queryStr", queryStr)
  215. const response = serverFetchJson<SearchDeliveryOrderInfoResponse>(
  216. `${BASE_API_URL}/jo/getRecordByPage?${queryStr}`,
  217. {
  218. method: "GET",
  219. headers: { "Content-Type": "application/json" },
  220. next: {
  221. tags: ["jos"]
  222. }
  223. }
  224. )
  225. return response
  226. })
  227. export const fetchTicketReleaseTable = cache(async (startDate: string, endDate: string)=> {
  228. return await serverFetchJson<getTicketReleaseTable[]>(
  229. `${BASE_API_URL}/doPickOrder/ticket-release-table/${startDate}&${endDate}`,
  230. {
  231. method: "GET",
  232. }
  233. );
  234. });
  235. export const fetchWorkbenchTicketReleaseTable = cache(async (startDate: string, endDate: string)=> {
  236. return await serverFetchJson<WorkbenchTicketReleaseTable[]>(
  237. `${BASE_API_URL}/doPickOrder/workbench/ticket-release-table/${startDate}&${endDate}`,
  238. {
  239. method: "GET",
  240. }
  241. );
  242. });
  243. export async function forceCompleteWorkbenchTicket(
  244. deliveryOrderPickOrderId: number,
  245. ): Promise<WorkbenchTicketOpResponse> {
  246. return await serverFetchJson<WorkbenchTicketOpResponse>(
  247. `${BASE_API_URL}/doPickOrder/workbench/force-complete/${deliveryOrderPickOrderId}`,
  248. {
  249. method: "POST",
  250. headers: { "Content-Type": "application/json" },
  251. },
  252. );
  253. }
  254. export async function revertWorkbenchTicketAssignment(
  255. deliveryOrderPickOrderId: number,
  256. ): Promise<WorkbenchTicketOpResponse> {
  257. return await serverFetchJson<WorkbenchTicketOpResponse>(
  258. `${BASE_API_URL}/doPickOrder/workbench/revert-assignment/${deliveryOrderPickOrderId}`,
  259. {
  260. method: "POST",
  261. headers: { "Content-Type": "application/json" },
  262. },
  263. );
  264. }
  265. export const fetchTruckScheduleDashboard = cache(async (date?: string) => {
  266. const url = date
  267. ? `${BASE_API_URL}/doPickOrder/truck-schedule-dashboard?date=${date}`
  268. : `${BASE_API_URL}/doPickOrder/truck-schedule-dashboard`;
  269. return await serverFetchJson<TruckScheduleDashboardItem[]>(
  270. url,
  271. {
  272. method: "GET",
  273. }
  274. );
  275. });
  276. export const startBatchReleaseAsyncSingle = cache(async (data: { doId: number; userId: number }) => {
  277. const { doId, userId } = data;
  278. return await serverFetchJson<{ id: number|null; code: string; entity?: any }>(
  279. `${BASE_API_URL}/doPickOrder/batch-release/async-single?userId=${userId}`,
  280. {
  281. method: "POST",
  282. body: JSON.stringify(doId),
  283. headers: { "Content-Type": "application/json" },
  284. }
  285. );
  286. });
  287. export const startBatchReleaseAsync = cache(async (data: { ids: number[]; userId: number }) => {
  288. const { ids, userId } = data;
  289. return await serverFetchJson<{ id: number|null; code: string; entity?: any }>(
  290. `${BASE_API_URL}/doPickOrder/batch-release/async?userId=${userId}`,
  291. {
  292. method: "POST",
  293. body: JSON.stringify(ids),
  294. headers: { "Content-Type": "application/json" },
  295. }
  296. );
  297. });
  298. export const getBatchReleaseProgress = cache(async (jobId: string) => {
  299. return await serverFetchJson<{ id: number|null; code: string; entity?: any }>(
  300. `${BASE_API_URL}/doPickOrder/batch-release/progress/${jobId}`,
  301. { method: "GET" }
  302. );
  303. });
  304. export const assignPickOrderByStore = cache(async (data: AssignByStoreRequest) => {
  305. return await serverFetchJson<AssignByStoreResponse>(`${BASE_API_URL}/doPickOrder/assign-by-store`,
  306. {
  307. method: "POST",
  308. body: JSON.stringify(data),
  309. headers: { "Content-Type": "application/json" },
  310. })
  311. })
  312. export const releaseAssignedPickOrderByStore = cache(async (data: AssignByStoreRequest) => {
  313. return await serverFetchJson<AssignByStoreResponse>(`${BASE_API_URL}/doPickOrder/release-assigned-by-store`,
  314. {
  315. method: "POST",
  316. body: JSON.stringify(data),
  317. headers: { "Content-Type": "application/json" },
  318. })
  319. })
  320. export async function releaseDo(input: ReleaseDoRequest) {
  321. const response = await serverFetchJson<ReleaseDoResponse>(`${BASE_API_URL}/do/release`, {
  322. method: 'POST',
  323. body: JSON.stringify(input),
  324. headers: {
  325. 'Content-Type': 'application/json',
  326. },
  327. });
  328. revalidateTag('do');
  329. return response;
  330. }
  331. export const preloadDo = () => {
  332. fetchDoList();
  333. };
  334. export const fetchDoList = cache(async () => {
  335. return serverFetchJson<DoResult[]>(`${BASE_API_URL}/do/list`, {
  336. next: { tags: ["doList"] },
  337. });
  338. });
  339. export const fetchDoDetail = cache(async (id: number) => {
  340. return serverFetchJson<DoDetail>(`${BASE_API_URL}/do/detail/${id}`, {
  341. method: "GET",
  342. headers: { "Content-Type": "application/json" },
  343. next: {
  344. tags: ["doDetail"]
  345. }
  346. });
  347. });
  348. export async function fetchDoSearch(
  349. code: string,
  350. shopName: string,
  351. status: string,
  352. orderStartDate: string,
  353. orderEndDate: string,
  354. estArrStartDate: string,
  355. estArrEndDate: string,
  356. pageNum?: number,
  357. pageSize?: number,
  358. truckLanceCode?: string,
  359. /** 後端:All/null 為全部;2F/4F 依供應商白名單篩選 */
  360. floor?: string | null,
  361. /** null:不篩;true/false:只顯示加單或非加單 DO */
  362. isExtra?: boolean | null,
  363. ): Promise<DoSearchLiteResponse> {
  364. // 构建请求体
  365. const requestBody: any = {
  366. code: code || null,
  367. shopName: shopName || null,
  368. status: status || null,
  369. estimatedArrivalDate: estArrStartDate || null, // 使用单个日期字段
  370. truckLanceCode: truckLanceCode || null,
  371. pageNum: pageNum || 1,
  372. pageSize: pageSize || 10,
  373. floor: floor && floor !== "All" ? floor : null,
  374. ...(isExtra !== undefined && isExtra !== null ? { isExtra } : {}),
  375. };
  376. // 如果日期不为空,转换为 LocalDateTime 格式
  377. if (estArrStartDate) {
  378. requestBody.estimatedArrivalDate = estArrStartDate; // 格式: "2026-01-19T00:00:00"
  379. } else {
  380. requestBody.estimatedArrivalDate = null;
  381. }
  382. /** v2:車線正規化、未指派合併、分批掃描(後端 /do/search-do-lite-v2) */
  383. const data = await serverFetchJson<DoSearchLiteResponse>(
  384. `${BASE_API_URL}/do/search-do-lite-v2`,
  385. {
  386. method: "POST",
  387. headers: { "Content-Type": "application/json" },
  388. body: JSON.stringify(requestBody),
  389. },
  390. );
  391. return data;
  392. }
  393. export async function fetchDoSearchList(
  394. code: string,
  395. shopName: string,
  396. status: string,
  397. orderStartDate: string,
  398. orderEndDate: string,
  399. etaFrom: string,
  400. etaTo: string,
  401. page = 0,
  402. size = 500
  403. ): Promise<DoSearchAll[]> {
  404. const params = new URLSearchParams();
  405. if (code) params.append("code", code);
  406. if (shopName) params.append("shopName", shopName);
  407. if (status) params.append("status", status);
  408. if (orderStartDate) params.append("orderFrom", orderStartDate);
  409. if (orderEndDate) params.append("orderTo", orderEndDate);
  410. if (etaFrom) params.append("etaFrom", etaFrom);
  411. if (etaTo) params.append("etaTo", etaTo);
  412. params.append("page", String(page));
  413. params.append("size", String(size));
  414. const res = await fetch(`/api/delivery-order/search-do-list?${params.toString()}`);
  415. const pageData = await res.json(); // Spring Page 结构
  416. return pageData.content; // 前端继续沿用你原来的 client-side 分页逻辑
  417. }
  418. export async function printDN(request: PrintDeliveryNoteRequest){
  419. const params = new URLSearchParams();
  420. params.append('doPickOrderId', request.doPickOrderId.toString());
  421. params.append('printerId', request.printerId.toString());
  422. if (request.printQty !== null && request.printQty !== undefined) {
  423. params.append('printQty', request.printQty.toString());
  424. }
  425. params.append('numOfCarton', request.numOfCarton.toString());
  426. params.append('isDraft', request.isDraft.toString());
  427. try {
  428. const response = await serverFetch(`${BASE_API_URL}/do/print-DN?${params.toString()}`, {
  429. method: "GET",
  430. });
  431. if (response.ok) {
  432. return { success: true, message: "Print job sent successfully (DN)" } as PrintDeliveryNoteResponse;
  433. }
  434. const errorText = await response.text();
  435. console.error("Print DN error:", errorText);
  436. return {
  437. success: false,
  438. message: "No data found for this pick order."
  439. } as PrintDeliveryNoteResponse;
  440. } catch (error) {
  441. console.error("Error in printDN:", error);
  442. return {
  443. success: false,
  444. message: "No data found for this pick order."
  445. } as PrintDeliveryNoteResponse;
  446. }
  447. }
  448. export async function printDNLabels(request: PrintDNLabelsRequest){
  449. const params = new URLSearchParams();
  450. params.append('doPickOrderId', request.doPickOrderId.toString());
  451. params.append('printerId', request.printerId.toString());
  452. if (request.printQty !== null && request.printQty !== undefined) {
  453. params.append('printQty', request.printQty.toString());
  454. }
  455. params.append('numOfCarton', request.numOfCarton.toString());
  456. const response = await serverFetchWithNoContent(`${BASE_API_URL}/do/print-DNLabels?${params.toString()}`,{
  457. method: "GET"
  458. });
  459. return { success: true, message: "Print job sent successfully (labels)"} as PrintDeliveryNoteResponse
  460. }
  461. export async function printDNLabelsReprint(request: PrintDNLabelsReprintRequest){
  462. const params = new URLSearchParams();
  463. params.append('doPickOrderId', request.doPickOrderId.toString());
  464. params.append('printerId', request.printerId.toString());
  465. if (request.printQty !== null && request.printQty !== undefined) {
  466. params.append('printQty', request.printQty.toString());
  467. }
  468. params.append('fromCarton', request.fromCarton.toString());
  469. params.append('toCarton', request.toCarton.toString());
  470. params.append('totalCartonsOnShipment', request.totalCartonsOnShipment.toString());
  471. await serverFetchWithNoContent(`${BASE_API_URL}/do/print-DNLabels-reprint?${params.toString()}`,{
  472. method: "GET"
  473. });
  474. return { success: true, message: "Print job sent successfully (reprint labels)"} as PrintDeliveryNoteResponse
  475. }
  476. export interface PrintWorkbenchDeliveryNoteRequest{
  477. deliveryOrderPickOrderId: number;
  478. printerId: number;
  479. printQty: number;
  480. numOfCarton: number;
  481. isDraft: boolean;
  482. }
  483. export interface PrintWorkbenchDNLabelsRequest{
  484. deliveryOrderPickOrderId: number;
  485. printerId: number;
  486. printQty: number;
  487. numOfCarton: number;
  488. }
  489. export interface PrintWorkbenchDNLabelsReprintRequest{
  490. deliveryOrderPickOrderId: number;
  491. printerId: number;
  492. printQty: number;
  493. fromCarton: number;
  494. toCarton: number;
  495. totalCartonsOnShipment: number;
  496. }
  497. export async function printDNWorkbench(request: PrintWorkbenchDeliveryNoteRequest){
  498. const params = new URLSearchParams();
  499. params.append("doPickOrderId", request.deliveryOrderPickOrderId.toString());
  500. params.append("printerId", request.printerId.toString());
  501. if (request.printQty !== null && request.printQty !== undefined) {
  502. params.append("printQty", request.printQty.toString());
  503. }
  504. params.append("numOfCarton", request.numOfCarton.toString());
  505. params.append("isDraft", request.isDraft.toString());
  506. try {
  507. const response = await serverFetch(`${BASE_API_URL}/doPickOrder/workbench/print-DN?${params.toString()}`, {
  508. method: "GET",
  509. });
  510. if (response.ok) {
  511. return { success: true, message: "Print job sent successfully (workbench DN)" } as PrintDeliveryNoteResponse;
  512. }
  513. const errorText = await response.text();
  514. console.error("Workbench print DN error:", errorText);
  515. return {
  516. success: false,
  517. message: "No workbench data found for this ticket.",
  518. } as PrintDeliveryNoteResponse;
  519. } catch (error) {
  520. console.error("Error in printDNWorkbench:", error);
  521. return {
  522. success: false,
  523. message: "No workbench data found for this ticket.",
  524. } as PrintDeliveryNoteResponse;
  525. }
  526. }
  527. export async function printDNLabelsWorkbench(request: PrintWorkbenchDNLabelsRequest){
  528. const params = new URLSearchParams();
  529. params.append("doPickOrderId", request.deliveryOrderPickOrderId.toString());
  530. params.append("printerId", request.printerId.toString());
  531. if (request.printQty !== null && request.printQty !== undefined) {
  532. params.append("printQty", request.printQty.toString());
  533. }
  534. params.append("numOfCarton", request.numOfCarton.toString());
  535. await serverFetchWithNoContent(`${BASE_API_URL}/doPickOrder/workbench/print-DNLabels?${params.toString()}`,{
  536. method: "GET"
  537. });
  538. return { success: true, message: "Print job sent successfully (workbench labels)"} as PrintDeliveryNoteResponse
  539. }
  540. export async function printDNLabelsReprintWorkbench(request: PrintWorkbenchDNLabelsReprintRequest){
  541. const params = new URLSearchParams();
  542. params.append("doPickOrderId", request.deliveryOrderPickOrderId.toString());
  543. params.append("printerId", request.printerId.toString());
  544. if (request.printQty !== null && request.printQty !== undefined) {
  545. params.append("printQty", request.printQty.toString());
  546. }
  547. params.append("fromCarton", request.fromCarton.toString());
  548. params.append("toCarton", request.toCarton.toString());
  549. params.append("totalCartonsOnShipment", request.totalCartonsOnShipment.toString());
  550. await serverFetchWithNoContent(`${BASE_API_URL}/doPickOrder/workbench/print-DNLabels-reprint?${params.toString()}`,{
  551. method: "GET"
  552. });
  553. return { success: true, message: "Print job sent successfully (workbench reprint labels)"} as PrintDeliveryNoteResponse
  554. }
  555. export interface Check4FTruckBatchResponse {
  556. hasProblem: boolean;
  557. problems: ProblemDoDto[];
  558. }
  559. export interface ProblemDoDto {
  560. deliveryOrderId: number;
  561. deliveryOrderCode: string;
  562. targetDate: string;
  563. availableTrucks: TruckInfoDto[];
  564. }
  565. export interface TruckInfoDto {
  566. id: number;
  567. truckLanceCode: string;
  568. departureTime: string;
  569. storeId: string;
  570. shopCode: string;
  571. shopName: string;
  572. }
  573. export const check4FTrucksBatch = cache(async (doIds: number[]) => {
  574. return await serverFetchJson<Check4FTruckBatchResponse>(`${BASE_API_URL}/do/check-4f-trucks-batch`, {
  575. method: "POST",
  576. body: JSON.stringify(doIds),
  577. headers: { "Content-Type": "application/json" },
  578. });
  579. });
  580. export async function fetchAllDoSearch(
  581. code: string,
  582. shopName: string,
  583. status: string,
  584. estArrStartDate: string,
  585. truckLanceCode?: string,
  586. floor?: string | null,
  587. isExtra?: boolean | null,
  588. ): Promise<DoSearchAll[]> {
  589. // 使用一个很大的 pageSize 来获取所有匹配的记录
  590. const requestBody: any = {
  591. code: code || null,
  592. shopName: shopName || null,
  593. status: status || null,
  594. estimatedArrivalDate: estArrStartDate || null,
  595. truckLanceCode: truckLanceCode || null,
  596. pageNum: 1,
  597. pageSize: 10000, // 使用一个很大的值来获取所有记录
  598. floor: floor && floor !== "All" ? floor : null,
  599. ...(isExtra !== undefined && isExtra !== null ? { isExtra } : {}),
  600. };
  601. if (estArrStartDate) {
  602. requestBody.estimatedArrivalDate = estArrStartDate;
  603. } else {
  604. requestBody.estimatedArrivalDate = null;
  605. }
  606. const data = await serverFetchJson<DoSearchLiteResponse>(
  607. `${BASE_API_URL}/do/search-do-lite-v2`,
  608. {
  609. method: "POST",
  610. headers: { "Content-Type": "application/json" },
  611. body: JSON.stringify(requestBody),
  612. },
  613. );
  614. return data.records;
  615. }