From 86289c0be5f9487b72fe91ef8643dc59af8fc738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B8=B8=E7=86=9F=E5=90=B4=E5=BD=A6=E7=A5=96?= Date: Wed, 4 Nov 2026 17:35:23 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=80=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/controller/PageController.java | 23 +- .../TransferNoticeReturnPdaController.java | 53 ++ .../app/dao/TransferNoticeReturnDao.java | 36 ++ .../TransferNoticeReturnConfirmData.java | 18 + .../entity/TransferNoticeReturnLineData.java | 32 + .../entity/TransferNoticeReturnNoticeRow.java | 36 ++ .../TransferNoticeReturnScanResult.java | 32 + .../TransferNoticeReturnValidateData.java | 14 + .../TransferNoticeReturnPdaService.java | 38 ++ .../TransferNoticeReturnPdaServiceImpl.java | 563 ++++++++++++++++++ .../mapper/app/TransferNoticeReturn.xml | 55 ++ .../js/pdaOther/transferNoticeReturnStep1.js | 137 +++++ .../js/pdaOther/transferNoticeReturnStep2.js | 279 +++++++++ .../pdaOther/transferNoticeReturnStep1.ftl | 152 +++++ .../pdaOther/transferNoticeReturnStep2.ftl | 120 ++++ 15 files changed, 1587 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/heai/modules/app/controller/TransferNoticeReturnPdaController.java create mode 100644 src/main/java/com/heai/modules/app/dao/TransferNoticeReturnDao.java create mode 100644 src/main/java/com/heai/modules/app/entity/TransferNoticeReturnConfirmData.java create mode 100644 src/main/java/com/heai/modules/app/entity/TransferNoticeReturnLineData.java create mode 100644 src/main/java/com/heai/modules/app/entity/TransferNoticeReturnNoticeRow.java create mode 100644 src/main/java/com/heai/modules/app/entity/TransferNoticeReturnScanResult.java create mode 100644 src/main/java/com/heai/modules/app/entity/TransferNoticeReturnValidateData.java create mode 100644 src/main/java/com/heai/modules/app/service/TransferNoticeReturnPdaService.java create mode 100644 src/main/java/com/heai/modules/app/service/impl/TransferNoticeReturnPdaServiceImpl.java create mode 100644 src/main/resources/mapper/app/TransferNoticeReturn.xml create mode 100644 src/main/resources/static/js/pdaOther/transferNoticeReturnStep1.js create mode 100644 src/main/resources/static/js/pdaOther/transferNoticeReturnStep2.js create mode 100644 src/main/resources/templates/pdaOther/transferNoticeReturnStep1.ftl create mode 100644 src/main/resources/templates/pdaOther/transferNoticeReturnStep2.ftl diff --git a/src/main/java/com/heai/modules/app/controller/PageController.java b/src/main/java/com/heai/modules/app/controller/PageController.java index 6866f51..e54a058 100644 --- a/src/main/java/com/heai/modules/app/controller/PageController.java +++ b/src/main/java/com/heai/modules/app/controller/PageController.java @@ -599,7 +599,8 @@ public class PageController { /** * PDA 袋装标签生产退库 步骤1 - rqrq */ - @GetMapping("/pdaOther/productionBagReturnStep1") + // @GetMapping("/pdaOther/productionBagReturnStep1") + @GetMapping("/pdaOther/productionBagReturnStep1_old") public String productionBagReturnStep1(String menuId, String titleName, Model model) { model.addAttribute("menuId", menuId); model.addAttribute("titleName", titleName); @@ -616,6 +617,26 @@ public class PageController { return "/pdaOther/productionBagReturnStep2"; } + /** + * PDA 扫入库通知单退库 步骤1 - rqrq + */ + @GetMapping("/pdaOther/productionBagReturnStep1") + public String transferNoticeReturnStep1(String menuId, String titleName, Model model) { + model.addAttribute("menuId", menuId); + model.addAttribute("titleName", titleName); + return "/pdaOther/transferNoticeReturnStep1"; + } + + /** + * PDA 扫入库通知单退库 步骤2 - rqrq + */ + @GetMapping("/pdaOther/transferNoticeReturnStep2") + public String transferNoticeReturnStep2(String menuId, String titleName, Model model) { + model.addAttribute("menuId", menuId); + model.addAttribute("titleName", titleName); + return "/pdaOther/transferNoticeReturnStep2"; + } + /** * 模具扫描页面跳转 diff --git a/src/main/java/com/heai/modules/app/controller/TransferNoticeReturnPdaController.java b/src/main/java/com/heai/modules/app/controller/TransferNoticeReturnPdaController.java new file mode 100644 index 0000000..b095021 --- /dev/null +++ b/src/main/java/com/heai/modules/app/controller/TransferNoticeReturnPdaController.java @@ -0,0 +1,53 @@ +package com.heai.modules.app.controller; + +import com.heai.common.annotation.RepeatSubmit; +import com.heai.common.utils.R; +import com.heai.modules.app.entity.TransferNoticeReturnConfirmData; +import com.heai.modules.app.entity.TransferNoticeReturnLineData; +import com.heai.modules.app.entity.TransferNoticeReturnScanResult; +import com.heai.modules.app.entity.TransferNoticeReturnValidateData; +import com.heai.modules.app.service.TransferNoticeReturnPdaService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * PDA 扫入库通知单退库 - rqrq + */ +@RestController +@RequestMapping("/pda/transferNoticeReturn") +public class TransferNoticeReturnPdaController { + + @Autowired + private TransferNoticeReturnPdaService transferNoticeReturnPdaService; + + /** + * 步骤1:扫描入库通知单 - rqrq + */ + @PostMapping("/resolveNotice") + public R resolveNotice(@RequestBody TransferNoticeReturnScanResult data) { + String transFerNo = data == null ? "" : data.getTransFerNo(); + return R.ok().put("row", transferNoticeReturnPdaService.resolveNotice(transFerNo)); + } + + /** + * 步骤2:扫袋贴校验 - rqrq + */ + @PostMapping("/validateBagLine") + public R validateBagLine(@RequestBody TransferNoticeReturnValidateData data) { + TransferNoticeReturnLineData line = transferNoticeReturnPdaService.validateBagLine(data); + return R.ok().put("row", line); + } + + /** + * 确认退库 - rqrq + */ + @PostMapping("/confirm") + @RepeatSubmit + public R confirm(@RequestBody TransferNoticeReturnConfirmData data) { + transferNoticeReturnPdaService.confirm(data); + return R.ok("操作成功!"); + } +} diff --git a/src/main/java/com/heai/modules/app/dao/TransferNoticeReturnDao.java b/src/main/java/com/heai/modules/app/dao/TransferNoticeReturnDao.java new file mode 100644 index 0000000..b15459f --- /dev/null +++ b/src/main/java/com/heai/modules/app/dao/TransferNoticeReturnDao.java @@ -0,0 +1,36 @@ +package com.heai.modules.app.dao; + +import com.heai.modules.app.entity.TransferNoticeReturnNoticeRow; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 扫入库通知单退库查询与回写 - rqrq + */ +@Mapper +public interface TransferNoticeReturnDao { + + /** + * 按通知单号取头和明细 - rqrq + */ + List listNoticeDetail(@Param("transNo") String transNo); + + /** + * 按 ConfirmedTransNo 取该张 SR 的入库批次、仓库、库位 - rqrq + */ + TransferNoticeReturnNoticeRow getInboundByConfirmedTransNo(@Param("site") String site, + @Param("transNo") String transNo, + @Param("partNo") String partNo); + + /** + * 通知单头改为已取消,仅当前仍是已入库时更新 - rqrq + */ + int cancelNoticeHeader(@Param("transNo") String transNo, @Param("site") String site); + + /** + * 通知单明细 ConfirmQty 置 0 - rqrq + */ + int resetNoticeConfirmQty(@Param("transNo") String transNo, @Param("site") String site); +} diff --git a/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnConfirmData.java b/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnConfirmData.java new file mode 100644 index 0000000..7d48d45 --- /dev/null +++ b/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnConfirmData.java @@ -0,0 +1,18 @@ +package com.heai.modules.app.entity; + +import lombok.Data; + +import java.util.List; + +/** + * PDA 扫入库通知单退库 - 确认 - rqrq + */ +@Data +public class TransferNoticeReturnConfirmData { + + private String transFerNo; + + private List lines; + + private String operatorUserName; +} diff --git a/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnLineData.java b/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnLineData.java new file mode 100644 index 0000000..bc5dd23 --- /dev/null +++ b/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnLineData.java @@ -0,0 +1,32 @@ +package com.heai.modules.app.entity; + +import lombok.Data; + +/** + * PDA 扫入库通知单退库 - 表格行 - rqrq + */ +@Data +public class TransferNoticeReturnLineData { + + private Long labelRecordId; + + private String partNo; + + private String qtyIssue; + + private String batchNo; + + private String locationId; + + private String partDescSpec; + + private String umid; + + private String warehouseId; + + private String wareHouseName; + + private String itemNo; + + private String qtyReady; +} diff --git a/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnNoticeRow.java b/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnNoticeRow.java new file mode 100644 index 0000000..80aa961 --- /dev/null +++ b/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnNoticeRow.java @@ -0,0 +1,36 @@ +package com.heai.modules.app.entity; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 扫入库通知单退库:通知单头、明细及对应 SR 批次 - rqrq + */ +@Data +public class TransferNoticeReturnNoticeRow { + + private String transNo; + + private String site; + + private String noticeStatus; + + private String confirmedTransNo; + + private String orderNo; + + private String partNo; + + private String partDescription; + + private Integer seqNo; + + private BigDecimal confirmQty; + + private String batchNo; + + private String inboundLocationId; + + private String inboundWarehouseId; +} diff --git a/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnScanResult.java b/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnScanResult.java new file mode 100644 index 0000000..4db4b29 --- /dev/null +++ b/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnScanResult.java @@ -0,0 +1,32 @@ +package com.heai.modules.app.entity; + +import lombok.Data; + +/** + * PDA 扫入库通知单退库 - 步骤1返回 - rqrq + */ +@Data +public class TransferNoticeReturnScanResult { + + private String site; + + private String orderNo; + + private String partNo; + + private String partDescription; + + /** 生产订单状态 - rqrq */ + private String status; + + private Integer seqNo; + + /** 入库通知单号 - rqrq */ + private String transFerNo; + + /** 通知单已入库数量 - rqrq */ + private String confirmQty; + + /** 该通知单 SR 入库批次 - rqrq */ + private String noticeBatchNo; +} diff --git a/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnValidateData.java b/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnValidateData.java new file mode 100644 index 0000000..68643eb --- /dev/null +++ b/src/main/java/com/heai/modules/app/entity/TransferNoticeReturnValidateData.java @@ -0,0 +1,14 @@ +package com.heai.modules.app.entity; + +import lombok.Data; + +/** + * PDA 扫入库通知单退库 - 袋贴校验 - rqrq + */ +@Data +public class TransferNoticeReturnValidateData { + + private String qrContent; + + private String transFerNo; +} diff --git a/src/main/java/com/heai/modules/app/service/TransferNoticeReturnPdaService.java b/src/main/java/com/heai/modules/app/service/TransferNoticeReturnPdaService.java new file mode 100644 index 0000000..3d7cf8d --- /dev/null +++ b/src/main/java/com/heai/modules/app/service/TransferNoticeReturnPdaService.java @@ -0,0 +1,38 @@ +package com.heai.modules.app.service; + +import com.heai.modules.app.entity.TransferNoticeReturnConfirmData; +import com.heai.modules.app.entity.TransferNoticeReturnLineData; +import com.heai.modules.app.entity.TransferNoticeReturnScanResult; +import com.heai.modules.app.entity.TransferNoticeReturnValidateData; + +/** + * PDA 扫入库通知单退库 - rqrq + */ +public interface TransferNoticeReturnPdaService { + + /** + * @Description 扫描入库通知单,带出派工单和生产订单 - rqrq + * @param transFerNo 入库通知单号 + * @return 步骤1展示数据 + * @author rqrq + * @date 2026/11/04 + */ + TransferNoticeReturnScanResult resolveNotice(String transFerNo); + + /** + * @Description 扫描袋贴,校验批次、派工单和整袋库存 - rqrq + * @param data 通知单号和袋贴内容 + * @return 可加入表格的一行 + * @author rqrq + * @date 2026/11/04 + */ + TransferNoticeReturnLineData validateBagLine(TransferNoticeReturnValidateData data); + + /** + * @Description 数量核对后执行退库,并关闭入库通知单 - rqrq + * @param data 通知单号和袋贴行 + * @author rqrq + * @date 2026/11/04 + */ + void confirm(TransferNoticeReturnConfirmData data); +} diff --git a/src/main/java/com/heai/modules/app/service/impl/TransferNoticeReturnPdaServiceImpl.java b/src/main/java/com/heai/modules/app/service/impl/TransferNoticeReturnPdaServiceImpl.java new file mode 100644 index 0000000..b580ff7 --- /dev/null +++ b/src/main/java/com/heai/modules/app/service/impl/TransferNoticeReturnPdaServiceImpl.java @@ -0,0 +1,563 @@ +package com.heai.modules.app.service.impl; + +import com.heai.common.utils.DateUtil; +import com.heai.modules.app.dao.InventoryStockDao; +import com.heai.modules.app.dao.TransferNoticeReturnDao; +import com.heai.modules.app.entity.InventoryStockData; +import com.heai.modules.app.entity.TransferNoticeReturnConfirmData; +import com.heai.modules.app.entity.TransferNoticeReturnLineData; +import com.heai.modules.app.entity.TransferNoticeReturnNoticeRow; +import com.heai.modules.app.entity.TransferNoticeReturnScanResult; +import com.heai.modules.app.entity.TransferNoticeReturnValidateData; +import com.heai.modules.app.service.TransferNoticeReturnPdaService; +import com.heai.modules.app.service.WareHouseService; +import com.heai.modules.production.dao.FunctionMapper; +import com.heai.modules.production.entity.ChangeLocationData; +import com.heai.modules.production.entity.DailyPlanInData; +import com.heai.modules.production.entity.PrintLabelRecord; +import com.heai.modules.production.entity.ShopOrderData; +import com.heai.modules.production.service.DailyPlanService; +import com.heai.modules.production.service.PrintLabelRecordService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * PDA 扫入库通知单退库:按通知单关联的 SR 校验批次,退库后关闭通知单 - rqrq + * + * @author rqrq + */ +@Slf4j +@Service +public class TransferNoticeReturnPdaServiceImpl implements TransferNoticeReturnPdaService { + + private static final String TRANS_TYPE_SRR = "SRR"; + private static final String COST_GROUP_EMPTY = ""; + private static final String ORDER_REF_EMPTY = ""; + private static final String ALLOW_NEGATIVE_N = "N"; + private static final String PARTNER_ID_STAR = "*"; + private static final String STATUS_IN_STOCK = "已入库"; + private static final String NOTICE_STATUS_IN = "已入库"; + private static final String NOTICE_STATUS_ENTERED = "已录入"; + private static final String NOTICE_STATUS_CANCEL = "已取消"; + private static final BigDecimal QTY_GAP_RATE = new BigDecimal("0.02"); + private static final String QTY_MISMATCH_MSG = "退库数量与入库通知单数量不符"; + + @Autowired + private TransferNoticeReturnDao transferNoticeReturnDao; + + @Autowired + private InventoryStockDao inventoryStockDao; + + @Autowired + private WareHouseService wareHouseService; + + @Autowired + private FunctionMapper functionMapper; + + @Autowired + private DailyPlanService dailyPlanService; + + @Autowired + private PrintLabelRecordService printLabelRecordService; + + /** + * @Description 扫描入库通知单 - rqrq + */ + @Override + public TransferNoticeReturnScanResult resolveNotice(String transFerNo) { + LoadedNotice loaded = loadNotice(transFerNo); + TransferNoticeReturnScanResult result = new TransferNoticeReturnScanResult(); + result.setSite(loaded.notice.getSite()); + result.setOrderNo(loaded.shop.getOrderNo()); + result.setPartNo(loaded.notice.getPartNo()); + result.setPartDescription(loaded.notice.getPartDescription()); + result.setStatus(loaded.shop.getStatus()); + result.setSeqNo(loaded.notice.getSeqNo()); + result.setTransFerNo(loaded.notice.getTransNo()); + result.setConfirmQty(toPlainQtyString(loaded.notice.getConfirmQty())); + result.setNoticeBatchNo(trim(loaded.inbound.getBatchNo())); + log.info("入库通知单退库-步骤1 - rqrq,transNo={},orderNo={},batch={}", + result.getTransFerNo(), result.getOrderNo(), result.getNoticeBatchNo()); + return result; + } + + /** + * @Description 扫描袋贴校验 - rqrq + */ + @Override + public TransferNoticeReturnLineData validateBagLine(TransferNoticeReturnValidateData data) { + if (data == null || !StringUtils.hasText(data.getQrContent())) { + throw new RuntimeException("请扫描袋装标签"); + } + LoadedNotice loaded = loadNotice(data.getTransFerNo()); + ParsedBagQr qr = parseBagQr(data.getQrContent()); + PrintLabelRecord bag = loadBag(qr); + assertBagBelongsToNotice(bag, loaded); + InventoryStockData stock = loadStock(loaded, bag); + BigDecimal printQty = assertBagStock(bag, stock); + TransferNoticeReturnLineData line = new TransferNoticeReturnLineData(); + line.setLabelRecordId(bag.getId()); + fillLine(line, stock, bag, printQty); + log.info("入库通知单退库-袋贴校验通过 - rqrq,transNo={},labelId={},batch={}", + loaded.notice.getTransNo(), bag.getId(), bag.getBatchNo()); + return line; + } + + /** + * @Description 确认退库并关闭通知单 - rqrq + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void confirm(TransferNoticeReturnConfirmData data) { + if (data == null) { + throw new RuntimeException("参数不能为空"); + } + if (!StringUtils.hasText(data.getOperatorUserName())) { + throw new RuntimeException("无法获取登录用户"); + } + List lines = data.getLines(); + if (lines == null || lines.isEmpty()) { + throw new RuntimeException("没有退库明细"); + } + LoadedNotice loaded = loadNotice(data.getTransFerNo()); + String userName = trim(data.getOperatorUserName()); + String site = loaded.notice.getSite(); + String orderNo = loaded.shop.getOrderNo(); + + Set labelSeen = new HashSet(); + List readyList = new ArrayList(); + BigDecimal returnQty = BigDecimal.ZERO; + for (int i = 0; i < lines.size(); i++) { + TransferNoticeReturnLineData line = lines.get(i); + int rowNo = i + 1; + if (line.getLabelRecordId() == null) { + throw new RuntimeException("第" + rowNo + "行缺少袋装标签标识"); + } + if (!labelSeen.add(line.getLabelRecordId())) { + throw new RuntimeException("第" + rowNo + "行:袋装标签重复"); + } + PrintLabelRecord bag = printLabelRecordService.getById(line.getLabelRecordId()); + assertBagBasics(bag); + assertBagBelongsToNotice(bag, loaded); + if (!StringUtils.hasText(line.getPartNo()) || !eqIgnoreCase(line.getPartNo(), bag.getPartNo())) { + throw new RuntimeException("第" + rowNo + "行料号与标签不一致"); + } + if (!StringUtils.hasText(line.getBatchNo()) || !trim(line.getBatchNo()).equals(trim(bag.getBatchNo()))) { + throw new RuntimeException("第" + rowNo + "行批号与标签不一致"); + } + BigDecimal qtyFromLine = parseQty(line.getQtyIssue(), rowNo); + BigDecimal printQty = bag.getPrintQty(); + if (printQty == null || printQty.compareTo(qtyFromLine) != 0) { + throw new RuntimeException("第" + rowNo + "行退库数量须等于标签整袋数量"); + } + InventoryStockData stock = loadStock(loaded, bag); + assertReturnQtyAgainstOnHand(rowNo, printQty, stock); + ReadyLine ready = new ReadyLine(); + ready.bag = bag; + ready.qty = printQty; + readyList.add(ready); + returnQty = returnQty.add(printQty); + } + assertQtyNearConfirm(returnQty, loaded.notice.getConfirmQty()); + + List outRows = new ArrayList(); + Set warehouses = new HashSet(); + for (int i = 0; i < readyList.size(); i++) { + ReadyLine ready = readyList.get(i); + PrintLabelRecord bag = ready.bag; + boolean needRelocate = needRelocate(bag.getWarehouseId(), bag.getLocationId(), + loaded.inbound.getInboundWarehouseId(), loaded.inbound.getInboundLocationId()); + if (needRelocate) { + ChangeLocationData mv = new ChangeLocationData(); + mv.setSite(site); + mv.setPartNo(trim(bag.getPartNo())); + mv.setQty(ready.qty.doubleValue()); + mv.setBatchNo(trim(bag.getBatchNo())); + mv.setLocationId(normLoc(bag.getLocationId())); + mv.setWarehouseId(trim(bag.getWarehouseId())); + mv.setNewLocationId(normLoc(loaded.inbound.getInboundLocationId())); + mv.setNewWareHouseId(trim(loaded.inbound.getInboundWarehouseId())); + mv.setUserId(userName); + mv.setPrintQty(1.0); + mv.setPrintLabelId(null); + wareHouseService.saveChangeLocationIdNoPrintLabel(Collections.singletonList(mv)); + log.info("入库通知单退库-已移回原始库位 - rqrq,partNo={},目标仓={},目标位={}", + bag.getPartNo(), loaded.inbound.getInboundWarehouseId(), loaded.inbound.getInboundLocationId()); + } + OutLine out = new OutLine(); + out.warehouseId = trim(loaded.inbound.getInboundWarehouseId()); + out.partNo = trim(bag.getPartNo()); + out.batchNo = trim(bag.getBatchNo()); + out.locationId = normLoc(loaded.inbound.getInboundLocationId()); + out.qty = ready.qty.doubleValue(); + outRows.add(out); + warehouses.add(out.warehouseId); + } + if (warehouses.size() != 1) { + throw new RuntimeException("本次退库包含多个仓库,请拆分为多次提交"); + } + String warehouse0 = outRows.get(0).warehouseId; + if (!StringUtils.hasText(warehouse0)) { + throw new RuntimeException("入库主档仓库为空,无法退库"); + } + saveReturnTrans(site, warehouse0, userName, orderNo, outRows); + for (ReadyLine ready : readyList) { + inventoryStockDao.updatePrintLabelAfterBagOtherOut(ready.bag.getId()); + } + int headerRows = transferNoticeReturnDao.cancelNoticeHeader(loaded.notice.getTransNo(), site); + if (headerRows != 1) { + throw new RuntimeException("入库通知单状态已变化,请重新扫描"); + } + int detailRows = transferNoticeReturnDao.resetNoticeConfirmQty(loaded.notice.getTransNo(), site); + if (detailRows < 1) { + throw new RuntimeException("入库通知单明细更新失败"); + } + log.info("入库通知单退库完成 - rqrq,transNo={},orderNo={},行数={}", + loaded.notice.getTransNo(), orderNo, readyList.size()); + } + + /** + * 读取已入库通知单、派工单和生产入库批次 - rqrq + */ + private LoadedNotice loadNotice(String transFerNo) { + if (!StringUtils.hasText(transFerNo)) { + throw new RuntimeException("请输入入库通知单号"); + } + List rows = transferNoticeReturnDao.listNoticeDetail(trim(transFerNo)); + if (rows == null || rows.isEmpty()) { + throw new RuntimeException("入库通知单不存在"); + } + if (rows.size() != 1) { + throw new RuntimeException("入库通知单明细不唯一"); + } + TransferNoticeReturnNoticeRow notice = rows.get(0); + String noticeStatus = trim(notice.getNoticeStatus()); + if (NOTICE_STATUS_CANCEL.equals(noticeStatus)) { + throw new RuntimeException("该入库通知单已取消"); + } + // 没收满时状态仍是已录入,但 ConfirmQty 已经大于 0,也允许退库 - rqrq + if (!NOTICE_STATUS_IN.equals(noticeStatus) && !NOTICE_STATUS_ENTERED.equals(noticeStatus)) { + throw new RuntimeException("该入库通知单不是已入库状态"); + } + if (notice.getSeqNo() == null) { + throw new RuntimeException("该入库通知单没有派工单号"); + } + if (!StringUtils.hasText(notice.getConfirmedTransNo())) { + throw new RuntimeException("该入库通知单未关联入库单"); + } + if (notice.getConfirmQty() == null || notice.getConfirmQty().compareTo(BigDecimal.ZERO) <= 0) { + throw new RuntimeException("该入库通知单没有入库数量"); + } + TransferNoticeReturnNoticeRow inbound = transferNoticeReturnDao.getInboundByConfirmedTransNo( + trim(notice.getSite()), trim(notice.getConfirmedTransNo()), trim(notice.getPartNo())); + if (inbound == null || !StringUtils.hasText(inbound.getBatchNo())) { + throw new RuntimeException("该入库通知单未找到对应入库批次"); + } + if (!StringUtils.hasText(inbound.getInboundWarehouseId()) || !StringUtils.hasText(inbound.getInboundLocationId())) { + throw new RuntimeException("该入库通知单的入库仓库或库位为空"); + } + DailyPlanInData dispatch = new DailyPlanInData(); + dispatch.setSeqNo(notice.getSeqNo()); + ShopOrderData shop = dailyPlanService.getShopOrderForReturn(dispatch); + if (shop == null || !StringUtils.hasText(shop.getOrderNo())) { + throw new RuntimeException("根据通知单派工单未找到生产订单"); + } + if (isForbiddenReturnStatus(shop.getStatus())) { + throw new RuntimeException("该生产订单状态不允许生产退库,请检查生产订单状态"); + } + if (!eqIgnoreCase(shop.getSite(), notice.getSite())) { + throw new RuntimeException("通知单工厂与派工单工厂不一致"); + } + if (!eqIgnoreCase(shop.getOrderNo(), notice.getOrderNo())) { + throw new RuntimeException("通知单生产订单与派工单不一致"); + } + if (!eqIgnoreCase(shop.getPartNo(), notice.getPartNo())) { + throw new RuntimeException("通知单物料与生产订单物料不一致"); + } + LoadedNotice loaded = new LoadedNotice(); + loaded.notice = notice; + loaded.inbound = inbound; + loaded.shop = shop; + return loaded; + } + + private PrintLabelRecord loadBag(ParsedBagQr qr) { + PrintLabelRecord bag = inventoryStockDao.selectPrintLabelBagBySeqNoAndItemNo(qr.seqNo, qr.itemNo); + assertBagBasics(bag); + if (!eqIgnoreCase(qr.site, bag.getSite())) { + throw new RuntimeException("扫码工厂与标签记录不一致"); + } + if (!eqIgnoreCase(qr.partNo, bag.getPartNo())) { + throw new RuntimeException("扫码物料与标签记录不一致"); + } + return bag; + } + + private void assertBagBelongsToNotice(PrintLabelRecord bag, LoadedNotice loaded) { + if (!eqIgnoreCase(bag.getSite(), loaded.notice.getSite())) { + throw new RuntimeException("袋贴工厂与入库通知单不一致"); + } + if (!eqIgnoreCase(bag.getPartNo(), loaded.notice.getPartNo())) { + throw new RuntimeException("该袋贴物料与入库通知单不一致"); + } + if (bag.getSeqNo() == null || bag.getSeqNo().longValue() != loaded.notice.getSeqNo().longValue()) { + throw new RuntimeException("该袋贴派工单与入库通知单不一致"); + } + if (!trim(bag.getBatchNo()).equals(trim(loaded.inbound.getBatchNo()))) { + throw new RuntimeException("袋贴批次错误,该通知单的批次应该是" + trim(loaded.inbound.getBatchNo())); + } + } + + private InventoryStockData loadStock(LoadedNotice loaded, PrintLabelRecord bag) { + InventoryStockData query = new InventoryStockData(); + query.setSite(trim(bag.getSite())); + query.setWarehouseId(trim(bag.getWarehouseId())); + query.setPartNo(trim(bag.getPartNo())); + query.setBatchNo(trim(bag.getBatchNo())); + query.setLocationId(normLoc(bag.getLocationId())); + query.setOrderNo(trim(loaded.shop.getOrderNo())); + query.setSeqNo(loaded.notice.getSeqNo()); + return inventoryStockDao.getInventoryStockData(query); + } + + private BigDecimal assertBagStock(PrintLabelRecord bag, InventoryStockData stock) { + if (stock == null || !StringUtils.hasText(stock.getSite())) { + throw new RuntimeException("仓库无此物料批次或标签与账存不一致"); + } + BigDecimal onHand = stock.getQtyOnHand() == null ? BigDecimal.ZERO : stock.getQtyOnHand(); + if (onHand.compareTo(BigDecimal.ZERO) <= 0) { + throw new RuntimeException("该库位现存量不足"); + } + BigDecimal printQty = bag.getPrintQty(); + if (printQty == null || printQty.compareTo(BigDecimal.ZERO) <= 0) { + throw new RuntimeException("标签打印数量无效"); + } + if (onHand.compareTo(printQty) < 0) { + throw new RuntimeException("现存量不足以整袋退库(需 " + toPlainQtyString(printQty) + ",现存量 " + toPlainQtyString(onHand) + ")"); + } + return printQty; + } + + private static void assertReturnQtyAgainstOnHand(int rowNo, BigDecimal qtyLine, InventoryStockData stock) { + if (stock == null || !StringUtils.hasText(stock.getSite())) { + throw new RuntimeException("第" + rowNo + "行:当前库位不存在该库存批次"); + } + BigDecimal onHand = stock.getQtyOnHand() == null ? BigDecimal.ZERO : stock.getQtyOnHand(); + if (onHand.compareTo(BigDecimal.ZERO) <= 0) { + throw new RuntimeException("第" + rowNo + "行:该库位现存数量不足"); + } + if (qtyLine.compareTo(onHand) > 0) { + throw new RuntimeException("第" + rowNo + "行:退库数量超过库位现存数量"); + } + } + + /** + * 袋贴合计与通知单 ConfirmQty 相差达到 2% 则拒绝,提示不写比例 - rqrq + */ + private static void assertQtyNearConfirm(BigDecimal returnQty, BigDecimal confirmQty) { + if (returnQty == null || confirmQty == null || confirmQty.compareTo(BigDecimal.ZERO) <= 0) { + throw new RuntimeException(QTY_MISMATCH_MSG); + } + BigDecimal diff = returnQty.subtract(confirmQty).abs(); + BigDecimal limit = confirmQty.multiply(QTY_GAP_RATE); + if (diff.compareTo(limit) >= 0) { + throw new RuntimeException(QTY_MISMATCH_MSG); + } + } + + private void assertBagBasics(PrintLabelRecord bag) { + if (bag == null || bag.getId() == null) { + throw new RuntimeException("袋装标签不存在"); + } + if (!STATUS_IN_STOCK.equals(trim(bag.getStatus()))) { + throw new RuntimeException("标签状态不是已入库,不能退库"); + } + if (!StringUtils.hasText(bag.getWarehouseId()) || !StringUtils.hasText(bag.getLocationId()) + || !StringUtils.hasText(bag.getBatchNo())) { + throw new RuntimeException("标签未绑定仓库/库位/批号,不能退库"); + } + } + + private void fillLine(TransferNoticeReturnLineData line, InventoryStockData stock, PrintLabelRecord bag, BigDecimal printQty) { + line.setWarehouseId(trim(bag.getWarehouseId())); + line.setWareHouseName(stock.getWareHouseName() != null ? stock.getWareHouseName() : ""); + line.setPartNo(trim(bag.getPartNo())); + line.setQtyIssue(toPlainQtyString(printQty)); + line.setBatchNo(trim(bag.getBatchNo())); + line.setLocationId(normLoc(bag.getLocationId())); + line.setPartDescSpec(stock.getPartNoDescSpec() != null ? stock.getPartNoDescSpec() : ""); + line.setUmid(""); + line.setItemNo(bag.getItemNo() == null ? "" : String.valueOf(bag.getItemNo())); + line.setQtyReady(""); + } + + private static ParsedBagQr parseBagQr(String raw) { + String[] parts = raw.split(";", -1); + if (parts.length != 5 && parts.length != 6) { + throw new RuntimeException("袋装标签格式错误,应为:site;partNo;数量;seqNo;item_no"); + } + for (int i = 0; i < parts.length; i++) { + parts[i] = parts[i] == null ? "" : parts[i].trim(); + } + long seq; + long item; + try { + seq = Long.parseLong(parts[3]); + item = Long.parseLong(parts[4]); + } catch (NumberFormatException e) { + throw new RuntimeException("袋装标签序号或项次格式错误"); + } + if (seq <= 0 || item <= 0) { + throw new RuntimeException("袋装标签序号或项次无效"); + } + if (!StringUtils.hasText(parts[0]) || !StringUtils.hasText(parts[1])) { + throw new RuntimeException("袋装标签缺少工厂或物料"); + } + ParsedBagQr qr = new ParsedBagQr(); + qr.site = parts[0]; + qr.partNo = parts[1]; + qr.seqNo = seq; + qr.itemNo = item; + return qr; + } + + private void saveReturnTrans(String site, String warehouseId, String userName, String orderNo, List outRows) { + Date transDate; + try { + transDate = DateUtil.getDate(DateUtil.getStringDate(new Date())); + } catch (ParseException e) { + throw new RuntimeException("业务日期解析失败"); + } + List headerParams = new ArrayList(); + headerParams.add(trim(site)); + headerParams.add(trim(warehouseId)); + headerParams.add(TRANS_TYPE_SRR); + headerParams.add(transDate); + headerParams.add(trim(userName)); + headerParams.add(trim(userName)); + headerParams.add(""); + headerParams.add(PARTNER_ID_STAR); + headerParams.add("入库通知单退库"); + headerParams.add(orderNo); + headerParams.add(""); + Map map = functionMapper.getProcedure("Inventory_Create_TransHeader_other", headerParams); + if (map == null) { + throw new RuntimeException("主档存储过程无返回"); + } + String resultCode = String.valueOf(map.get("result_code")).trim(); + String transNo = String.valueOf(map.get("result_msg")).trim(); + if (!"200".equals(resultCode)) { + throw new RuntimeException(transNo); + } + if (!StringUtils.hasText(transNo)) { + throw new RuntimeException("未生成退库出库单号"); + } + for (int i = 0; i < outRows.size(); i++) { + OutLine row = outRows.get(i); + List detailParams = new ArrayList(); + detailParams.add(trim(site)); + detailParams.add(transNo); + detailParams.add(i + 1); + detailParams.add(row.partNo); + detailParams.add(row.batchNo); + detailParams.add(row.locationId.toUpperCase()); + detailParams.add(row.qty); + detailParams.add(COST_GROUP_EMPTY); + detailParams.add(trim(orderNo)); + detailParams.add(ORDER_REF_EMPTY); + detailParams.add(ORDER_REF_EMPTY); + detailParams.add(ALLOW_NEGATIVE_N); + map = functionMapper.getProcedure("Inventory_Create_TransDetail_Out_other", detailParams); + if (map == null) { + throw new RuntimeException("明细存储过程无返回:" + row.partNo); + } + String detailCode = String.valueOf(map.get("result_code")).trim(); + if (!"200".equals(detailCode)) { + throw new RuntimeException(String.valueOf(map.get("result_msg"))); + } + } + } + + private static BigDecimal parseQty(String qtyStr, int rowNo) { + if (!StringUtils.hasText(qtyStr)) { + throw new RuntimeException("第" + rowNo + "行退库数量无效"); + } + try { + BigDecimal value = new BigDecimal(trim(qtyStr)); + if (value.compareTo(BigDecimal.ZERO) <= 0) { + throw new RuntimeException("第" + rowNo + "行退库数量须大于 0"); + } + return value; + } catch (NumberFormatException e) { + throw new RuntimeException("第" + rowNo + "行退库数量格式错误"); + } + } + + private static boolean needRelocate(String labelWh, String labelLoc, String inboundWh, String inboundLoc) { + return !eqIgnoreCase(labelWh, inboundWh) || !Objects.equals(normLoc(labelLoc), normLoc(inboundLoc)); + } + + private static boolean isForbiddenReturnStatus(String status) { + if (!StringUtils.hasText(status)) { + return false; + } + String value = status.trim(); + return "已计划".equals(value) || "已取消".equals(value) || "已关闭".equals(value); + } + + private static boolean eqIgnoreCase(String left, String right) { + return trim(left).equalsIgnoreCase(trim(right)); + } + + private static String toPlainQtyString(BigDecimal qty) { + return qty.stripTrailingZeros().toPlainString(); + } + + private static String normLoc(String value) { + return value == null ? "" : value.trim().toUpperCase(); + } + + private static String trim(String value) { + return value == null ? "" : value.trim(); + } + + private static final class ParsedBagQr { + private String site; + private String partNo; + private long seqNo; + private long itemNo; + } + + private static final class LoadedNotice { + private TransferNoticeReturnNoticeRow notice; + private TransferNoticeReturnNoticeRow inbound; + private ShopOrderData shop; + } + + private static final class ReadyLine { + private PrintLabelRecord bag; + private BigDecimal qty; + } + + private static final class OutLine { + private String warehouseId; + private String partNo; + private String batchNo; + private String locationId; + private double qty; + } +} diff --git a/src/main/resources/mapper/app/TransferNoticeReturn.xml b/src/main/resources/mapper/app/TransferNoticeReturn.xml new file mode 100644 index 0000000..3b4a5eb --- /dev/null +++ b/src/main/resources/mapper/app/TransferNoticeReturn.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + UPDATE SOOpsTransferHeader + SET Status = N'已取消' + WHERE TransNo = #{transNo,jdbcType=VARCHAR} + AND Site = #{site,jdbcType=VARCHAR} + AND Status IN (N'已入库', N'已录入') + + + + + UPDATE SOOpsTransferDetail + SET ConfirmQty = 0 + WHERE TransNo = #{transNo,jdbcType=VARCHAR} + AND Site = #{site,jdbcType=VARCHAR} + + diff --git a/src/main/resources/static/js/pdaOther/transferNoticeReturnStep1.js b/src/main/resources/static/js/pdaOther/transferNoticeReturnStep1.js new file mode 100644 index 0000000..3f1c635 --- /dev/null +++ b/src/main/resources/static/js/pdaOther/transferNoticeReturnStep1.js @@ -0,0 +1,137 @@ +/** + * PDA 扫入库通知单退库 - 步骤1 - rqrq + */ +var titleName = $("#current_titleName").val(); + +var currentData = null; + +var COOKIE_ORDER = "noticeRetPdaOrder"; +var COOKIE_TABLE = "noticeRetPdaTable"; + +function clearOrderCookie () { + $.cookie(COOKIE_ORDER, "", { expires: -1, path: "/" }); + $.cookie(COOKIE_ORDER, "", { expires: -1 }); +} + +function clearTableCookie () { + $.cookie(COOKIE_TABLE, "", { expires: -1, path: "/" }); + $.cookie(COOKIE_TABLE, "", { expires: -1 }); +} + +function clearNoticeReturnCookies () { + clearOrderCookie(); + clearTableCookie(); +} + +function readOrderCookieSafe () { + var saved = $.cookie(COOKIE_ORDER); + if (saved == null || saved === "") { + return null; + } + try { + return JSON.parse(saved); + } catch (e) { + clearOrderCookie(); + return null; + } +} + +$(function () { + if (titleName != null && titleName !== "") { + $("#titleName").text(titleName); + } else { + window.location.href = "/login"; + } + currentData = readOrderCookieSafe(); + if (currentData != null) { + initVal(); + clearOrderCookie(); + } + $("#orderNo_search").focus(); +}); + +$("#orderNo_search").bind("keydown", function (event) { + if (event.keyCode === 13) { + getOrderNoData(); + } +}); + +function getOrderNoData () { + var raw = ($("#orderNo_search").val() || "").trim(); + if (raw === "") { + layer.msg("请输入入库通知单号!"); + return false; + } + $.ajax({ + url: "/pda/transferNoticeReturn/resolveNotice", + contentType: "application/json", + type: "POST", + data: JSON.stringify({ transFerNo: raw }), + dataType: "JSON", + beforeSend: function (request) { + request.setRequestHeader("token", $.cookie("token")); + }, + success: function (data) { + if (data.code === 0) { + if (data.row && data.row.orderNo != null && data.row.orderNo !== "") { + currentData = data.row; + if (currentData.status === "已计划" || currentData.status === "已取消" || currentData.status === "已关闭") { + currentData = null; + layer.msg("该生产订单状态不允许生产退库,请检查生产订单状态"); + return false; + } + clearTableCookie(); + initVal(); + } else { + layer.msg("入库通知单号错误!"); + } + } else { + layer.msg(data.msg || "查询失败"); + } + }, + error: function (data) { + showHttpError(data); + } + }); +} + +function initVal () { + $("#transFerNo").val(currentData.transFerNo); + $("#site").val(currentData.site); + $("#orderNo").val(currentData.orderNo); + $("#seqNo").val(currentData.seqNo); + $("#partNo").val(currentData.partNo); + $("#partDescription").val(currentData.partDescription); + $("#status").val(currentData.status); + $("#confirmQty").val(currentData.confirmQty); + $("#noticeBatchNo").val(currentData.noticeBatchNo); +} + +function pageJump () { + if (currentData == null || !currentData.transFerNo) { + layer.msg("请先扫描入库通知单!"); + return false; + } + $.cookie(COOKIE_ORDER, JSON.stringify(currentData), { path: "/" }); + var menuId = $("#menuId").val(); + var superiorName = $("#current_titleName").val(); + window.location.href = "/pdaOther/transferNoticeReturnStep2?menuId=" + encodeURIComponent(menuId || "") + "&titleName=" + encodeURIComponent(superiorName || ""); +} + +function pdaBaseJump () { + clearNoticeReturnCookies(); + window.location.href = "/pda/pdaBase"; +} + +function showHttpError (data) { + var responseText = data.responseText; + var json_str = JSON.parse(responseText); + var status = json_str.status; + var message = json_str.message; + if (403 === status) { + layer.alert(message, function () { + window.location.href = "/login"; + }); + } + layer.closeAll("loading"); +} diff --git a/src/main/resources/static/js/pdaOther/transferNoticeReturnStep2.js b/src/main/resources/static/js/pdaOther/transferNoticeReturnStep2.js new file mode 100644 index 0000000..2fef67f --- /dev/null +++ b/src/main/resources/static/js/pdaOther/transferNoticeReturnStep2.js @@ -0,0 +1,279 @@ +/** + * PDA 扫入库通知单退库 - 步骤2 - rqrq + */ +var titleName = $("#current_titleName").val(); + +var currentData = null; + +var tableList = []; + +var confirmSubmitting = false; + +var COOKIE_ORDER = "noticeRetPdaOrder"; +var COOKIE_TABLE = "noticeRetPdaTable"; + +function clearOrderCookie () { + $.cookie(COOKIE_ORDER, "", { expires: -1, path: "/" }); + $.cookie(COOKIE_ORDER, "", { expires: -1 }); +} + +function clearTableCookie () { + $.cookie(COOKIE_TABLE, "", { expires: -1, path: "/" }); + $.cookie(COOKIE_TABLE, "", { expires: -1 }); +} + +function clearNoticeReturnCookies () { + clearOrderCookie(); + clearTableCookie(); +} + +function readJsonCookieSafe (cookieName, clearFn) { + var raw = $.cookie(cookieName); + if (raw == null || raw === "") { + return null; + } + try { + return JSON.parse(raw); + } catch (e) { + if (clearFn) { + clearFn(); + } + return null; + } +} + +function bagLabelDupKey (seqNo, itemNo) { + return String(seqNo) + "_" + String(itemNo); +} + +function showCheckMessage (msg) { + if (msg && msg.indexOf("袋贴批次错误") === 0) { + layer.alert(msg); + return; + } + layer.msg(msg || "校验失败"); +} + +$(function () { + if (titleName != null && titleName !== "") { + $("#titleName").text(titleName); + } else { + window.location.href = "/login"; + } + var orderCookie = readJsonCookieSafe(COOKIE_ORDER, clearOrderCookie); + if (orderCookie != null && orderCookie.transFerNo) { + currentData = orderCookie; + } else { + clearNoticeReturnCookies(); + layer.msg("请先扫描入库通知单"); + goStep1(); + return; + } + var list = readJsonCookieSafe(COOKIE_TABLE, clearTableCookie); + if (Array.isArray(list)) { + tableList = list; + changeTable(); + } + $("#partNo_search").focus(); +}); + +function changeTable () { + var str = ""; + if (tableList.length > 0) { + $("#wareHouse").val(tableList[0].warehouseId + "-" + (tableList[0].wareHouseName || "")); + } else { + $("#wareHouse").val(""); + } + for (var i = 0; i < tableList.length; i++) { + str += "" + + '' + tableList[i].partNo + "" + + '' + tableList[i].qtyIssue + "" + + '' + tableList[i].batchNo + "" + + '' + tableList[i].locationId + "" + + ""; + } + $("#issue_table").html("").append(str); + $.cookie(COOKIE_TABLE, JSON.stringify(tableList), { path: "/" }); +} + +$("#partNo_search").bind("keydown", function (event) { + if (event.keyCode === 13) { + queryPart(); + } +}); + +function appendRowFromValidated (row, labelDupKey) { + if (!row || !row.partNo || row.labelRecordId == null) { + layer.msg("校验返回数据无效"); + return; + } + if (labelDupKey != null && tableList.some(function (item) { return item.labelDupKey === labelDupKey; })) { + layer.msg("该袋装标签已在本单扫描过,请勿重复扫码"); + return; + } + if (tableList.some(function (item) { return item.labelRecordId === row.labelRecordId; })) { + layer.msg("该袋装标签已在本单扫描过,请勿重复扫码"); + return; + } + if (tableList.length > 0 && row.warehouseId !== tableList[0].warehouseId) { + layer.msg("仓库编码与首张标签不一致!"); + return; + } + tableList.push({ + partNo: row.partNo, + qtyIssue: String(row.qtyIssue), + batchNo: row.batchNo, + locationId: row.locationId, + partDescSpec: row.partDescSpec != null ? row.partDescSpec : "", + umid: row.umid != null ? row.umid : "", + warehouseId: row.warehouseId, + wareHouseName: row.wareHouseName != null ? row.wareHouseName : "", + qtyReady: row.qtyReady != null ? row.qtyReady : "", + itemNo: row.itemNo != null ? row.itemNo : "", + labelRecordId: row.labelRecordId, + labelDupKey: labelDupKey + }); + changeTable(); + $("#partNo_search").val("").focus(); +} + +function queryPart () { + var raw = $("#partNo_search").val(); + if (raw == null || raw === "") { + layer.msg("请扫描袋装标签!"); + return false; + } + var segs = raw.split(";").map(function (item) { return (item || "").trim(); }); + if (segs.length !== 5 && segs.length !== 6) { + layer.msg("袋装标签格式错误!"); + return false; + } + if (currentData == null || !currentData.transFerNo) { + layer.msg("缺少入库通知单,请返回上一步"); + return false; + } + var seqNoParsed = Number(segs[3]); + var itemNoParsed = Number(segs[4]); + if (!isFinite(seqNoParsed) || !isFinite(itemNoParsed) || seqNoParsed <= 0 || itemNoParsed <= 0) { + layer.msg("袋装标签序号或项次无效"); + return false; + } + var dupKey = bagLabelDupKey(Math.floor(seqNoParsed), Math.floor(itemNoParsed)); + if (tableList.some(function (item) { return item.labelDupKey === dupKey; })) { + layer.msg("该袋装标签已在本单扫描过,请勿重复扫码"); + return false; + } + $.ajax({ + url: "/pda/transferNoticeReturn/validateBagLine", + contentType: "application/json", + type: "POST", + data: JSON.stringify({ + qrContent: raw, + transFerNo: currentData.transFerNo + }), + dataType: "JSON", + beforeSend: function (request) { + request.setRequestHeader("token", $.cookie("token")); + }, + success: function (data) { + if (data.code === 0) { + appendRowFromValidated(data.row, dupKey); + } else { + showCheckMessage(data.msg); + } + }, + error: function (data) { + showHttpError(data); + } + }); +} + +function confirmReturn () { + if (confirmSubmitting) { + return false; + } + if (tableList.length === 0) { + layer.msg("请扫描袋装标签并添加退库行!"); + return false; + } + var body = { + transFerNo: currentData.transFerNo, + operatorUserName: $("#current_username").val(), + lines: tableList.map(function (item) { + return { + labelRecordId: item.labelRecordId, + partNo: item.partNo, + qtyIssue: String(item.qtyIssue), + batchNo: item.batchNo, + locationId: item.locationId, + partDescSpec: item.partDescSpec, + umid: item.umid, + warehouseId: item.warehouseId, + wareHouseName: item.wareHouseName, + itemNo: item.itemNo, + qtyReady: item.qtyReady + }; + }) + }; + confirmSubmitting = true; + $.ajax({ + url: "/pda/transferNoticeReturn/confirm", + contentType: "application/json", + type: "POST", + data: JSON.stringify(body), + dataType: "JSON", + beforeSend: function (request) { + request.setRequestHeader("token", $.cookie("token")); + }, + success: function (data) { + if (data.code === 0) { + layer.msg(data.msg || "操作成功!"); + clearNoticeReturnCookies(); + tableList = []; + currentData = null; + changeTable(); + setTimeout(function () { + goStep1(); + }, 600); + } else { + showCheckMessage(data.msg); + } + }, + error: function (data) { + showHttpError(data); + }, + complete: function () { + confirmSubmitting = false; + } + }); +} + +function superiorJump () { + $.cookie(COOKIE_TABLE, JSON.stringify(tableList), { path: "/" }); + $.cookie(COOKIE_ORDER, JSON.stringify(currentData), { path: "/" }); + goStep1(); +} + +function pdaBaseJump () { + clearNoticeReturnCookies(); + window.location.href = "/pda/pdaBase"; +} + +function goStep1 () { + var menuId = $("#menuId").val(); + var superiorName = $("#current_titleName").val(); + window.location.href = "/pdaOther/productionBagReturnStep1?menuId=" + encodeURIComponent(menuId || "") + "&titleName=" + encodeURIComponent(superiorName || ""); +} + +function showHttpError (data) { + var responseText = data.responseText; + var json_str = JSON.parse(responseText); + var status = json_str.status; + var message = json_str.message; + if (403 === status) { + layer.alert(message, function () { + window.location.href = "/login"; + }); + } + layer.closeAll("loading"); +} diff --git a/src/main/resources/templates/pdaOther/transferNoticeReturnStep1.ftl b/src/main/resources/templates/pdaOther/transferNoticeReturnStep1.ftl new file mode 100644 index 0000000..7f8d07a --- /dev/null +++ b/src/main/resources/templates/pdaOther/transferNoticeReturnStep1.ftl @@ -0,0 +1,152 @@ + + + + + + + + + + ${project_title!"赫艾Pda"} + + + + + + + + + + +
+
+
+
+ + +
+
+

+
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + + + + diff --git a/src/main/resources/templates/pdaOther/transferNoticeReturnStep2.ftl b/src/main/resources/templates/pdaOther/transferNoticeReturnStep2.ftl new file mode 100644 index 0000000..d38cf55 --- /dev/null +++ b/src/main/resources/templates/pdaOther/transferNoticeReturnStep2.ftl @@ -0,0 +1,120 @@ + + + + + + + + + + ${project_title!"赫艾Pda"} + + + + + + + + + + +
+
+
+
+ + +
+
+

+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+
+
+
+ + + + + + + + + +
物料编码退库数量批号库位
+
+
+ + + +
+
+
+
+
+ +
+ + +
+ +
+ + + + + + + + +