package com.zy.asrs.controller; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.baomidou.mybatisplus.plugins.Page; import com.core.common.Cools; import com.core.common.R; import com.core.annotations.ManagerAuth; import com.zy.asrs.entity.MaterialWwOut; import com.zy.asrs.service.MaterialWwOutService; import com.zy.common.web.BaseController; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import com.core.common.DateUtils; import java.lang.reflect.Field; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController public class MaterialWwOutController extends BaseController { @Autowired private MaterialWwOutService materialWwOutService; @RequestMapping(value = "/materialWwOut/{id}/auth") @ManagerAuth public R get(@PathVariable("id") String id) { return R.ok(materialWwOutService.selectById(String.valueOf(id))); } @RequestMapping(value = "/materialWwOut/list/auth") @ManagerAuth public R list(@RequestParam(defaultValue = "1") Integer curr, @RequestParam(defaultValue = "1000") Integer limit, @RequestParam(required = false) String orderByField, @RequestParam(required = false) String orderByType, @RequestParam(required = false) String condition, @RequestParam(required = false) Boolean pdaQuery, @RequestParam Map param) { EntityWrapper wrapper = new EntityWrapper<>(); excludeTrash(param); // 移除pdaQuery参数,因为它不是数据库字段,只是控制参数 param.remove("pdaQuery"); convert(param, wrapper); allLike(MaterialWwOut.class, param.keySet(), wrapper, condition); // 参考其他出库模块,PDA出库查询时过滤掉已全部出库的物料(只显示还有剩余数量的) // 通过 pdaQuery 参数判断是否是PDA出库查询 if (pdaQuery != null && pdaQuery) { // PDA出库查询:只显示剩余数量大于0的记录 wrapper.gt("remain_qty", 0); } if (!Cools.isEmpty(orderByField)) { wrapper.orderBy(humpToLine(orderByField), "asc".equals(orderByType)); } return R.ok(materialWwOutService.selectPage(new Page<>(curr, limit), wrapper)); } @RequestMapping(value = "/materialWwOut/batchSave/auth", method = RequestMethod.POST) @ManagerAuth public R batchSave(@RequestBody List> dataList) { if (Cools.isEmpty(dataList)) { return R.error("数据不能为空"); } int successCount = 0; int updateCount = 0; for (Map data : dataList) { try { // 检查是否已存在(根据recordId和invCode唯一标识,如果recordId为空则使用id) String recordId = data.get("recordId") != null ? String.valueOf(data.get("recordId")) : null; // 如果recordId为空,尝试使用id字段 if (recordId == null || recordId.isEmpty() || "null".equals(recordId)) { if (data.get("id") != null) { recordId = String.valueOf(data.get("id")); } } String invCode = data.get("invCode") != null ? String.valueOf(data.get("invCode")) : null; MaterialWwOut existRecord = null; if (recordId != null && !recordId.isEmpty() && !"null".equals(recordId) && invCode != null) { existRecord = materialWwOutService.selectOne(new EntityWrapper() .eq("record_id", recordId) .eq("inv_code", invCode)); } MaterialWwOut materialWwOut; if (existRecord != null) { // 已存在,更新数据(不覆盖出库相关字段) materialWwOut = existRecord; updateCount++; } else { // 不存在,创建新记录 materialWwOut = new MaterialWwOut(); materialWwOut.setCreateTime(new Date()); // 初始化出库相关字段 materialWwOut.setOutQty(BigDecimal.ZERO); materialWwOut.setRemainQty(data.get("fqty") != null ? new BigDecimal(String.valueOf(data.get("fqty"))) : (data.get("qty") != null ? new BigDecimal(String.valueOf(data.get("qty"))) : BigDecimal.ZERO)); materialWwOut.setIsAllOut(0); successCount++; } // 更新/设置字段 - 确保recordId有值 if (recordId == null || recordId.isEmpty() || "null".equals(recordId)) { // 如果recordId为空,尝试使用id字段 if (data.get("id") != null) { recordId = String.valueOf(data.get("id")); } } materialWwOut.setRecordId(recordId); if (data.get("dateStart") != null && !Cools.isEmpty(String.valueOf(data.get("dateStart")))) { try { String dateStr = String.valueOf(data.get("dateStart")); java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd"); materialWwOut.setDateStart(sdf.parse(dateStr)); } catch (Exception ex) { // 忽略日期解析错误 } } if (data.get("dateEnd") != null && !Cools.isEmpty(String.valueOf(data.get("dateEnd")))) { try { String dateStr = String.valueOf(data.get("dateEnd")); java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd"); materialWwOut.setDateEnd(sdf.parse(dateStr)); } catch (Exception ex) { // 忽略日期解析错误 } } if (data.get("venId") != null) { try { materialWwOut.setVenId(Integer.valueOf(String.valueOf(data.get("venId")))); } catch (Exception e) { // 忽略转换错误 } } materialWwOut.setVenName(data.get("venName") != null ? String.valueOf(data.get("venName")) : null); materialWwOut.setInvCode(invCode); materialWwOut.setInvName(data.get("invName") != null ? String.valueOf(data.get("invName")) : null); materialWwOut.setInvStd(data.get("invStd") != null ? String.valueOf(data.get("invStd")) : null); materialWwOut.setUnit(data.get("unit") != null ? String.valueOf(data.get("unit")) : null); // 数量字段处理(优先使用fqty,如果没有则使用qty) BigDecimal qty = null; if (data.get("fqty") != null) { qty = new BigDecimal(String.valueOf(data.get("fqty"))); materialWwOut.setFqty(qty); } else if (data.get("qty") != null) { qty = new BigDecimal(String.valueOf(data.get("qty"))); materialWwOut.setQty(qty); } if (data.get("qqty") != null) { materialWwOut.setQqty(new BigDecimal(String.valueOf(data.get("qqty")))); } if (data.get("yqty") != null) { materialWwOut.setYqty(new BigDecimal(String.valueOf(data.get("yqty")))); } if (data.get("wqty") != null) { materialWwOut.setWqty(new BigDecimal(String.valueOf(data.get("wqty")))); } // 如果已存在,更新剩余数量(基于原始数量) if (existRecord == null && qty != null) { materialWwOut.setRemainQty(qty); } else if (existRecord != null && qty != null) { // 已存在时,如果数量有变化,重新计算剩余数量 BigDecimal originalQty = existRecord.getFqty() != null ? existRecord.getFqty() : (existRecord.getQty() != null ? existRecord.getQty() : BigDecimal.ZERO); BigDecimal outQty = existRecord.getOutQty() != null ? existRecord.getOutQty() : BigDecimal.ZERO; // 如果新数量与原始数量不同,说明数量更新了,需要重新计算剩余数量 if (qty.compareTo(originalQty) != 0) { // 数量变化,剩余数量 = 新数量 - 已出库数量 materialWwOut.setRemainQty(qty.subtract(outQty)); } else { // 数量没变化,保持原有剩余数量 materialWwOut.setRemainQty(existRecord.getRemainQty()); } } if (data.get("funitid") != null) { try { materialWwOut.setFunitid(Integer.valueOf(String.valueOf(data.get("funitid")))); } catch (Exception e) { // 忽略转换错误 } } if (data.get("fitemid") != null) { try { materialWwOut.setFitemid(Integer.valueOf(String.valueOf(data.get("fitemid")))); } catch (Exception e) { // 忽略转换错误 } } if (data.get("whId") != null) { try { materialWwOut.setWhId(Integer.valueOf(String.valueOf(data.get("whId")))); } catch (Exception e) { // 忽略转换错误 } } materialWwOut.setWhName(data.get("whName") != null ? String.valueOf(data.get("whName")) : null); if (data.get("izSync") != null) { materialWwOut.setIzSync(String.valueOf(data.get("izSync"))); } if (data.get("izPrint") != null) { materialWwOut.setIzPrint(String.valueOf(data.get("izPrint"))); } // 将其他字段存储到ext_data(JSON格式) Map extDataMap = new HashMap<>(); // 已映射到数据库表字段的字段列表(这些字段不需要存储在ext_data中) java.util.Set mappedFields = new java.util.HashSet<>(); mappedFields.add("recordId"); mappedFields.add("dateStart"); mappedFields.add("dateEnd"); mappedFields.add("venId"); mappedFields.add("venName"); mappedFields.add("invCode"); mappedFields.add("invName"); mappedFields.add("invStd"); mappedFields.add("unit"); mappedFields.add("funitid"); mappedFields.add("fitemid"); mappedFields.add("whId"); mappedFields.add("whName"); mappedFields.add("qty"); mappedFields.add("fqty"); mappedFields.add("qqty"); mappedFields.add("yqty"); mappedFields.add("wqty"); mappedFields.add("izSync"); mappedFields.add("izPrint"); // 将所有未映射的字段存储到ext_data中 for (Map.Entry entry : data.entrySet()) { String key = entry.getKey(); if (!mappedFields.contains(key) && entry.getValue() != null) { extDataMap.put(key, entry.getValue()); } } // 始终更新ext_data,即使为空也要存储(用于后续扩展) materialWwOut.setExtData(com.alibaba.fastjson.JSON.toJSONString(extDataMap)); materialWwOut.setSyncTime(new Date()); materialWwOut.setUpdateTime(new Date()); // 保存或更新 if (existRecord != null) { materialWwOutService.updateById(materialWwOut); } else { materialWwOutService.insert(materialWwOut); } } catch (Exception e) { // 记录失败的记录,继续处理下一条 e.printStackTrace(); } } return R.ok("成功保存 " + successCount + " 条新数据,更新 " + updateCount + " 条已存在数据"); } @RequestMapping(value = "/materialWwOut/update/auth") @ManagerAuth public R update(MaterialWwOut materialWwOut) { if (Cools.isEmpty(materialWwOut) || null == materialWwOut.getId()) { return R.error(); } materialWwOut.setUpdateTime(new Date()); materialWwOutService.updateById(materialWwOut); return R.ok(); } @RequestMapping(value = "/materialWwOut/updateOutQty/auth", method = RequestMethod.POST) @ManagerAuth public R updateOutQty(@RequestBody Map param) { Long id = Long.valueOf(String.valueOf(param.get("id"))); BigDecimal addOutQty = new BigDecimal(String.valueOf(param.get("outQty"))); // 本次出库数量 MaterialWwOut materialWwOut = materialWwOutService.selectById(id); if (materialWwOut == null) { return R.error("记录不存在"); } // 累加出库数量 BigDecimal currentOutQty = materialWwOut.getOutQty() != null ? materialWwOut.getOutQty() : BigDecimal.ZERO; BigDecimal newOutQty = currentOutQty.add(addOutQty); materialWwOut.setOutQty(newOutQty); // 计算剩余数量(优先使用fqty,如果没有则使用qty) BigDecimal qty = materialWwOut.getFqty() != null ? materialWwOut.getFqty() : (materialWwOut.getQty() != null ? materialWwOut.getQty() : BigDecimal.ZERO); BigDecimal remainQty = qty.subtract(newOutQty); materialWwOut.setRemainQty(remainQty.compareTo(BigDecimal.ZERO) > 0 ? remainQty : BigDecimal.ZERO); // 判断是否全部出库完成 materialWwOut.setIsAllOut(remainQty.compareTo(BigDecimal.ZERO) <= 0 ? 1 : 0); materialWwOut.setUpdateTime(new Date()); materialWwOutService.updateById(materialWwOut); return R.ok(); } @RequestMapping(value = "/materialWwOut/checkSyncStatus/auth") @ManagerAuth public R checkSyncStatus(@RequestParam String recordId, @RequestParam(required = false) String invCode) { EntityWrapper wrapper = new EntityWrapper<>(); wrapper.eq("record_id", recordId); if (!Cools.isEmpty(invCode)) { wrapper.eq("inv_code", invCode); } List list = materialWwOutService.selectList(wrapper); Map result = new HashMap<>(); if (Cools.isEmpty(list)) { result.put("synced", false); result.put("allOut", false); result.put("message", "该记录ID未同步到WMS"); return R.ok(result); } // 检查是否全部出库完成 boolean allOut = true; List> notOutList = new ArrayList<>(); for (MaterialWwOut mwo : list) { if (mwo.getIsAllOut() == null || mwo.getIsAllOut() != 1) { allOut = false; Map notOutItem = new HashMap<>(); notOutItem.put("invCode", mwo.getInvCode()); notOutItem.put("invName", mwo.getInvName()); notOutItem.put("remainQty", mwo.getRemainQty()); notOutList.add(notOutItem); } } result.put("synced", true); result.put("allOut", allOut); result.put("records", list); if (!allOut && !notOutList.isEmpty()) { result.put("notOutList", notOutList); result.put("message", "部分物料未全部出库完成"); } else if (allOut) { result.put("message", "全部物料已出库完成"); } return R.ok(result); } private void convert(Map map, EntityWrapper wrapper) { for (Map.Entry entry : map.entrySet()) { String fieldName = entry.getKey(); String columnName = getColumnName(MaterialWwOut.class, fieldName); String val = String.valueOf(entry.getValue()); if (val.contains(RANGE_TIME_LINK)) { String[] dates = val.split(RANGE_TIME_LINK); wrapper.ge(columnName, DateUtils.convert(dates[0])); wrapper.le(columnName, DateUtils.convert(dates[1])); } else { wrapper.like(columnName, val); } } } /** * 根据实体类字段名获取数据库列名 * @param cls 实体类 * @param fieldName Java字段名(驼峰命名) * @return 数据库列名(下划线命名) */ private String getColumnName(Class cls, String fieldName) { for (Field field : Cools.getAllFields(cls)) { if (field.getName().equals(fieldName)) { if (field.isAnnotationPresent(TableField.class)) { TableField annotation = field.getAnnotation(TableField.class); if (!annotation.exist()) { continue; } String column = annotation.value(); if (!Cools.isEmpty(column)) { return column; } } // 如果没有@TableField注解,使用humpToLine转换 return humpToLine(fieldName); } } // 如果找不到字段,使用humpToLine转换 return humpToLine(fieldName); } @RequestMapping(value = "/materialWwOut/delete/auth") @ManagerAuth public R delete(@RequestParam String param) { com.alibaba.fastjson.JSONArray jsonArray = com.alibaba.fastjson.JSONArray.parseArray(param); List list = jsonArray.toJavaList(MaterialWwOut.class); if (Cools.isEmpty(list)) { return R.error("请选择要删除的数据"); } for (MaterialWwOut entity : list) { materialWwOutService.deleteById(entity.getId()); } return R.ok(); } }