10 changed files with 1068 additions and 1 deletions
-
5src/main/java/com/gaotao/modules/autoWareHourceHaian/entity/vo/HaiAnSOIssueNotifyOrderMaterialListDetail.java
-
65src/main/java/com/gaotao/modules/warehouse/controller/CrossSiteHuTransferController.java
-
51src/main/java/com/gaotao/modules/warehouse/entity/CrossSiteHuTransferData.java
-
55src/main/java/com/gaotao/modules/warehouse/entity/CrossSiteHuTransferRequest.java
-
57src/main/java/com/gaotao/modules/warehouse/entity/CrossSiteHuTransferResult.java
-
27src/main/java/com/gaotao/modules/warehouse/entity/SiteSubOptionData.java
-
88src/main/java/com/gaotao/modules/warehouse/mapper/CrossSiteHuTransferMapper.java
-
41src/main/java/com/gaotao/modules/warehouse/service/CrossSiteHuTransferService.java
-
495src/main/java/com/gaotao/modules/warehouse/service/impl/CrossSiteHuTransferServiceImpl.java
-
185src/main/resources/mapper/warehouse/CrossSiteHuTransferMapper.xml
@ -0,0 +1,65 @@ |
|||
package com.gaotao.modules.warehouse.controller; |
|||
|
|||
import com.gaotao.common.utils.PageUtils; |
|||
import com.gaotao.common.utils.R; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferData; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferRequest; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferResult; |
|||
import com.gaotao.modules.warehouse.entity.SiteSubOptionData; |
|||
import com.gaotao.modules.warehouse.service.CrossSiteHuTransferService; |
|||
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; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 跨小site调拨控制器:只负责收参、调用Service、返回统一R结构 - rqrq |
|||
* @date 2026/09/04 |
|||
*/ |
|||
@RestController |
|||
@RequestMapping("warehouse/crossSiteHuTransfer") |
|||
public class CrossSiteHuTransferController { |
|||
|
|||
@Autowired |
|||
private CrossSiteHuTransferService crossSiteHuTransferService; |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 分页查询可跨小site调拨标签,入参缺失site或无查询条件时由Service抛出业务异常 - rqrq |
|||
* @param query 查询对象,site=登录大site,searchSite=可选小site |
|||
* @return page 分页结果 |
|||
*/ |
|||
@PostMapping("/searchHandlingUnitList") |
|||
public R searchHandlingUnitList(@RequestBody CrossSiteHuTransferData query) { |
|||
PageUtils page = crossSiteHuTransferService.searchHandlingUnitList(query); |
|||
return R.ok().put("page", page); |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 查询目标小site下拉,排除当前选中标签的来源site - rqrq |
|||
* @param query site=登录大site,excludeSite=来源小site |
|||
* @return rows 目标小site列表 |
|||
*/ |
|||
@PostMapping("/listTargetSubSites") |
|||
public R listTargetSubSites(@RequestBody CrossSiteHuTransferData query) { |
|||
List<SiteSubOptionData> rows = crossSiteHuTransferService.listTargetSubSites(query); |
|||
return R.ok().put("rows", rows); |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 提交跨小site调拨:二次校验后写STO/STI并改标签site - rqrq |
|||
* @param request 登录大site、来源/目标小site、操作人、选中标签 |
|||
* @return row 处理结果(含STO/STI事务号) |
|||
*/ |
|||
@PostMapping("/transferHuSite") |
|||
public R transferHuSite(@RequestBody CrossSiteHuTransferRequest request) { |
|||
CrossSiteHuTransferResult result = crossSiteHuTransferService.transferHuSite(request); |
|||
return R.ok().put("row", result); |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
package com.gaotao.modules.warehouse.entity; |
|||
|
|||
import com.gaotao.modules.warehouse.entity.vo.HandlingUnitQueryVo; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
import org.apache.ibatis.type.Alias; |
|||
|
|||
/** |
|||
* @Description 跨小site调拨查询业务实体 - 用于分页查询可调拨标签 - rqrq |
|||
* |
|||
* <p><b>继承关系:</b>继承 HandlingUnitQueryVo,复用标签查询字段与分页参数</p> |
|||
* |
|||
* <p><b>用途:</b></p> |
|||
* <ul> |
|||
* <li>跨小site调拨页查询入参/出参</li> |
|||
* <li>site 表示当前登录大site,用于 site_sub 反查允许的小site集合</li> |
|||
* <li>searchSite 表示用户输入的标签小site过滤条件,对应 handling_unit.site</li> |
|||
* </ul> |
|||
* |
|||
* <p><b>常用查询逻辑:</b></p> |
|||
* <pre> |
|||
* WHERE h.in_stock_flag = 'Y' |
|||
* AND h.reserve_flag = 'N' |
|||
* AND h.site IN (SELECT ss.subsiteid FROM site_sub ss WHERE ss.siteid = #{query.site}) |
|||
* AND h.site = #{query.searchSite} -- 仅当用户填写了site条件 |
|||
* </pre> |
|||
* |
|||
* @author rqrq |
|||
* @date 2026/09/04 |
|||
*/ |
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@Alias("CrossSiteHuTransferData") |
|||
public class CrossSiteHuTransferData extends HandlingUnitQueryVo { |
|||
|
|||
/** |
|||
* 查询条件 - 标签小site(精确查询,对应 handling_unit.site) |
|||
* <p>SQL示例:AND h.site = #{query.searchSite}</p> |
|||
* <p>是否落库:否,仅查询入参;赋值时机:前端筛选区输入;消费方:查询SQL</p> |
|||
* - rqrq |
|||
*/ |
|||
private String searchSite; |
|||
|
|||
/** |
|||
* 查询条件 - 需要排除的小site(目标站点下拉用,对应当前选中标签的site) |
|||
* <p>SQL示例:AND ss.subsiteid <> #{query.excludeSite}</p> |
|||
* <p>是否落库:否,仅弹窗查询入参;赋值时机:点击跨site调拨后;消费方:目标site下拉SQL</p> |
|||
* - rqrq |
|||
*/ |
|||
private String excludeSite; |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
package com.gaotao.modules.warehouse.entity; |
|||
|
|||
import com.gaotao.modules.warehouse.entity.vo.HandlingUnitVo; |
|||
import lombok.Data; |
|||
import org.apache.ibatis.type.Alias; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @Description 跨小site调拨提交请求 - 承载登录大site、来源/目标小site和选中标签 - rqrq |
|||
* |
|||
* <p><b>用途:</b>前端确认目标site后提交调拨。后台二次校验在库/未预留后,先按来源小site写STO出库,再按目标小site写STI入库,最后改 handling_unit.site。调拨外部接口后续接入。</p> |
|||
* |
|||
* @author rqrq |
|||
* @date 2026/09/04 |
|||
*/ |
|||
@Data |
|||
@Alias("CrossSiteHuTransferRequest") |
|||
public class CrossSiteHuTransferRequest { |
|||
|
|||
/** |
|||
* 当前登录大site,来源前端 this.$store.state.user.site,用于校验来源/目标小site都属于该大site |
|||
* <p>是否落库:否;赋值时机:前端提交;消费方:后端校验 site_sub 映射</p> |
|||
* - rqrq |
|||
*/ |
|||
private String site; |
|||
|
|||
/** |
|||
* 来源小site,必须等于选中标签的 handling_unit.site,且整批只能有一个来源 |
|||
* <p>是否落库:否;赋值时机:前端根据选中行汇总;消费方:更新WHERE条件</p> |
|||
* - rqrq |
|||
*/ |
|||
private String fromSite; |
|||
|
|||
/** |
|||
* 目标小site,必须来自 site_sub,且不能等于 fromSite |
|||
* <p>是否落库:是,写入 handling_unit.site;出库单site用 fromSite,入库单site用 toSite</p> |
|||
* - rqrq |
|||
*/ |
|||
private String toSite; |
|||
|
|||
/** |
|||
* 操作人,来源前端登录用户名,写入 modified_by |
|||
* <p>是否落库:是,写入 handling_unit.modified_by</p> |
|||
* - rqrq |
|||
*/ |
|||
private String createdBy; |
|||
|
|||
/** |
|||
* 选中的标签列表,至少1条;仅使用 site+unitId 作为更新主键 |
|||
* <p>是否落库:否,仅作为待处理清单</p> |
|||
* - rqrq |
|||
*/ |
|||
private List<HandlingUnitVo> selectedItems; |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
package com.gaotao.modules.warehouse.entity; |
|||
|
|||
import lombok.Data; |
|||
import org.apache.ibatis.type.Alias; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @Description 跨小site调拨处理结果 - 供前端弹窗展示成功/失败明细 - rqrq |
|||
* |
|||
* <p><b>数据来源:</b>CrossSiteHuTransferServiceImpl.transferHuSite 汇总</p> |
|||
* |
|||
* @author rqrq |
|||
* @date 2026/09/04 |
|||
*/ |
|||
@Data |
|||
@Alias("CrossSiteHuTransferResult") |
|||
public class CrossSiteHuTransferResult { |
|||
|
|||
/** |
|||
* 成功数量,来源本次实际更新 handling_unit 的条数 - rqrq |
|||
*/ |
|||
private int successCount; |
|||
|
|||
/** |
|||
* 失败数量,来源冲突校验或更新影响行数为0的标签数 - rqrq |
|||
*/ |
|||
private int failCount; |
|||
|
|||
/** |
|||
* 失败标签号列表,前端用于展示失败序列号 - rqrq |
|||
*/ |
|||
private List<String> failedUnitIds = new ArrayList<>(); |
|||
|
|||
/** |
|||
* 失败原因列表,与 failedUnitIds 顺序对应,前端展示第一条即可定位 - rqrq |
|||
*/ |
|||
private List<String> failedReasons = new ArrayList<>(); |
|||
|
|||
/** |
|||
* 处理结果摘要,前端结果弹窗标题补充说明 - rqrq |
|||
*/ |
|||
private String message; |
|||
|
|||
/** |
|||
* 出库事务号,来源登录大site的 transNoControl(STO),写入 trans_header.trans_no;前端结果弹窗回显 - rqrq |
|||
* <p>是否落库:是,对应 STO 出库单(site=来源小site);赋值时机:校验通过后生成;消费方:前端结果展示、后续调拨接口</p> |
|||
*/ |
|||
private String stoTransNo; |
|||
|
|||
/** |
|||
* 入库事务号,来源登录大site的 transNoControl(STI),写入 trans_header.trans_no;前端结果弹窗回显 - rqrq |
|||
* <p>是否落库:是,对应 STI 入库单(site=目标小site);赋值时机:校验通过后生成;消费方:前端结果展示、后续调拨接口</p> |
|||
*/ |
|||
private String stiTransNo; |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
package com.gaotao.modules.warehouse.entity; |
|||
|
|||
import lombok.Data; |
|||
import org.apache.ibatis.type.Alias; |
|||
|
|||
/** |
|||
* @Description 跨小site调拨目标站点下拉结果 - 映射 site_sub 表 - rqrq |
|||
* |
|||
* <p><b>数据来源:</b>site_sub.siteid / site_sub.subsiteid</p> |
|||
* |
|||
* @author rqrq |
|||
* @date 2026/09/04 |
|||
*/ |
|||
@Data |
|||
@Alias("SiteSubOptionData") |
|||
public class SiteSubOptionData { |
|||
|
|||
/** |
|||
* 大site编码,来源 site_sub.siteid,对应当前登录工厂 - rqrq |
|||
*/ |
|||
private String siteId; |
|||
|
|||
/** |
|||
* 小site编码,来源 site_sub.subsiteid,前端下拉展示并作为调拨目标 - rqrq |
|||
*/ |
|||
private String subSiteId; |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
package com.gaotao.modules.warehouse.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.metadata.IPage; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.gaotao.modules.handlingunit.entity.HandlingUnit; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferData; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferRequest; |
|||
import com.gaotao.modules.warehouse.entity.SiteSubOptionData; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
import org.apache.ibatis.annotations.Param; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @Description 跨小site调拨数据访问层,负责可调拨标签查询、小site清单和site改写 - rqrq |
|||
* |
|||
* @author rqrq |
|||
* @date 2026/09/04 |
|||
*/ |
|||
@Mapper |
|||
public interface CrossSiteHuTransferMapper { |
|||
|
|||
/** |
|||
* @Description 分页查询可跨小site调拨的在库未预留标签 - rqrq |
|||
* @param page 分页对象 |
|||
* @param query 查询条件:site=登录大site,searchSite=可选小site |
|||
* @return 标签分页结果 |
|||
*/ |
|||
IPage<CrossSiteHuTransferData> searchHandlingUnitList(Page<CrossSiteHuTransferData> page, @Param("query") CrossSiteHuTransferData query); |
|||
|
|||
/** |
|||
* @Description 按登录大site查询可选小site,排除当前标签来源site - rqrq |
|||
* @param query site=登录大site,excludeSite=当前标签site |
|||
* @return 小site列表 |
|||
*/ |
|||
List<SiteSubOptionData> listTargetSubSites(@Param("query") CrossSiteHuTransferData query); |
|||
|
|||
/** |
|||
* @Description 校验小site是否属于当前登录大site的 site_sub 映射 - rqrq |
|||
* @param site 登录大site |
|||
* @param subSite 待校验小site |
|||
* @return 命中数量,0表示映射不存在 |
|||
*/ |
|||
int countSiteSubMapping(@Param("site") String site, @Param("subSite") String subSite); |
|||
|
|||
/** |
|||
* @Description 按来源小site+标签号加锁查询待调拨标签,供二次校验预留/在库状态 - rqrq |
|||
* @param fromSite 来源小site,对应 handling_unit.site |
|||
* @param unitIds 待调拨标签号 |
|||
* @return 当前库内标签清单;查不到的标签表示已被删除或site已变化 |
|||
*/ |
|||
List<HandlingUnit> listTransferHandlingUnits(@Param("fromSite") String fromSite, @Param("unitIds") List<String> unitIds); |
|||
|
|||
/** |
|||
* @Description 查询目标小site下已存在的同号标签,避免联合主键冲突 - rqrq |
|||
* @param toSite 目标小site |
|||
* @param unitIds 待调拨标签号 |
|||
* @return 已存在的标签号 |
|||
*/ |
|||
List<String> listConflictUnitIds(@Param("toSite") String toSite, @Param("unitIds") List<String> unitIds); |
|||
|
|||
/** |
|||
* @Description 将符合在库未预留条件的标签site改写到目标小site - rqrq |
|||
* @param request 含 fromSite/toSite/createdBy |
|||
* @param unitIds 待更新标签号 |
|||
* @return 实际更新行数 |
|||
*/ |
|||
int updateHandlingUnitSite(@Param("request") CrossSiteHuTransferRequest request, @Param("unitIds") List<String> unitIds); |
|||
|
|||
/** |
|||
* @Description 查询海安托盘明细中是否存在本次调拨标签,serial_no对应handling_unit.unit_id - rqrq |
|||
* @param site 登录大site,对应 haian_pallet_detail.site |
|||
* @param unitIds 待调拨标签号 |
|||
* @return 已存在明细的条码号;空列表表示这些标签不在海安托盘上 |
|||
*/ |
|||
List<String> listHaiAnPalletDetailSerialNos(@Param("site") String site, @Param("unitIds") List<String> unitIds); |
|||
|
|||
/** |
|||
* @Description 将海安托盘明细的sub_site改到目标小site,与handling_unit.site保持一致 - rqrq |
|||
* @param request 含 toSite |
|||
* @param site 登录大site,对应 haian_pallet_detail.site |
|||
* @param unitIds 已确认存在明细的条码号 |
|||
* @return 实际更新行数 |
|||
*/ |
|||
int updateHaiAnPalletDetailSubSite(@Param("request") CrossSiteHuTransferRequest request, |
|||
@Param("site") String site, |
|||
@Param("unitIds") List<String> unitIds); |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
package com.gaotao.modules.warehouse.service; |
|||
|
|||
import com.gaotao.common.utils.PageUtils; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferData; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferRequest; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferResult; |
|||
import com.gaotao.modules.warehouse.entity.SiteSubOptionData; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 跨小site调拨业务接口:查询可调拨标签、目标site下拉、校验后写STO/STI并改标签site - rqrq |
|||
* @date 2026/09/04 |
|||
*/ |
|||
public interface CrossSiteHuTransferService { |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 分页查询可跨小site调拨的在库未预留标签 - rqrq |
|||
* @param query site=登录大site,searchSite=可选小site过滤;必须至少有一个业务查询条件 |
|||
* @return page 分页结果,供前端表格展示 |
|||
*/ |
|||
PageUtils searchHandlingUnitList(CrossSiteHuTransferData query); |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 按登录大site查询可选目标小site,排除当前标签来源site - rqrq |
|||
* @param query site=登录大site,excludeSite=选中标签的来源小site |
|||
* @return 目标小site下拉列表 |
|||
*/ |
|||
List<SiteSubOptionData> listTargetSubSites(CrossSiteHuTransferData query); |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 二次校验预留/在库后生成STO出库、STI入库,再改写标签site;调拨外部接口当前留空 - rqrq |
|||
* @param request 登录大site、来源/目标小site、操作人、选中标签 |
|||
* @return 成功数量、出库/入库事务号 |
|||
*/ |
|||
CrossSiteHuTransferResult transferHuSite(CrossSiteHuTransferRequest request); |
|||
} |
|||
@ -0,0 +1,495 @@ |
|||
package com.gaotao.modules.warehouse.service.impl; |
|||
|
|||
import com.baomidou.mybatisplus.core.metadata.IPage; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.gaotao.common.utils.PageUtils; |
|||
import com.gaotao.modules.handlingunit.entity.HandlingUnit; |
|||
import com.gaotao.modules.sys.entity.SysUserEntity; |
|||
import com.gaotao.modules.sys.service.SysUserService; |
|||
import com.gaotao.modules.trans.entity.TransDetail; |
|||
import com.gaotao.modules.trans.entity.TransDetailSub; |
|||
import com.gaotao.modules.trans.entity.TransHeader; |
|||
import com.gaotao.modules.trans.entity.TransNoControl; |
|||
import com.gaotao.modules.trans.service.TransDetailService; |
|||
import com.gaotao.modules.trans.service.TransDetailSubService; |
|||
import com.gaotao.modules.trans.service.TransHeaderService; |
|||
import com.gaotao.modules.trans.service.TransNoControlService; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferData; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferRequest; |
|||
import com.gaotao.modules.warehouse.entity.CrossSiteHuTransferResult; |
|||
import com.gaotao.modules.warehouse.entity.SiteSubOptionData; |
|||
import com.gaotao.modules.warehouse.entity.vo.HandlingUnitVo; |
|||
import com.gaotao.modules.warehouse.mapper.CrossSiteHuTransferMapper; |
|||
import com.gaotao.modules.warehouse.service.CrossSiteHuTransferService; |
|||
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.CollectionUtils; |
|||
import org.springframework.util.StringUtils; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.time.LocalDate; |
|||
import java.time.ZoneId; |
|||
import java.util.ArrayList; |
|||
import java.util.Date; |
|||
import java.util.LinkedHashSet; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 跨小site调拨实现:查询限定大site下在库未预留标签;提交时二次校验后先写STO再写STI,再改标签site,海安托盘明细有记录则同步sub_site - rqrq |
|||
* @date 2026/09/04 |
|||
*/ |
|||
@Slf4j |
|||
@Service |
|||
public class CrossSiteHuTransferServiceImpl implements CrossSiteHuTransferService { |
|||
|
|||
@Autowired |
|||
private CrossSiteHuTransferMapper crossSiteHuTransferMapper; |
|||
|
|||
@Autowired |
|||
private TransNoControlService transNoControlService; |
|||
|
|||
@Autowired |
|||
private TransHeaderService transHeaderService; |
|||
|
|||
@Autowired |
|||
private TransDetailService transDetailService; |
|||
|
|||
@Autowired |
|||
private TransDetailSubService transDetailSubService; |
|||
|
|||
@Autowired |
|||
private SysUserService sysUserService; |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 分页查询可调拨标签;登录大site缺失、无查询条件时直接失败,避免全表扫描 - rqrq |
|||
* @param query site=登录大site,searchSite=可选小site |
|||
* @return 分页结果 |
|||
*/ |
|||
@Override |
|||
public PageUtils searchHandlingUnitList(CrossSiteHuTransferData query) { |
|||
// 业务隔离必须使用请求中的登录大site,禁止后端兜底登录态 - rqrq |
|||
if (query == null || !StringUtils.hasText(query.getSite())) { |
|||
throw new RuntimeException("登录工厂site不能为空"); |
|||
} |
|||
// 至少填一个业务条件才能查,防止无过滤把大site下全部在库标签拉出来 - rqrq |
|||
if (!hasAnySearchCondition(query)) { |
|||
throw new RuntimeException("请至少填写一个查询条件"); |
|||
} |
|||
if (query.getPage() == null || query.getPage() < 1) { |
|||
query.setPage(1); |
|||
} |
|||
if (query.getLimit() == null || query.getLimit() < 1) { |
|||
query.setLimit(20); |
|||
} |
|||
// 用户填了小site时先校验属于当前大site,避免查出无关工厂标签 - rqrq |
|||
if (StringUtils.hasText(query.getSearchSite())) { |
|||
validateSubSiteBelongToLoginSite(query.getSite(), query.getSearchSite(), "查询site"); |
|||
} |
|||
|
|||
log.info("开始查询跨小site调拨标签 - rqrq,loginSite={}, searchSite={}, unitId={}, partNo={}", |
|||
query.getSite(), query.getSearchSite(), query.getUnitId(), query.getPartNo()); |
|||
|
|||
// 调用分页查询:SQL已固定 in_stock_flag=Y、reserve_flag=N,并限制 site_sub 范围;失败则无列表可展示 - rqrq |
|||
Page<CrossSiteHuTransferData> page = new Page<>(query.getPage(), query.getLimit()); |
|||
IPage<CrossSiteHuTransferData> pageResult = crossSiteHuTransferMapper.searchHandlingUnitList(page, query); |
|||
|
|||
log.info("跨小site调拨标签查询完成 - rqrq,total={}", pageResult.getTotal()); |
|||
return new PageUtils(pageResult); |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 查询目标小site下拉;excludeSite用于排除当前选中标签的来源site - rqrq |
|||
* @param query site=登录大site,excludeSite=来源小site |
|||
* @return 目标小site列表 |
|||
*/ |
|||
@Override |
|||
public List<SiteSubOptionData> listTargetSubSites(CrossSiteHuTransferData query) { |
|||
if (query == null || !StringUtils.hasText(query.getSite())) { |
|||
throw new RuntimeException("登录工厂site不能为空"); |
|||
} |
|||
if (!StringUtils.hasText(query.getExcludeSite())) { |
|||
throw new RuntimeException("来源site不能为空"); |
|||
} |
|||
// 来源site必须属于当前大site,否则下拉结果会误导后续提交 - rqrq |
|||
validateSubSiteBelongToLoginSite(query.getSite(), query.getExcludeSite(), "来源site"); |
|||
|
|||
// 按大site查 site_sub,排除来源site;失败则弹窗无法选目标,中断调拨 - rqrq |
|||
List<SiteSubOptionData> rows = crossSiteHuTransferMapper.listTargetSubSites(query); |
|||
return rows == null ? new ArrayList<>() : rows; |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 跨小site调拨主流程:二次校验预留/在库 -> 生成STO出库 -> 生成STI入库 -> 改标签site -> 调拨接口留空 - rqrq |
|||
* |
|||
* <p>事务边界:单据写入与标签site改写同一事务;任一校验或写入失败整批回滚,避免只出库不改site。</p> |
|||
* <p>出入库记录site使用小site:STO.site=fromSite,STI.site=toSite。</p> |
|||
* |
|||
* @param request 登录大site、来源/目标小site、操作人、选中标签 |
|||
* @return 成功数量与STO/STI事务号 |
|||
*/ |
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public CrossSiteHuTransferResult transferHuSite(CrossSiteHuTransferRequest request) { |
|||
// 先校验登录大site、来源/目标归属和整批同一来源;失败直接抛错,不写任何单据 - rqrq |
|||
validateTransferRequest(request); |
|||
|
|||
// 从选中行提取去重条码号,空条码会失败,避免后续IN条件无值 - rqrq |
|||
List<String> unitIds = collectUnitIds(request.getSelectedItems()); |
|||
log.info("开始跨小site调拨 - rqrq,loginSite={}, fromSite={}, toSite={}, count={}", |
|||
request.getSite(), request.getFromSite(), request.getToSite(), unitIds.size()); |
|||
|
|||
// 加锁读取来源site下选中标签,入参fromSite+unitIds;失败或漏行则中断,避免按过期列表写单 - rqrq |
|||
List<HandlingUnit> handlingUnits = crossSiteHuTransferMapper.listTransferHandlingUnits(request.getFromSite(), unitIds); |
|||
validateHandlingUnitStatus(unitIds, handlingUnits); |
|||
|
|||
// 目标site已存在同号标签时禁止改联合主键,避免唯一约束冲突导致半成品单据 - rqrq |
|||
List<String> conflictUnitIds = crossSiteHuTransferMapper.listConflictUnitIds(request.getToSite(), unitIds); |
|||
if (!CollectionUtils.isEmpty(conflictUnitIds)) { |
|||
throw new RuntimeException("目标site已存在相同条码,无法调拨:" + String.join(",", conflictUnitIds)); |
|||
} |
|||
|
|||
// 按操作人查用户档案,写入出入库单 userId/userName;查不到则仅用请求中的createdBy,不阻断调拨 - rqrq |
|||
SysUserEntity operatorUser = null; |
|||
if (StringUtils.hasText(request.getCreatedBy())) { |
|||
operatorUser = sysUserService.queryByUserName(request.getCreatedBy()); |
|||
} |
|||
String userId = operatorUser != null && operatorUser.getUserId() != null |
|||
? operatorUser.getUserId().toString() : ""; |
|||
String userName = operatorUser != null && StringUtils.hasText(operatorUser.getUsername()) |
|||
? operatorUser.getUsername() : request.getCreatedBy(); |
|||
|
|||
// 流水号按登录大site取号(trans_no_control通常按大site维护);单据site仍写小site。取号失败则无法写单,整批回滚 - rqrq |
|||
TransNoControl stoTransData = transNoControlService.getTransNo(request.getSite(), "STO", 10); |
|||
if (stoTransData == null || !StringUtils.hasText(stoTransData.getNewTransNo())) { |
|||
throw new RuntimeException("生成出库事务号失败,请检查当前工厂的STO流水配置:" + request.getSite()); |
|||
} |
|||
String stoTransNo = stoTransData.getNewTransNo(); |
|||
|
|||
// STI流水同样按登录大site取号;失败时STO号虽已占用(独立事务)但本事务回滚业务单据 - rqrq |
|||
TransNoControl stiTransData = transNoControlService.getTransNo(request.getSite(), "STI", 10); |
|||
if (stiTransData == null || !StringUtils.hasText(stiTransData.getNewTransNo())) { |
|||
throw new RuntimeException("生成入库事务号失败,请检查当前工厂的STI流水配置:" + request.getSite()); |
|||
} |
|||
String stiTransNo = stiTransData.getNewTransNo(); |
|||
|
|||
String warehouseId = handlingUnits.get(0).getWarehouseId(); |
|||
|
|||
// 先写出库头:site=来源小site,orderRef1互指入库单号,便于后续对账 - rqrq |
|||
TransHeader stoHeader = buildTransHeader(request.getFromSite(), stoTransNo, "STO", |
|||
warehouseId, stiTransNo, "跨小site调拨出库 " + request.getFromSite() + " -> " + request.getToSite(), |
|||
userId, userName); |
|||
transHeaderService.save(stoHeader); |
|||
|
|||
// 再写入库头:site=目标小site,orderRef1互指出库单号 - rqrq |
|||
TransHeader stiHeader = buildTransHeader(request.getToSite(), stiTransNo, "STI", |
|||
warehouseId, stoTransNo, "跨小site调拨入库 " + request.getFromSite() + " -> " + request.getToSite(), |
|||
userId, userName); |
|||
transHeaderService.save(stiHeader); |
|||
|
|||
// 按物料+批次+库位+WDR+工程变更级别汇总明细,减少单据行数;库位不改,仅site变化 - rqrq |
|||
Map<String, List<HandlingUnit>> groupedHUs = handlingUnits.stream() |
|||
.collect(Collectors.groupingBy(hu -> |
|||
nvl(hu.getPartNo()) + "|" + nvl(hu.getBatchNo()) + "|" + |
|||
nvl(hu.getLocationId()) + "|" + nvl(hu.getWdr()) + "|" + |
|||
(StringUtils.hasText(hu.getEngChgLevel()) ? hu.getEngChgLevel() : "1"))); |
|||
|
|||
int itemNo = 1; |
|||
for (Map.Entry<String, List<HandlingUnit>> entry : groupedHUs.entrySet()) { |
|||
List<HandlingUnit> groupHUs = entry.getValue(); |
|||
HandlingUnit firstHU = groupHUs.get(0); |
|||
BigDecimal totalQty = groupHUs.stream() |
|||
.map(hu -> hu.getQty() == null ? BigDecimal.ZERO : hu.getQty()) |
|||
.reduce(BigDecimal.ZERO, BigDecimal::add); |
|||
|
|||
// 写出库明细:site=来源小site,direction=-,库位仍为标签当前库位 - rqrq |
|||
transDetailService.save(buildTransDetail(request.getFromSite(), stoTransNo, itemNo, firstHU, |
|||
totalQty, "-", firstHU.getLocationId())); |
|||
// 写入库明细:site=目标小site,direction=+,库位不变(本次只改site) - rqrq |
|||
transDetailService.save(buildTransDetail(request.getToSite(), stiTransNo, itemNo, firstHU, |
|||
totalQty, "+", firstHU.getLocationId())); |
|||
|
|||
int seqNo = 1; |
|||
for (HandlingUnit hu : groupHUs) { |
|||
// 出库子明细按标签落 subNo=unitId,site用来源小site - rqrq |
|||
transDetailSubService.save(buildTransDetailSub(request.getFromSite(), stoTransNo, (double) itemNo, |
|||
seqNo, hu, "-")); |
|||
// 入库子明细同样按标签落行,site用目标小site - rqrq |
|||
transDetailSubService.save(buildTransDetailSub(request.getToSite(), stiTransNo, (double) itemNo, |
|||
seqNo, hu, "+")); |
|||
seqNo++; |
|||
} |
|||
itemNo++; |
|||
} |
|||
|
|||
// 单据写完后再改标签site;WHERE再次卡在库未预留,影响行数必须等于选中数,否则回滚 - rqrq |
|||
int updatedRows = crossSiteHuTransferMapper.updateHandlingUnitSite(request, unitIds); |
|||
if (updatedRows != unitIds.size()) { |
|||
throw new RuntimeException("更新标签site失败,期望更新" + unitIds.size() + "条,实际" + updatedRows |
|||
+ "条,可能标签已被预留或出库,请刷新后重试"); |
|||
} |
|||
|
|||
// 标签site改完后再查海安托盘明细:有明细才改sub_site,无明细视为普通仓标签直接跳过 - rqrq |
|||
syncHaiAnPalletDetailSubSite(request, unitIds); |
|||
|
|||
// 调拨外部接口当前留空:后续接入失败策略需与本事务一起评估,避免先提交本地再调外部导致不一致 - rqrq |
|||
callCrossSiteTransferApi(request, handlingUnits, stoTransNo, stiTransNo); |
|||
|
|||
CrossSiteHuTransferResult result = new CrossSiteHuTransferResult(); |
|||
result.setSuccessCount(updatedRows); |
|||
result.setFailCount(0); |
|||
result.setStoTransNo(stoTransNo); |
|||
result.setStiTransNo(stiTransNo); |
|||
result.setMessage("跨site调拨完成,出库事务号:" + stoTransNo + ",入库事务号:" + stiTransNo); |
|||
log.info("跨小site调拨完成 - rqrq,fromSite={}, toSite={}, sto={}, sti={}, count={}", |
|||
request.getFromSite(), request.getToSite(), stoTransNo, stiTransNo, updatedRows); |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 校验提交参数:登录大site、来源/目标小site归属、整批同一来源、禁止同site调拨 - rqrq |
|||
* @param request 调拨请求 |
|||
*/ |
|||
private void validateTransferRequest(CrossSiteHuTransferRequest request) { |
|||
if (request == null) { |
|||
throw new RuntimeException("调拨请求不能为空"); |
|||
} |
|||
if (!StringUtils.hasText(request.getSite())) { |
|||
throw new RuntimeException("登录工厂site不能为空"); |
|||
} |
|||
if (!StringUtils.hasText(request.getFromSite())) { |
|||
throw new RuntimeException("来源site不能为空"); |
|||
} |
|||
if (!StringUtils.hasText(request.getToSite())) { |
|||
throw new RuntimeException("目标site不能为空"); |
|||
} |
|||
if (!StringUtils.hasText(request.getCreatedBy())) { |
|||
throw new RuntimeException("操作人不能为空"); |
|||
} |
|||
if (request.getFromSite().equals(request.getToSite())) { |
|||
throw new RuntimeException("目标site不能与来源site相同"); |
|||
} |
|||
if (CollectionUtils.isEmpty(request.getSelectedItems())) { |
|||
throw new RuntimeException("请先选择要调拨的标签"); |
|||
} |
|||
// 前端可能漏传fromSite一致性,这里以后端选中行再校验一遍,避免跨多个小site混调 - rqrq |
|||
Set<String> selectedSites = request.getSelectedItems().stream() |
|||
.map(HandlingUnitVo::getSite) |
|||
.filter(StringUtils::hasText) |
|||
.collect(Collectors.toCollection(LinkedHashSet::new)); |
|||
if (selectedSites.size() > 1) { |
|||
throw new RuntimeException("选中标签来自多个site,不允许一起调拨:" + String.join(",", selectedSites)); |
|||
} |
|||
if (!selectedSites.isEmpty() && !selectedSites.contains(request.getFromSite())) { |
|||
throw new RuntimeException("来源site与选中标签site不一致"); |
|||
} |
|||
// 来源/目标都必须落在当前登录大site的 site_sub 内,防止把标签调到无关工厂 - rqrq |
|||
validateSubSiteBelongToLoginSite(request.getSite(), request.getFromSite(), "来源site"); |
|||
validateSubSiteBelongToLoginSite(request.getSite(), request.getToSite(), "目标site"); |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 二次校验标签仍在库且未预留;漏行、已出库、已预留均整批失败 - rqrq |
|||
* @param unitIds 前端提交的标签号 |
|||
* @param handlingUnits 加锁查询到的当前库数据 |
|||
*/ |
|||
private void validateHandlingUnitStatus(List<String> unitIds, List<HandlingUnit> handlingUnits) { |
|||
if (CollectionUtils.isEmpty(handlingUnits)) { |
|||
throw new RuntimeException("未找到可调拨标签,请确认标签仍在来源site且在库未预留"); |
|||
} |
|||
Map<String, HandlingUnit> huMap = handlingUnits.stream() |
|||
.collect(Collectors.toMap(HandlingUnit::getUnitId, hu -> hu, (a, b) -> a)); |
|||
List<String> errors = new ArrayList<>(); |
|||
for (String unitId : unitIds) { |
|||
HandlingUnit hu = huMap.get(unitId); |
|||
if (hu == null) { |
|||
errors.add(unitId + "不存在或不属于来源site"); |
|||
continue; |
|||
} |
|||
if (!"Y".equals(hu.getInStockFlag())) { |
|||
errors.add(unitId + "不在库,当前在库状态=" + nvl(hu.getInStockFlag())); |
|||
} |
|||
if (!"N".equals(hu.getReserveFlag())) { |
|||
errors.add(unitId + "已被预留,当前预留标记=" + nvl(hu.getReserveFlag())); |
|||
} |
|||
} |
|||
if (!errors.isEmpty()) { |
|||
throw new RuntimeException("标签预留/在库校验失败:" + String.join(";", errors)); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 从选中行提取去重后的条码号,空条码直接失败 - rqrq |
|||
* @param selectedItems 前端选中标签 |
|||
* @return 去重后的unitId列表 |
|||
*/ |
|||
private List<String> collectUnitIds(List<HandlingUnitVo> selectedItems) { |
|||
List<String> unitIds = selectedItems.stream() |
|||
.map(HandlingUnitVo::getUnitId) |
|||
.filter(StringUtils::hasText) |
|||
.distinct() |
|||
.collect(Collectors.toList()); |
|||
if (unitIds.isEmpty()) { |
|||
throw new RuntimeException("选中标签缺少条码号"); |
|||
} |
|||
return unitIds; |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 校验小site是否属于登录大site的 site_sub 映射,0条则拒绝 - rqrq |
|||
* @param loginSite 登录大site |
|||
* @param subSite 待校验小site |
|||
* @param fieldName 异常提示字段名 |
|||
*/ |
|||
private void validateSubSiteBelongToLoginSite(String loginSite, String subSite, String fieldName) { |
|||
// 按大site+小site查 site_sub;0表示越权或录错,必须中断避免改到无关工厂 - rqrq |
|||
int count = crossSiteHuTransferMapper.countSiteSubMapping(loginSite, subSite); |
|||
if (count <= 0) { |
|||
throw new RuntimeException(fieldName + "[" + subSite + "]不属于当前登录工厂[" + loginSite + "]"); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 判断是否至少填写一个业务查询条件(含可选小site) - rqrq |
|||
* @param query 查询对象 |
|||
* @return true=允许查询 |
|||
*/ |
|||
private boolean hasAnySearchCondition(CrossSiteHuTransferData query) { |
|||
return StringUtils.hasText(query.getUnitId()) |
|||
|| StringUtils.hasText(query.getPartNo()) |
|||
|| StringUtils.hasText(query.getBatchNo()) |
|||
|| StringUtils.hasText(query.getLocationId()) |
|||
|| StringUtils.hasText(query.getWarehouseId()) |
|||
|| StringUtils.hasText(query.getSearchSite()); |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 组装出入库单头;site必须是小site,status直接COMPLETED因为本地调拨同步完成 - rqrq |
|||
*/ |
|||
private TransHeader buildTransHeader(String site, String transNo, String transTypeDb, String warehouseId, |
|||
String orderRef1, String remark, String userId, String userName) { |
|||
TransHeader header = new TransHeader(); |
|||
header.setSite(site); |
|||
header.setTransNo(transNo); |
|||
header.setTransDate(Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant())); |
|||
header.setTransTypeDb(transTypeDb); |
|||
header.setWarehouseId(warehouseId); |
|||
header.setUserId(userId); |
|||
header.setUserName(userName); |
|||
header.setRemark(remark); |
|||
header.setOrderRef1(orderRef1); |
|||
header.setStatus("COMPLETED"); |
|||
header.setStatusDb("C"); |
|||
header.setEnterDate(new Date()); |
|||
header.setIfsFlag("N"); |
|||
return header; |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 组装出入库明细;site按出库/入库分别用来源或目标小site - rqrq |
|||
*/ |
|||
private TransDetail buildTransDetail(String site, String transNo, int itemNo, HandlingUnit hu, |
|||
BigDecimal totalQty, String direction, String locationId) { |
|||
TransDetail detail = new TransDetail(); |
|||
detail.setSite(site); |
|||
detail.setTransNo(transNo); |
|||
detail.setItemNo((double) itemNo); |
|||
detail.setPartNo(hu.getPartNo()); |
|||
detail.setTransQty(totalQty); |
|||
detail.setBatchNo(hu.getBatchNo()); |
|||
detail.setLocationId(locationId); |
|||
detail.setDirection(direction); |
|||
detail.setWdrNo(hu.getWdr()); |
|||
detail.setEngChgLevel(hu.getEngChgLevel()); |
|||
return detail; |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 组装出入库子明细,一条标签一行,subNo使用unitId便于反查 - rqrq |
|||
*/ |
|||
private TransDetailSub buildTransDetailSub(String site, String transNo, Double itemNo, int seqNo, |
|||
HandlingUnit hu, String direction) { |
|||
TransDetailSub detailSub = new TransDetailSub(); |
|||
detailSub.setSite(site); |
|||
detailSub.setTransNo(transNo); |
|||
detailSub.setItemNo(itemNo); |
|||
detailSub.setSubNo(hu.getUnitId()); |
|||
detailSub.setSubQty(hu.getQty() == null ? 0D : hu.getQty().doubleValue()); |
|||
detailSub.setDirection(direction); |
|||
detailSub.setSeqNo((double) seqNo); |
|||
detailSub.setPartNo(hu.getPartNo()); |
|||
detailSub.setBatchNo(hu.getBatchNo()); |
|||
detailSub.setLocationId(hu.getLocationId()); |
|||
detailSub.setEngChgLevel(hu.getEngChgLevel()); |
|||
return detailSub; |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 同步海安托盘明细sub_site;先按条码查询是否存在明细,没有则跳过,有则改成目标小site - rqrq |
|||
* |
|||
* <p>haian_pallet_detail.serial_no 对应 handling_unit.unit_id;sub_site 对应 handling_unit.site。</p> |
|||
* <p>查不到明细不算失败,因为跨site调拨页也会处理非海安托盘上的普通标签。</p> |
|||
* |
|||
* @param request 含登录大site和目标小site |
|||
* @param unitIds 已改写handling_unit.site的标签号 |
|||
*/ |
|||
private void syncHaiAnPalletDetailSubSite(CrossSiteHuTransferRequest request, List<String> unitIds) { |
|||
// 按登录大site+条码查海安托盘明细;失败则无法判断是否组盘,中断并回滚以免HU与托盘明细site不一致 - rqrq |
|||
List<String> haiAnSerialNos = crossSiteHuTransferMapper.listHaiAnPalletDetailSerialNos(request.getSite(), unitIds); |
|||
if (CollectionUtils.isEmpty(haiAnSerialNos)) { |
|||
log.info("跨site调拨未命中海安托盘明细,跳过sub_site改写 - rqrq,loginSite={}, count={}", |
|||
request.getSite(), unitIds.size()); |
|||
return; |
|||
} |
|||
// 仅改已存在的明细行,sub_site改为目标小site,与刚改完的handling_unit.site对齐 - rqrq |
|||
int haiAnUpdatedRows = crossSiteHuTransferMapper.updateHaiAnPalletDetailSubSite(request, request.getSite(), haiAnSerialNos); |
|||
log.info("跨site调拨已同步海安托盘明细sub_site - rqrq,loginSite={}, toSite={}, hit={}, updated={}", |
|||
request.getSite(), request.getToSite(), haiAnSerialNos.size(), haiAnUpdatedRows); |
|||
if (haiAnUpdatedRows <= 0) { |
|||
throw new RuntimeException("海安托盘明细已查到" + haiAnSerialNos.size() + "条标签,但更新sub_site影响行数为0,请刷新后重试"); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 调用跨site调拨外部接口的预留点;当前不发请求,只记日志,后续补接口时在此接入 - rqrq |
|||
* |
|||
* <p>后续接入时需明确:成功条件、失败是否回滚本地STO/STI/标签site、幂等键用哪张单据号。</p> |
|||
* |
|||
* @param request 调拨请求 |
|||
* @param handlingUnits 已校验通过的标签 |
|||
* @param stoTransNo 出库事务号 |
|||
* @param stiTransNo 入库事务号 |
|||
*/ |
|||
private void callCrossSiteTransferApi(CrossSiteHuTransferRequest request, List<HandlingUnit> handlingUnits, |
|||
String stoTransNo, String stiTransNo) { |
|||
log.info("跨site调拨外部接口暂未接入,本次仅完成本地STO/STI单据和标签site改写 - rqrq,fromSite={}, toSite={}, sto={}, sti={}, count={}", |
|||
request.getFromSite(), request.getToSite(), stoTransNo, stiTransNo, |
|||
handlingUnits == null ? 0 : handlingUnits.size()); |
|||
} |
|||
|
|||
/** |
|||
* @author rqrq |
|||
* @Description 空字符串转空,避免分组key出现null导致NPE - rqrq |
|||
*/ |
|||
private String nvl(String value) { |
|||
return value == null ? "" : value; |
|||
} |
|||
} |
|||
@ -0,0 +1,185 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
|||
|
|||
<mapper namespace="com.gaotao.modules.warehouse.mapper.CrossSiteHuTransferMapper"> |
|||
|
|||
<!-- rqrq - 分页查询可跨小site调拨标签:固定在库且未预留,site限定在当前登录大site的 site_sub 范围内 --> |
|||
<select id="searchHandlingUnitList" parameterType="CrossSiteHuTransferData" resultType="CrossSiteHuTransferData"> |
|||
SELECT |
|||
h.unit_id AS unitId, |
|||
h.site, |
|||
h.parent_unit_id AS parentUnitId, |
|||
h.unit_type AS unitType, |
|||
h.unit_type_db AS unitTypeDb, |
|||
h.part_no AS partNo, |
|||
h.part_desc AS partDesc, |
|||
h.qty, |
|||
h.batch_no AS batchNo, |
|||
h.location_id AS locationId, |
|||
h.warehouse_id AS warehouseId, |
|||
h.wdr, |
|||
h.availability_control_id AS availabilityControlId, |
|||
h.status, |
|||
h.status_db AS statusDb, |
|||
h.freeze_flag AS freezeFlag, |
|||
h.merged_flag AS mergedFlag, |
|||
h.in_stock_flag AS inStockFlag, |
|||
h.order_ref1 AS orderRef1, |
|||
h.order_ref2 AS orderRef2, |
|||
h.order_ref3 AS orderRef3, |
|||
h.supplier_id AS supplierId, |
|||
h.customer_id AS customerId, |
|||
h.manufacture_date AS manufactureDate, |
|||
h.expired_date AS expiredDate, |
|||
h.created_date AS createdDate, |
|||
h.created_by AS createdBy, |
|||
h.modified_date AS modifiedDate, |
|||
h.modified_by AS modifiedBy, |
|||
h.remark, |
|||
h.source_type AS sourceType, |
|||
h.source_ref AS sourceRef, |
|||
h.gross_weight AS grossWeight, |
|||
h.net_weight AS netWeight, |
|||
h.weight_unit AS weightUnit, |
|||
h.volume, |
|||
h.volume_unit AS volumeUnit, |
|||
h.qr_code AS qrCode, |
|||
h.bar_code AS barCode, |
|||
h.printer_name AS printerName, |
|||
h.last_print_date AS lastPrintDate, |
|||
h.print_count AS printCount, |
|||
h.receive_date AS receiveDate, |
|||
h.original_qty AS originalQty, |
|||
h.tid, |
|||
h.epc, |
|||
h.length, |
|||
h.width, |
|||
h.um_id AS umId, |
|||
h.reserve_flag AS reserveFlag, |
|||
h.reserve_order_ref1 AS reserveOrderRef1, |
|||
h.reserve_order_ref2 AS reserveOrderRef2, |
|||
h.reserve_order_ref3 AS reserveOrderRef3, |
|||
h.height, |
|||
h.eng_chg_level AS engChgLevel |
|||
FROM handling_unit h WITH (NOLOCK) |
|||
WHERE h.in_stock_flag = 'Y' |
|||
AND h.reserve_flag = 'N' |
|||
AND h.site IN ( |
|||
SELECT ss.subsiteid |
|||
FROM site_sub ss WITH (NOLOCK) |
|||
WHERE ss.siteid = #{query.site} |
|||
) |
|||
<if test="query.searchSite != null and query.searchSite != ''"> |
|||
AND h.site = #{query.searchSite} |
|||
</if> |
|||
<if test="query.unitId != null and query.unitId != ''"> |
|||
AND h.unit_id LIKE '%' + #{query.unitId} + '%' |
|||
</if> |
|||
<if test="query.partNo != null and query.partNo != ''"> |
|||
AND h.part_no = #{query.partNo} |
|||
</if> |
|||
<if test="query.batchNo != null and query.batchNo != ''"> |
|||
AND h.batch_no LIKE '%' + #{query.batchNo} + '%' |
|||
</if> |
|||
<if test="query.locationId != null and query.locationId != ''"> |
|||
AND h.location_id LIKE '%' + #{query.locationId} + '%' |
|||
</if> |
|||
<if test="query.warehouseId != null and query.warehouseId != ''"> |
|||
AND h.warehouse_id = #{query.warehouseId} |
|||
</if> |
|||
ORDER BY h.created_date DESC |
|||
</select> |
|||
|
|||
<!-- rqrq - 按登录大site查询可选目标小site,排除当前标签来源site;NOLOCK仅用于下拉展示,允许脏读 --> |
|||
<select id="listTargetSubSites" parameterType="CrossSiteHuTransferData" resultType="SiteSubOptionData"> |
|||
SELECT |
|||
ss.siteid AS siteId, |
|||
ss.subsiteid AS subSiteId |
|||
FROM site_sub ss WITH (NOLOCK) |
|||
WHERE ss.siteid = #{query.site} |
|||
<if test="query.excludeSite != null and query.excludeSite != ''"> |
|||
AND ss.subsiteid <> #{query.excludeSite} |
|||
</if> |
|||
ORDER BY ss.subsiteid |
|||
</select> |
|||
|
|||
<!-- rqrq - 校验小site是否属于当前登录大site;用于拒绝越权调拨 --> |
|||
<select id="countSiteSubMapping" resultType="int"> |
|||
SELECT COUNT(1) |
|||
FROM site_sub WITH (NOLOCK) |
|||
WHERE siteid = #{site} |
|||
AND subsiteid = #{subSite} |
|||
</select> |
|||
|
|||
<!-- rqrq - 加锁读取待调拨标签,避免并发改预留/出库后仍按旧状态写单 --> |
|||
<select id="listTransferHandlingUnits" resultType="com.gaotao.modules.handlingunit.entity.HandlingUnit"> |
|||
SELECT |
|||
h.unit_id, |
|||
h.site, |
|||
h.part_no, |
|||
h.part_desc, |
|||
h.qty, |
|||
h.batch_no, |
|||
h.location_id, |
|||
h.warehouse_id, |
|||
h.wdr, |
|||
h.eng_chg_level, |
|||
h.in_stock_flag, |
|||
h.reserve_flag |
|||
FROM handling_unit h WITH (UPDLOCK, ROWLOCK) |
|||
WHERE h.site = #{fromSite} |
|||
AND h.unit_id IN |
|||
<foreach collection="unitIds" item="unitId" open="(" separator="," close=")"> |
|||
#{unitId} |
|||
</foreach> |
|||
</select> |
|||
|
|||
<!-- rqrq - 目标小site已存在同 unit_id 时禁止改主键,避免联合主键冲突 --> |
|||
<select id="listConflictUnitIds" resultType="java.lang.String"> |
|||
SELECT h.unit_id |
|||
FROM handling_unit h WITH (NOLOCK) |
|||
WHERE h.site = #{toSite} |
|||
AND h.unit_id IN |
|||
<foreach collection="unitIds" item="unitId" open="(" separator="," close=")"> |
|||
#{unitId} |
|||
</foreach> |
|||
</select> |
|||
|
|||
<!-- rqrq - 仅改写标签site;WHERE再次限定在库且未预留,防止校验后状态被并发改写 --> |
|||
<update id="updateHandlingUnitSite"> |
|||
UPDATE handling_unit WITH (ROWLOCK) |
|||
SET site = #{request.toSite}, |
|||
modified_by = #{request.createdBy}, |
|||
modified_date = GETDATE() |
|||
WHERE site = #{request.fromSite} |
|||
AND in_stock_flag = 'Y' |
|||
AND reserve_flag = 'N' |
|||
AND unit_id IN |
|||
<foreach collection="unitIds" item="unitId" open="(" separator="," close=")"> |
|||
#{unitId} |
|||
</foreach> |
|||
</update> |
|||
|
|||
<!-- rqrq - 按大site+条码查海安托盘明细,确认标签是否组在海安托盘上;无记录则跳过sub_site改写 --> |
|||
<select id="listHaiAnPalletDetailSerialNos" resultType="java.lang.String"> |
|||
SELECT DISTINCT d.serial_no |
|||
FROM haian_pallet_detail d WITH (NOLOCK) |
|||
WHERE d.site = #{site} |
|||
AND d.serial_no IN |
|||
<foreach collection="unitIds" item="unitId" open="(" separator="," close=")"> |
|||
#{unitId} |
|||
</foreach> |
|||
</select> |
|||
|
|||
<!-- rqrq - 仅改已存在的海安托盘明细sub_site;site用登录大site隔离,serial_no对应标签号 --> |
|||
<update id="updateHaiAnPalletDetailSubSite"> |
|||
UPDATE haian_pallet_detail WITH (ROWLOCK) |
|||
SET sub_site = #{request.toSite} |
|||
WHERE site = #{site} |
|||
AND serial_no IN |
|||
<foreach collection="unitIds" item="unitId" open="(" separator="," close=")"> |
|||
#{unitId} |
|||
</foreach> |
|||
</update> |
|||
|
|||
</mapper> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue