837 Commits
Author SHA1 Message Date
秦鸿展 07393e43ff 31 2026-09-13 18:26:40 +08:00
秦鸿展 08858f24d6 30 2026-09-13 18:22:47 +08:00
秦鸿展 a994241400 BI月台指标新增字段 2026-09-13 18:21:26 +08:00
王奎兴 a9be03961a feign地址修改; 2026-09-12 17:57:49 +08:00
王奎兴 7f6006ca48 feign地址修改; 2026-09-12 17:20:01 +08:00
赵辉 defc8c3709 31 2026-09-12 10:03:33 +08:00
王奎兴 3c21c2c848 发30 2026-09-12 10:00:45 +08:00
王奎兴 71936b50a7 Merge remote-tracking branch 'origin/dev' into dev 2026-09-12 09:59:56 +08:00
赵辉 9cfffe1224 去除验证码校验 2026-09-12 09:59:39 +08:00
王奎兴 d7574d188a 客户月结报告; 2026-09-12 09:59:30 +08:00
赵辉 1c1b06c1bf 去除验证码校验 2026-09-12 09:24:11 +08:00
rcx 117019c55c 30 2026-09-11 17:46:07 +08:00
rcx 171909b68d 31 2026-09-11 17:44:15 +08:00
赵辉 31c27c16c6 user31 2026-09-11 17:28:40 +08:00
赵辉 8dfe9545aa user30 2026-09-11 17:22:50 +08:00
赵辉 028afb57d7 用户-yms同步新增与修改密码 2026-09-11 15:45:15 +08:00
rcx 37dd374bda fix(wms): 入库单导入"该货主下不存在该料号"误报修复
- 根因:Excel客户名称按USER表user_name解析货主ID,同名双账号(如3519/3525)解析到非档案归属账号,带错误shipperId查物料必为空
- 料号匹配:主查询(料号+顶级组织+解析shipperId)为空时,去掉货主条件按档案shipper_name与Excel客户名称等值兜底匹配,命中后以档案货主纠正单据shipperId/shipperCode/shipperName
- 新增pickMaterialByCode挑选:料号精确等值优先于LIKE模糊命中,避免子串料号截胡
- SKU校验:档案条码barCode为空时跳过比对,档案有值时仍严格校验
- 校验失败输出诊断日志并附解析shipperId/登录topOrganizationId,区分货主错配(原因A)与组织口径(原因B)
2026-09-11 15:14:46 +08:00
秦鸿展 d69af9ef20 30 2026-09-10 16:49:24 +08:00
秦鸿展 9704dbfb07 导入物料组织覆盖问题 2026-09-10 16:20:59 +08:00
秦鸿展 3276792bb5 告警修改 2026-09-10 13:20:07 +08:00
秦鸿展 b57db4b8cc 30 2026-09-10 11:49:34 +08:00
秦鸿展 8a31ed9974 BI月台指标检测修改 2026-09-10 11:46:34 +08:00
秦鸿展 9777156959 31 2026-09-09 23:46:09 +08:00
秦鸿展 ba5d78b36c 准时率统计修改 2026-09-09 23:40:33 +08:00
秦鸿展 dea39a1a4b 30 2026-09-09 22:05:47 +08:00
秦鸿展 0493030620 BI月台作业准时率计算 2026-09-09 22:02:31 +08:00
秦鸿展 3907b126d9 31 2026-09-09 19:42:39 +08:00
秦鸿展 7b76d5c203 BI接口业务类型恢复 2026-09-09 19:38:47 +08:00
秦鸿展 f02a2d52f2 OMS调整接口开发 2026-09-09 16:24:05 +08:00
秦鸿展 a3c0f15e39 30 2026-09-09 15:19:29 +08:00
秦鸿展 d2a6a5a4f6 BI启动报错 2026-09-09 15:12:55 +08:00
秦鸿展 752216ad45 31 2026-09-09 14:22:58 +08:00
秦鸿展 6a8661da63 BI模块修改 2026-09-09 13:59:55 +08:00
秦鸿展 2b6777abe4 BI模块修改 2026-09-09 13:47:46 +08:00
rcx fd3a9afddf 发31 2026-09-08 17:52:42 +08:00
rcx 0358c694ea 发30 2026-09-08 17:46:49 +08:00
rcx 009dc5b3a6 feat(wms): 盘点单详情investigetionManageDetailList返回批次号、入库日期、生产日期、过期日期 2026-09-08 17:35:29 +08:00
rcx 178b7697af fix(oms): 出库单列表totalOutboundQuantity恒为null,queryList改为SQL汇总一级明细出库数量
原Java循环逐单调getInfoChildren汇总(N+1)被注释后无赋值导致恒为null;改为关联子查询coalesce(sum(outbound_quantity),0),仅统计level=1且del_flag=1,口径与详情页一致;/list与/list1共用同一语句同时生效,无需DDL
2026-09-08 15:08:00 +08:00
rcx 32364baba8 发测试 2026-09-08 13:38:54 +08:00
rcx 6c6a491ff8 feat(oms/wms): WMS上架状态回传OMS入库业务单,修复入库状态不同步
- WMS上架推进入库状态后回传OMS(OmsServiceFeign新增returnInResult)
- OMS回传接收加固:无登录上下文判空、已入库同步issueStatus=4
- 已入库联动同步预约入库单(入库业务单)状态
2026-09-08 13:37:43 +08:00
rcx a496fc235b fix(oms): 新增/编辑入库单以业务类型为准同步单据类型,修复退货入库被写成普通入库及编辑类型不生效 2026-09-08 10:53:23 +08:00
rcx 06202b652a 发测试 2026-09-08 09:32:47 +08:00
rcx 5d748a9ac6 fix(oms): 入库业务单新增时用businessType回填单据类型,修复退货单被写成普通入库 2026-09-08 09:28:27 +08:00
王奎兴 361a91d701 发31 2026-09-07 19:02:39 +08:00
王奎兴 3471874139 退货入库; 2026-09-07 18:58:33 +08:00
王奎兴 a38e28bb97 退货入库; 2026-09-07 18:57:51 +08:00
rcx ab7a4e265f Merge branch 'dev-ty1.2' into dev
# Conflicts:
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/BmsServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/OmsServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/WlhyServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/WmsServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/YmsServiceFeign.java
#	mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/feign/ThirdPartyServiceFeign.java
#	mhd_oms/src/main/java/com/mhd/oms/infrastructure/feign/ThirdPartyServiceFeign.java
#	mhd_wms/src/main/resources/bootstrap.yml
2026-09-07 18:03:18 +08:00
rcx 976ab715af 发30 2026-09-07 18:02:10 +08:00
王奎兴 6856899afc Merge remote-tracking branch 'origin/dev' into dev 2026-09-07 17:23:10 +08:00
王奎兴 6d7be15d97 发31 2026-09-07 17:23:01 +08:00
rcx 0babc7dbf8 Merge remote-tracking branch 'origin/dev' into dev 2026-09-07 17:19:31 +08:00
王奎兴 1a80f715dd 恢复xxl 2026-09-07 17:16:11 +08:00
rcx 7742d11d1c 发31 2026-09-07 17:15:05 +08:00
rcx c4df9b3403 Merge remote-tracking branch 'origin/dev' into dev 2026-09-07 17:08:20 +08:00
rcx 7ed34df81e 发30 2026-09-07 17:07:16 +08:00
王奎兴 0ace96ea9f 恢复xxl 2026-09-07 17:06:27 +08:00
王奎兴 34014f40a5 Merge branch 'dev-ty1.2' into dev 2026-09-07 16:57:14 +08:00
rcx acbf7c9fdf fix: 退货入库单下发时执行入库单类型被固定写成普通入库 2026-09-07 16:56:17 +08:00
rcx 9e1c5d8570 fix(oms): 预约单下发不再推送WMS,修复执行单下发后WMS出现预约单+执行单两张单;三个下发入口补充软删单拦截 2026-09-07 15:44:44 +08:00
秦鸿展 98b5ce81cc 委托方导出功能 2026-09-07 14:28:29 +08:00
rcx b6a69411f1 发 测试 2026-09-07 14:25:29 +08:00
rcx 34b27eabd2 fix(oms): 出入库导入行级必填校验+页签解析失败完整堆栈日志
一、行级必填校验(ReservationStockInOrderImpl)
- 入库导入:新增校验空【產品編號】/空【支/件数】的明细行,给出明确提示
- 出库导入:新增校验空【支/件数】的明细行
- 修复原因:明细行件数为空时 new BigDecimal(null) 抛无信息的 NullPointerException,页面只显示 页签[x]:java.lang.NullPointerException 无法定位

二、页签解析失败完整堆栈日志
- 出/入库多页签解析第一阶段捕获异常时,将完整堆栈打入服务端日志(LOGGER.error),便于远程定位页签内具体报错行号
2026-09-07 14:18:34 +08:00
rcx 1c4b520f5a Merge remote-tracking branch 'origin/dev-bms-260826' into dev-ty1.2 2026-09-07 13:50:28 +08:00
王奎兴 32459fd443 xxl-job配置; 2026-09-07 11:33:14 +08:00
王奎兴 625b195183 发测试 2026-09-07 10:21:36 +08:00
王奎兴 0c95470300 Merge branch 'dev-ty1.2' into dev-bms-260826 2026-09-07 10:19:22 +08:00
王奎兴 ba3a540a94 Merge branch 'dev' into dev-bms-260826
# Conflicts:
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/BmsServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/OmsServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/WlhyServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/WmsServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/YmsServiceFeign.java
#	mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/feign/ThirdPartyServiceFeign.java
#	mhd_oms/src/main/java/com/mhd/oms/infrastructure/feign/ThirdPartyServiceFeign.java
#	mhd_wms/src/main/resources/bootstrap.yml
2026-09-07 10:00:28 +08:00
王奎兴 a484e81b32 发测试 2026-09-07 09:23:22 +08:00
rcx 627f63cbd3 fix(oms,wms): 入库执行单取消下发完整回退WMS数据,修复重复下发数据致取消阻断
一、取消下发回退不完整/阻断:原OMS跨库仅软删4张表,收货任务/收货作业单/质检单/电子签名残留;且getWShOrder在重复下发产生多张同号收货单时抛TooManyResultsException,取消下发整体回滚失败。WMS新增/stockInOrderApi/omsCancelInOrder:单事务软删下发链路全部8张表(入库单/明细、收货单/明细、收货任务、收货作业单/明细、质检单),幂等可重试,已开始收货报错拦截;OMS执行单取消下发改调该接口并清理待签名电子签名;预约单取消下发补齐WMS清理

二、下发失败被静默吞掉:omsInOrderAdd/omsInOrderAddDetail原返回void、Feign降级静默,OMS已下发但WMS无数据。改返回AjaxResult、fallback报错,执行单/预约单下发逐一校验返回值,失败回滚下发标记(WMS侧幂等,重下发安全)

三、下发防重原子化:issueOrder下发标记改条件更新(issue_time IS NULL)+影响行数校验,关闭并发/双击重复推送WMS的窗口
2026-09-07 09:20:37 +08:00
王奎兴 f6c454765e jobid查询接口; 2026-09-05 19:21:17 +08:00
王奎兴 25102b5207 jobid查询接口; 2026-09-05 19:14:34 +08:00
王奎兴 6708353379 jobid查询接口; 2026-09-05 19:08:42 +08:00
王奎兴 20d11dc9b2 jobid查询接口; 2026-09-05 19:00:02 +08:00
王奎兴 fa7db5df0c jobid查询接口; 2026-09-05 18:52:30 +08:00
王奎兴 cb1a1ec9a6 jobid查询接口; 2026-09-05 18:48:19 +08:00
王奎兴 3abac7b3d6 jobid查询接口; 2026-09-05 18:44:25 +08:00
秦鸿展 3c81e37e32 30 2026-09-05 18:39:15 +08:00
王奎兴 cecfe3e777 jobid查询接口; 2026-09-05 18:28:34 +08:00
王奎兴 104fc8bbef code 2026-09-05 18:19:25 +08:00
王奎兴 d9e5cede10 code 2026-09-05 17:59:18 +08:00
王奎兴 1689da1911 token 2026-09-05 17:51:37 +08:00
王奎兴 c043da88e4 groupid 2026-09-05 17:41:01 +08:00
王奎兴 d10a81fc42 自动添加xxl任务; 2026-09-05 17:37:33 +08:00
王奎兴 10bba6fd9e 物料仓租修改; 2026-09-05 16:59:46 +08:00
王奎兴 bc09b77695 添加计费字段; 2026-09-05 16:55:10 +08:00
秦鸿展 a7a387f215 南岐GPS接口对接增加字段 2026-09-05 16:29:38 +08:00
王奎兴 4d0ea8522e 发31 2026-09-05 15:52:37 +08:00
王奎兴 700eb3ee95 发30 2026-09-05 15:45:09 +08:00
王奎兴 fd62a7aff5 发31 2026-09-05 15:41:11 +08:00
王奎兴 b05c87e291 Merge branch 'dev' into dev-bms-260826
# Conflicts:
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/BmsServiceFeign.java
#	mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/facade/IReservationStockInOrderService.java
#	mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/mapper/ReservationStockInOrderMapper.java
#	mhd_oms/src/main/resources/mapper/reservationStockInOrder/ReservationStockInOrderMapper.xml
#	mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/po/MaterialInventoryPO.java
#	mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/todo/MaterialInventoryDO.java
#	mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/materialInventory/MaterialInventoryDTO.java
#	mhd_wms/src/main/resources/mapper/materialInventory/MaterialInventoryMapper.xml
2026-09-05 15:14:35 +08:00
王奎兴 7790850da3 自动生成job 2026-09-05 14:51:25 +08:00
秦鸿展 8ddf20f3e7 南岐GPS接口 2026-09-05 14:39:04 +08:00
秦鸿展 9e186bc034 南岐GPS接口 2026-09-05 14:38:49 +08:00
rcx c0065074d3 Merge branch 'dev-ty1.2' into dev 2026-09-05 13:53:01 +08:00
rcx be8ba45067 fix(oms,wms): 出库单下发WMS失败被静默吞掉,修复WMS出库拣货不显示OMS单据
- 建单/下发前统一校验(数量>0、已关联库存、WMS可用库存),错误汇总一次性提示
- 新增WMS库存校验接口,库存不足在OMS侧拦截不再推送WMS;拦截重复下发
- 检查WMS自动分配/生成拣货单返回值,失败报错并补偿清理WMS残留单据
- 下发状态逐单提交,避免批量部分失败造成两边状态撕裂
- 预约单多仓下发增加逐仓预校验
- 修复取消下发不删拣货单、无库存脏单无法取消两个历史问题
2026-09-05 13:42:02 +08:00
rcx c0bcedbdc3 fix(wms,oms): JSON日期反序列化兼容yyyy-MM-dd纯日期格式
- 库存查询日期只保留年月日后,前端回传纯日期(如 createTime=2026-07-06)触发
  @JsonFormat("yyyy-MM-dd HH:mm:ss") 严格格式反序列化 InvalidFormatException
- 新增 FlexibleDateDeserializer:字段 @JsonFormat 模式优先严格解析,失败后兼容
  yyyy-MM-dd HH:mm:ss / yyyy-MM-dd HH:mm / yyyy-MM-dd / 时间戳 / ISO-8601
- 仅在 OMS/WMS 通过 Module Bean 注册生效,不改动 BaseVOEntity 全局行为
2026-09-05 13:38:06 +08:00
王奎兴 84558fe2f6 xxl配置类; 2026-09-05 10:46:24 +08:00
秦鸿展 b46483263b 31 2026-09-05 10:36:12 +08:00
秦鸿展 4755d4e62b 30 2026-09-05 10:30:36 +08:00
王奎兴 3081460143 Merge branch 'dev' into dev_sfjk_0827 2026-09-05 10:23:32 +08:00
王奎兴 6c6afe4342 联查合同接口开发; 2026-09-05 10:22:24 +08:00
王奎兴 befdb82b53 联查合同接口开发; 2026-09-04 19:16:57 +08:00
王奎兴 5a329904c3 正式合同定时任务; 2026-09-04 15:40:19 +08:00
王奎兴 c25a9a5f68 发30 2026-09-04 14:06:48 +08:00
王奎兴 6b3912aae9 发30 2026-09-04 13:59:37 +08:00
王奎兴 12e43080b8 发31 2026-09-04 13:55:07 +08:00
王奎兴 77e0c77fbf 发31 2026-09-04 12:21:17 +08:00
王奎兴 03978d23d7 发30 2026-09-04 12:17:28 +08:00
王奎兴 ee7dbfcfb9 发30 2026-09-04 11:55:45 +08:00
王奎兴 94d05cca9c 发31 2026-09-04 11:52:53 +08:00
王奎兴 9fd3d34610 逻辑删除查询条件; 2026-09-04 11:51:10 +08:00
王奎兴 edb7a5343d 逻辑删除查询条件; 2026-09-04 11:37:06 +08:00
王奎兴 6108606daa bms改造; 2026-09-04 11:11:39 +08:00
rcx 762c49cd0f 发 测试 2026-09-04 11:10:20 +08:00
rcx 1b8511c092 feat(oms): 出库/入库业务单导入支持多页签——每个工作表独立生成一张单据
一、行为变更(ReservationStockInOrderImpl)
- 出库导入(parseExcelFile)/入库导入(parseStockInExcel):不再固定读单一页签,枚举Excel全部工作表,每个页签独立解析为一张单据(5个页签=5张单5个单号)
- 全部回滚策略:任一页签校验失败整体不落库,报错按页签聚合列出(页签[x]:原因;页签[y]:原因)
- 空页签(无货品/客户明细)自动跳过;单页签文件行为与原先完全一致
- 出库单号改到落库阶段逐张生成:多页签下校验阶段统一生成会因全部未入库而取到相同单号
- 入库模板OrderNO增加本文件内跨页签查重:各页签都未入库时库查重互相不可见,防两页签同OrderNO重复落库
- 页签解析异常message为空时兜底用异常类名,避免报错显示null
- 方法级@Transactional(rollbackFor=Exception.class):顺带修复旧入库导入因this自调用导致事务代理失效的问题

二、接口与返回结构(IReservationStockInOrderService / ReservationStockInOrderApi)
- 两个导入方法返回类型改为List<SheetImportResultDTO>(每页签一条:页签名/单号/物料行数/数量合计/解析数据)
- /parseExcel与/parse-excel返回:result=第一个页签解析数据(兼容老前端)、results=全部页签结果、msg=成功导入N张单:单号1、单号2…
- 入库接口不传sheetName为多页签模式,显式传页签名保持单页签老行为
2026-09-04 10:55:18 +08:00
rcx ce3bb036fa 发 测试 2026-09-04 10:50:48 +08:00
rcx 71515e74f5 Merge branch 'refs/heads/dev' into dev-ty1.2 2026-09-04 10:48:46 +08:00
rcx 7d3c229b9a feat(oms): 新增出仓委托单,支持新增/编辑/审核/下发WMS/完成入库
- 订单状态五态:1待审核(新增默认,驳回单编辑后自动回此态) 2已审核(下发后保持,用下发状态区分) 3已驳回 4进行中(预留) 5已入库
- 下发走WMS出库通知单链路(stockOutOrInInsert),返回强校验防吞错;完成入库限已审核+已下发
- 订单类型未传默认普通出库;明细新增单价unitPrice;列表支持invoiceNo/settlementCurrency查询,时间参数只传年月日
- 必填:客户/业务员/仓库/商品名称/申报数量;编辑删除限待审核/已驳回且未下发
- 附达梦建表脚本oms_out_entrust_order(主表+明细表,最终版)
2026-09-04 10:47:29 +08:00
rcx a549ac1507 发 31 2026-09-03 18:32:25 +08:00
rcx bf3f0a2bfe 发 30 2026-09-03 18:25:37 +08:00
rcx 35b026c8bd Merge branch 'refs/heads/dev-ty1.2' into dev 2026-09-03 18:23:32 +08:00
rcx 0eb47793a8 fix(库存): OMS/WMS库存查询入库时间/更新时间只保留年月日,去掉时分秒
- 入库时间(createTime)/更新时间(updateTime)继承自全系统基类 BaseVOEntity,默认序列化带时分秒;库存查询导出复用 /list 接口,前端取 JSON 值直接进 Excel,导出后无法在 Excel 里修改格式
- 两个库存 PO 覆盖 getCreateTime/getUpdateTime 并收窄 @JsonFormat 为 yyyy-MM-dd,仅影响 OMS/WMS 库存查询的显示与导出,不改动 BaseVOEntity 全局行为
- 页面列表/详情回显同步变为纯年月日;排序仍按原始时间值,逻辑不变
2026-09-03 18:00:52 +08:00
rcx fee891dad0 fix(oms): 下发出库单增加幂等拦截,已存在有效执行单时禁止重复下发
问题:单据下发过并取消后重新下发(或重复点下发),issueOrder 会再生成新执行单并原样复制业务明细uniqueId插入,撞执行明细表唯一约束(如CONS134279709)导致下发失败。
修复:issueOrder 生成执行单前先查同业务单号下是否已存在有效执行单(del_flag=1),存在则提示「已下发,请勿重复下发;如需重新下发请先取消下发」。
配套DB变更(单独由DBA执行):执行明细表唯一键CONS134279709改为函数唯一索引,仅对DEL_FLAG=1的行约束UNIQUE_ID唯一,软删行不再占用唯一键。
2026-09-03 17:44:16 +08:00
rcx 34496de969 发测试 2026-09-03 16:04:04 +08:00
rcx 7a3021f82a feat(wms,oms):出库排名统计改造为聚合排名——商品按物料合并/线路按线路+物料合并,按出库数量降序
- 商品tab:一行=一个货品(跨出库单汇总),返回 货号/货名/件数/毛重(吨)/体积(CBM)/退保总额(占位null),忽略线路筛选参数

- 线路tab:一行=线路×货品(按线路+物料编码合并),额外返回 线路编码/线路,仅统计带线路的单(排除line_code为空的历史单);商品/线路筛选参数均生效

- 单据级字段(种类/仓单编号/入库单号/客户编号/收货人/出仓日期)合并后无单值可对应,不再返回

- 件数=SUM(CHECK_QUANTITY)复核确认的实际出库量(与入库排名实际上架量SHELVES_QUANTITY对称),按件数降序,编码次之

- 合计行:件数/毛重吨/体积 全量合计;商品tab含totalOrderCount(去重出库单数),线路tab含totalOrderCount+totalLineCount(去重线路数)

- 数据源不变:WMS查本库出库表,OMS跨库查NGWL_TEST_WMS同名表,两边数字一致;接口路径/传参不变
2026-09-03 16:01:17 +08:00
rcx c9c3062789 feat(wms,oms):入库排名统计改为按物料编码合并(一行=一个物料在区间内全部已入库仓单的合计):返回列裁剪为物料编码/货名/规格型号/单位/件数(实际上架量)/毛重(吨)/投保总额(货品档案保额取MAX不跨仓单累加)/体积;仓单编号/客户编号/存货人/入仓日期为单据级字段单值失真,移出返回列仅保留为查询条件;HAVING过滤0件行;合计行投保总额=各物料保额之和(每物料计一次),totalOrderCount=涉及仓单数;OMS/WMS两端口径数字一致;查询参数与返回结构外层不变 2026-09-03 15:57:44 +08:00
rcx 4ad31a870a fix(oms): 物料解析防张冠李戴+导入三类校验合并报错,客户编码只认USER_MEMBER_CODE
一、出库业务单导入(ReservationStockInOrderImpl)
- 物料不存在/客户不存在/批次库存不足三类校验全部收集完成后统一报错,不再分阶段中断
- materialCache 取用统一 trim,防 Excel 编号带空格导致校验被跳过

二、物料三级解析防张冠李戴(MaterialBaseInfoResolveService)
- baseId 按主键查到的档案与明细编码不一致时不再信任 baseId,转库存ID反查/编码+组织兜底,两级落空才退回按ID档案,命中打WARN日志
- 背景:前端把库存ID传进 materialBaseInfoId,撞上编码=名称的脏档案主键后整行物料被覆盖成错误物料

三、客户编码口径(reservationStockOutOrder/ReservationStockOutOrderMapper.xml)
- queryCustomerByCode 只认 USER.USER_MEMBER_CODE,不再放行 USER_SHIPPER.CUSTOMER_NC_CODE

四、明细查询补字段(reserveStockOutOrder/ReserveStockOutOrderMapper.xml)
- resultMap 补 status/issue_status 映射,detailsList 查询补查 a.status, a.issue_status
2026-09-03 15:52:18 +08:00
秦鸿展 9447604c96 31 2026-09-03 12:37:33 +08:00
秦鸿展 1577eddc7b 30 2026-09-03 11:49:38 +08:00
秦鸿展 f5300fdd5d BI查询YMS月台管理列表查询开发接口 2026-09-03 11:39:13 +08:00
秦鸿展 3880755df0 BI查询YMS月台管理列表查询开发接口 2026-09-03 11:35:33 +08:00
秦鸿展 28bf58e8d1 BI查询YMS月台管理列表查询开发接口 2026-09-03 11:28:22 +08:00
秦鸿展 3a5af634dd 30 2026-09-03 00:29:18 +08:00
秦鸿展 4f45a73505 已登录账号APP菜单问题 2026-09-03 00:26:45 +08:00
秦鸿展 b5f710cd33 31 2026-09-02 20:49:09 +08:00
秦鸿展 bfffc6bbf1 App游客时正常展示消息页面 2026-09-02 20:46:31 +08:00
秦鸿展 a8815ade02 App游客时正常展示页面 2026-09-02 20:28:59 +08:00
rcx 57312753ed 发 30 2026-09-02 19:52:47 +08:00
rcx 03ce38ed9b 发 30 2026-09-02 19:46:44 +08:00
rcx b09b07978f fix(oms): 出库导入批次分配优化:批次号优先排序、移除归属校验、库存不足统一报错
c1f483f0 出库导入指定仓库功能的迭代调整:

1. 移除物料仓库归属前置校验(countInventoryByWarehouse):物料档案全仓共享、
   不属于任何仓库,仓库约束收敛到批次分配环节——分不到当前仓批次即报库存不足
2. getkcId 增加分配排序:同物料同仓多条可用库存时,有批次号的优先、空批次
   沉底、同组按库存ID(入库先后);此前无排序随机取第一条,会分到无批次号的
   历史脏数据记录
3. 明细仓库编码/名称兜底:部分历史库存记录只存仓库ID未存编码/名称,按ID
   反查仓库表补齐,修复明细仓库只显示ID不显示名称
4. 库存校验改收集式:全部物料批次比较完成后统一报出不足物料清单,原为逐行
   分配时立即抛错,首个不足即中断、后续物料不参与比较
2026-09-02 19:43:48 +08:00
rcx 87dae51a15 fix(bms): 发票列表兼容pageNum/pageNo参数名,修复翻页始终返回第一页;排序补id兜底防翻页重复 2026-09-02 19:31:01 +08:00
rcx 49ab26a8e9 fix(bms): 发票列表条数显示为0,注册MyBatis-Plus分页拦截器使Page生效 2026-09-02 18:33:50 +08:00
rcx c1f483f0a0 feat(oms): 出库导入支持指定仓库,校验物料库存归属并按仓过滤批次库存
背景:物料档案全仓共享,此前导入不区分仓库,批次库存"查到哪条算哪条",单据可能取到其他仓库的库存且主表仓库为空。

1. /parseExcel 新增可选参数 warehouseId(前端随文件提交当前页面仓库;不传保持原有行为)
2. 新增 countInventoryByWarehouse 归属校验:物料在指定仓库无库存记录时统一报错"物料[xx]在当前仓库[名]没有库存记录,无法从该仓库出库"
3. getkcId 批次库存查询增加仓库过滤,明细批次/仓库/入库单号均取当前仓库
4. 导入单主表回填当前仓库 warehouseId/Code/Name(此前导入单仓库为空)
5. 出库导入两个入口(reservationStockInOrderApi/executionStockInOrderApi 的 parseExcel)同步支持
6. 库存不足报错补充物料编码,便于定位
2026-09-02 18:32:12 +08:00
rcx 6d7e42bcde 发 31 2026-09-02 16:55:19 +08:00
rcx 61572c536a 发 30 2026-09-02 16:48:35 +08:00
rcx 572b25ee88 feat(oms): 运输业务单列表新增预计起运时间范围查询条件(layDateStart/layDateEnd) 2026-09-02 16:16:46 +08:00
rcx 3576d734af fix(oms): 出库业务单导入发票编号不落库,补齐繁简归一化「發/額」映射
模板列头「發票編號/金額/發票張數」归一化时映射表缺「發→发」「額→额」,發票編號列识别失败(invoiceNoCol=-1),客户配送明细落库时发票编号为空、查看不回显,金额列与发票张数同样受影响。补齐映射并在关键列缺失时输出告警日志;历史已导入单据需重新导入。
2026-09-02 15:43:07 +08:00
rcx 028af3dd2f fix(wms,oms):出库排名件数改为复核确认的实际出库量(CHECK_QUANTITY),排序同步调整
- 件数取数由明细 PIECE_COUNT(计划/申报件数)改为 SUM(CHECK_QUANTITY) 复核确认的实际出库量,与入库排名的实际上架量 SHELVES_QUANTITY 取数逻辑对称(已验证现有已出库数据 222/222 全覆盖)

- 排序第一键由出库数量(outbound_quantity,下发时的计划复制值)改为件数(实际出库量)降序,出仓日期/单号次之

- 接口路径/传参/返回字段结构均不变,前端无感;其余为注释同步
2026-09-02 15:41:51 +08:00
rcx 3af78d5d7b feat(wms,oms):出库排名统计改造为仓单×货品明细列表,按出库数量降序排名
- 字段:种类/仓单编号/入库单号/客户编号/收货人/货名/线路/件数/毛重(吨)/体积(CBM)/退保总额(占位null,数据来源待确认)/出仓日期

- 商品/线路各一套接口,路径名不变;商品接口忽略线路筛选参数,线路接口忽略商品筛选参数;含合计行(件数/毛重吨/体积/仓单数)与Excel导出

- 统计口径不变:出库单创建时间区间+已出库状态(9,12,13)+明细level=1主行;排序按出库数量(销售量)降序,件数/出仓日期/单号次之

- 数据源:WMS查本库出库表;OMS跨库查NGWL_TEST_WMS同名表(OMS库出库单状态不流转,跨库与WMS端数字一致)

- 删除原按商品/线路聚合的排名接口(销售量/交易数/金额字段)
2026-09-02 15:25:51 +08:00
rcx e821619a96 fix(库存): 修复OMS/WMS库存查询过期日期不回显
根因:业务只在OMS填写饮用日期,且下发DTO无过期日期字段,饮用日期→过期日期的转换仅存在于收货单生成瞬间,后续环节全部丢失。

- InMaterialDetail(DTO) 补充 expiryDate 字段,打通OMS→WMS传递
- 预约单/执行单下发前:过期日期为空时用饮用日期补齐(治本)
- WMS收货批次属性回写:恢复饮用日期回写并兜底转换为过期日期(加固)
- WMS上架确认:过期日期为空时从收货明细兜底补齐(加固)
2026-09-02 15:05:29 +08:00
rcx 434348f972 fix(oms,wms): 出库单下发WMS失败被静默吞掉,修复WMS出库拣货不显示OMS单据
- OMS建单/下发前校验明细数量>0且已关联库存
- OMS检查WMS自动分配/生成拣货单返回值,失败即报错回滚
- WMS自动分配各类失败场景抛带单号的明确异常,替代NPE
- WMS接单幂等保护,失败重试不产生重复数据
2026-09-02 14:32:13 +08:00
rcx 72cb1d8c07 feat(wms): 库存列表接口新增隐藏可用数量为0的参数
/materialInventoryApi/list 新增可选参数 excludeZeroAllocationQuantity,为 true 时排除可用数量=0 的库存行;与已有 excludeZeroInventoryQuantity 组成两个独立开关,不传时保持原有行为。配合盘点-库存选择页隐藏数量为0物料及出库选库存隐藏0库存需求。
2026-09-02 14:04:15 +08:00
rcx f5a7c8c1f3 发 31 2026-09-02 00:12:59 +08:00
rcx 3989d75f05 发 30 2026-09-01 23:50:34 +08:00
rcx 471b515a45 Merge branch 'refs/heads/dev-ty1.2' into dev
# Conflicts:
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/BmsServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/OmsServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/WlhyServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/WmsServiceFeign.java
#	mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/YmsServiceFeign.java
#	mhd-common/mhd-common-core/src/main/java/com/mhd/common/core/feign/ThirdPartyServiceFeign.java
#	mhd_oms/src/main/java/com/mhd/oms/infrastructure/feign/ThirdPartyServiceFeign.java
#	mhd_oms/src/main/resources/bootstrap.yml
2026-09-01 23:49:08 +08:00
rcx 19e897cae0 发 30 2026-09-01 23:02:30 +08:00
rcx 91bdb99ec2 发 31 2026-09-01 22:50:50 +08:00
rcx 004580e252 发 30 2026-09-01 22:36:10 +08:00
rcx da3c58a366 fix(wms,oms):入库排名统计口径修复:件数改为实际上架量SUM(SHELVES_QUANTITY)(原PIECE_COUNT为建档申报值不随收货上架变化);OMS端数据源跨库改查WMS入库表NGWL_TEST_WMS.stock_in_order/in_material_detail(OMS执行单状态不回传且上架量回填代码未启用,与出库排名1300a4e1跨库修法一致),状态恢复为已入库(5);入仓日期为空兜底建档时间;OMS与WMS两端数字一致;接口路径/参数/返回结构不变 2026-09-01 21:36:33 +08:00
赵辉 1cec762930 user30 2026-09-01 17:35:21 +08:00
赵辉 4deaeaa89d user30 2026-09-01 17:22:26 +08:00
赵辉 1208e02fe7 yms租户同步 2026-09-01 17:14:23 +08:00
王奎兴 2c60dc8f84 bms改造; 2026-09-01 16:58:39 +08:00
秦鸿展 77fb71dab4 30 2026-09-01 16:32:33 +08:00
秦鸿展 cd41c616bb 31 2026-09-01 16:30:23 +08:00
rcx a4f27ab643 feat(oms,wms):库存查询导出新增isExport标识与融合排序 /list 新增可选参数 isExport 标识导出请求(导出显示商品饮用有效期/物料分类/进货日期由查询结果直接返回);isExport=true 时所有查询维度(OMS 6条/WMS 8条)统一启用导出融合排序:到期日倒序空值最后(保留原 orderByExpiryDate 第一优先级,融合不取代)→同到期日内按物料编码升序→0库存靠后→更新时间倒序→MAX(库存ID)兜底保证分页稳定;各语句挂载公共片段 exportOrderByMaterialCode,不传 isExport 保持原有排序;OMS Controller 在 isExport=true 时跳过 Java 按更新时间重排避免覆盖 SQL 导出排序 2026-09-01 16:29:41 +08:00
秦鸿展 c174ea8742 单号编辑变化问题,以及组织查询问题 2026-09-01 15:15:53 +08:00
秦鸿展 2bbd6784c4 31 2026-09-01 14:14:51 +08:00
秦鸿展 923afda21c 大屏月台接口查询修改 2026-09-01 14:09:23 +08:00
rcx bb3ca932d2 feat(oms):出入库导入存在性校验改为收集后统一提示(物料+客户不存在的编号一条消息带全)
调整2d1e4b59引入的校验流程(入库parseStockInExcel/出库parseExcelFile统一):
1. 第一步:物料编号存在性校验——逐编号查库,全部不存在的收集到missingMaterials,不立即报错
2. 第二步:客户编号存在性校验——逐编号查库,全部不存在的收集到missingCustomers,不立即报错
3. 第三步:两步全部完成后统一抛出提示,避免修完物料问题重导一次才暴露客户问题:
   只缺物料:"物料[A、B]不存在,请先维护物料信息,维护完成后重新导入"
   只缺客户:"客户[C]不存在,请先维护客户信息,维护完成后重新导入"
   都缺:"物料[A、B]不存在,请先维护物料信息;客户[C、D]不存在,请先维护客户信息,维护完成后重新导入"
4. 存在性全部通过后才继续多货主/多客户编号/客户与货主一致性等校验及建单;
   入库"多个客户编号"校验相应移到存在性之后,多个编号中缺哪个报哪个
5. 入库客户查询结果存入customerCache复用,一致性校验不再二次查库

漏填编号(空白行)仍即时报错,不属于存在性问题,行为不变
2026-09-01 09:53:51 +08:00
rcx a588264849 fix(wms,oms):入库排名统计查询恒为空修复:OMS执行入库单状态不回传(全停status=1)无法按已入库过滤,改为仅排除已取消(6)/已关闭(7)(与入库明细查询页口径一致);入仓日期为空的历史单筛选与展示均兜底建档时间create_time(与出库明细统计口径一致);WMS仍保持仅已入库(5) 2026-09-01 09:24:20 +08:00
rcx 1300a4e1f8 fix(oms):出库排名OMS端数据源改为跨库查WMS出库表,修复查询结果恒为空
OMS库出库单状态从不流转(预约/执行单全部status=1,无"已出库"数据),原SQL按执行出库单status=9过滤导致查不出任何数据;改为跨库取WMS出库表NGWL_TEST_WMS.stock_out_order/out_material_detail(与OMS库存查询跨库join material_base_info同一模式),口径与WMS端/outboundRankApi完全一致:已出库及之后状态(9,12,13)+明细level=1主行+按出库单创建时间筛选,两边页面数字一致;接口路径/参数/返回结构均不变,其余文件仅更新注释中的数据源说明
2026-09-01 09:10:59 +08:00
rcx bf96f5f005 feat(wms,oms):库存管理新增入库排名统计(按仓单+货品汇总,件数降序,与出库排名tab配对);还原出库排名第一版源码
入库排名统计(新增):WMS /inboundRankApi、OMS /executionInboundRankApi 的 queryMaterialRankList 分页+合计、exportMaterialRank 导出;口径:仅已入库(status=5),明细仅level=1主行,日期区间按入仓日期warehouse_date筛选(必填);一行=仓单内某货品合计(GROUP BY 仓单+货品 ORDER BY 件数DESC);字段:入仓日期/仓单编号/客户编号/存货人/货名/件数/毛重(吨=KG/1000)/投保总额(货品档案保额,组内MAX防重复累加)/体积(CBM)+货号/规格/单位;合计行:totalPieceCount/totalGrossWeightTon/totalInsureAmount/totalVolume/totalOrderCount;登录上下文:日期必填校验+topOrganizationId租户隔离,WMS另注入关联仓库warehouseId。出库排名统计(还原第一版):/outboundRankApi、/executionOutboundRankApi,按货品/线路汇总排名
2026-08-31 17:47:09 +08:00
rcx a983ae639e fix(wms,oms):物料/过期日期查询补查入库日期(create_time)与更新时间,分组页签入库日期显示为空 2026-08-31 15:59:54 +08:00
rcx a74afd837c feat(oms):入库业务单新增页面新增按物料编号查询库存批次最近5条过期日期接口 /reservationMaterialInventoryApi/queryRecentExpiryDates/{materialCode},按物料编号关联 NGWL_TEST_WMS.material_base_info 查 reservation_material_inventory 库存批次,返回过期日期+批次号(date_format 按天去重、到期日倒序、limit 5),供前端下拉回显(也可点日期图标手动选择);非平台租户按登录用户一级组织 top_organization_id 过滤(与 /list 一致);沿用 Api→ApplicationService→DomainService→Facade→Impl→Mapper 分层,新增响应对象 MaterialInventoryExpiryBatchPO(expiryDate/batchNumber) 2026-08-31 15:22:59 +08:00
rcx bc3afbacb1 feat(wms,oms):物料分类:库存列表返回增加 materialClassifyCode/Name 显式映射
(ListTypeHandler,数据关联 material_base_info 带出)
2026-08-31 13:58:02 +08:00
rcx 5ba6a3b73d 发测试 2026-08-31 13:43:11 +08:00
rcx da84b7bb69 feat(wms,oms):库存管理-库存查询新增进货日期、入库日期查询条件,新增进货日期字段贯通收货-上架-库存全链路
需求:OMS/WMS 库存管理-库存查询页增加查询条件:物料分类(后端已支持,无需改动)、
进货日期(新增字段)、入库日期。

一、DDL(sql/20260831_wms_oms_add_purchase_date.sql)
    WMS 收货明细、上架明细、物料库存及 OMS 预留库存共 4 张表新增 PURCHASE_DATE DATE 列,
    附批次明细配置模板、执行前检查与回滚语句;须先执行 DDL 再发布服务。

二、进货日期录入与落库链路(收货→上架→WMS库存→OMS库存)
    1、录入入口为收货批次属性「进货日期」标签(批次规则配置,标签须一字不差),
       ReceiptMaterialDetailImpl 两处标签解析新增分支;
    2、收货明细→上架明细:StockReceiptOrderDomainService 6 处日期拷贝点补 setPurchaseDate(含子项);
    3、上架落库:stockIn/sj 赋值写入 material_inventory;
    4、同步 OMS:MaterialInventoryOmsParamDO 新增字段经 Feign omsEdit 传递,
       写入 reservation_material_inventory;
    5、库存行合并键:批次规则勾选后进货日期参与分行(getParam 映射 + selectListByWhere 全等匹配),
       OMS omsEdit 行匹配同步按进货日期区分,避免不同进货日期误合并到同一行。

三、查询条件(两模块 /list 接口)
    1、进货日期:purchaseDate(单日精确)+ purchaseDateStart/purchaseDateEnd(区间,End 含当天);
    2、入库日期:WMS 新增 createTimeStart/createTimeEnd(按库存行创建时间过滤,与 OMS 现有口径一致);
    3、列表/导出返回新增 purchaseDate 字段,分组查询取 MAX(purchase_date)。

说明:历史库存进货日期为空,按进货日期查询查不到存量数据(无来源可回填),区间查询会排除空值行。
2026-08-31 13:41:19 +08:00
rcx 2d1e4b5912 feat(oms):出入库导入按编号自动匹配名称并校验客户/物料存在性,模板列位改为动态识别
需求:①入库业务单导入模板只填物料编号+客户编号,物料名称/客户名称按编号自动匹配库中数据
②③出库导入校验客户/物料是否已存在,不存在提示"进行维护" ④库中查询结果为空(确无数据)时报错

一、入库导入(ReservationStockInOrderImpl.parseStockInExcel):
1. 物料逐编号查库,缺失料号收集后一次性报错"物料[xx]不存在,请先维护物料信息后再导入"
2. 明细新增客户编号:去重后查库,为空报错"客户[编号]不存在,请先维护客户信息后再导入";
   查到则以该客户为单据货主并自动匹配名称;与物料归属货主不一致时拦截并提示两者编号
3. 明细回填库中物料名称;未填客户编号时维持原"货主取自物料"逻辑,兼容老模板

二、出库导入(parseExcelFile):
1. 物料/客户校验前移到落库前(原为先落库后查客户,报错会留半截数据)
2. 物料查不到收集后报错维护提示;客户查不到报错维护提示,客户ID/名称改取库中匹配值
  (替换仅返回id且查不到时静默存null的queryShipperId)
3. 產品編號/客户編号漏填的行直接报错提示补全

三、模板解析改为按列头文字动态定位列(繁简体归一化),列/行顺序调整不影响解析,
   识别不到时回落老模板固定列位,老模板行为不变:
1. StockInExcelListener(入库):以產品編號为锚点识别列头行,新增客戶編號列支持
2. DynamicDeliveryExcelListener(出库):左右分栏各自锚点识别;送货日期/线号/车次/
   发票张数/小计/纪录合共改按标签文字定位,行号列号不再写死

四、Mapper:ReservationStockOutOrderMapper新增queryCustomerByCode(按组织查询,
   USER_MEMBER_CODE或USER_SHIPPER.CUSTOMER_NC_CODE任一命中),删除queryShipperId
2026-08-31 11:15:41 +08:00
rcx 2781f0d8d9 feat(oms):库存查询导出新增库存为0是否导出参数 /reservationMaterialInventoryApi/list 新增可选参数 excludeZeroInventoryQuantity,前端"库存为0是否导出"选"是"时传 true,SQL 以 HAVING IFNULL(SUM(inventory_quantity),0)>0 排除汇总库存为0的数据;所有查询维度(all/hz/wl/kw/wlkw/wlExpiry)共6条查询在 GROUP BY 后统一挂载公共片段 excludeZeroInventoryHaving,与 sort_order 对0库存的定义保持一致;不传参数时 SQL 不拼接条件,行为与原来完全一致 2026-08-31 10:17:53 +08:00
王奎兴 8a9bbb3cef 本地配置 2026-08-31 09:33:58 +08:00
rcx 155f1866b4 feat(system):库区管理新增库区面积合计查询接口
新增 GET /storageSectionApi/sumStorageRegion,与库区列表 /list 相同筛选条件及组织数据权限,
SQL 端 IFNULL(SUM(storage_region),0) 返回面积合计(平方米),无数据返回0;
抽取 queryList 数据权限为 applyQueryDataPermission 供列表与合计共用,/list 行为不变。
2026-08-28 18:01:44 +08:00
王奎兴 d4446e8482 发30 2026-08-28 17:35:43 +08:00
王奎兴 3349552e10 结算对象改造; 2026-08-28 17:32:02 +08:00
秦鸿展 254a804a17 30 2026-08-28 17:10:05 +08:00
秦鸿展 4c4b8f4e29 大屏月台接口只查询预约日期是当天的 2026-08-28 17:06:28 +08:00
zhaoqing 06cf5ce861 fix(oms):明细表修改 2026-08-28 16:22:28 +08:00
rcx 7a01315ca8 feat(sys):导出字段优化与前端显示保持一致 2026-08-28 16:17:48 +08:00
rcx d0773a40d2 feat(transport):基础数据-运营数据-车辆管理增加导出功能
新增 /vehicle/export 导出接口(GET/POST,兼容前端 download 工具),
复用列表查询条件与数据权限,不分页导出全量数据为 xlsx;
新增 VehicleExportVO 导出对象(40列,状态字段转中文)。
2026-08-28 16:12:56 +08:00
rcx 6349181cc3 feat(sys):费用科目导出增加新vo对象
新增 ExpenseAccountExportVO 导出对象(27列业务字段)
2026-08-28 09:20:11 +08:00
rcx e95feb5c24 Merge branch 'refs/heads/dev' into dev-ty1.2 2026-08-28 09:15:39 +08:00
rcx afa502eeaf feat(system):仓库管理-库位管理新增复制功能
需求:库位管理列表增加复制功能,快速复用已有库位配置新建库位。
实现(仿照bms复制账单copyBill的回显式复制):
一、新增接口 POST /storageLocationApi/copyStorageLocation(StorageLocationApi):
    id判空+try-catch兜底,异常返回"复制库单失败:xxx"
二、StorageLocationApplicationService新增copyStorageLocation:
    取原库位PO后清空唯一性字段(storageLocationId不清空会误走修改分支覆盖原库位、
    storageLocationCode同组织同仓库唯一须用户重填、locationBarCode物理唯一)、
    清空审计字段(提交时Assembler按登录人重写)、状态重置初始值
    (status=1空/openingUp=1启用/nullify=1未作废);其余业务字段保留回显
三、前端拿PO回显到新增页,用户改编码后走现有edit接口(id为空即新增)提交,
    天然复用编码唯一性校验、仓库/库区/库位组回填、库位组计数+1,Domain层零改动
2026-08-28 09:14:03 +08:00
rcx 627376da07 feat(sys):费用科目增加复制、导出功能
1、新增 POST /expenseAccountApi/copy 复制接口(回显式,清空主键及科目编码)
2、新增 GET/POST /expenseAccountApi/export 导出接口(按列表查询条件+数据权限全量导出)
3、新增 ExpenseAccountExportVO 导出对象(27列业务字段)
2026-08-28 09:13:10 +08:00
rcx 5127123236 发31 2026-08-27 16:38:33 +08:00
rcx 7b0d08a132 发30 2026-08-27 16:33:43 +08:00
zhaoqing ccdbbda165 Merge remote-tracking branch 'origin/dev' into dev-ty1.2 2026-08-27 14:27:16 +08:00
zhaoqing e3058d8eb1 fix(oms):明细表修改 2026-08-27 14:24:58 +08:00
rcx 5e3a0d86d0 发测试 2026-08-27 14:21:23 +08:00
rcx 76d95c1b2d feat(oms):入库业务单导入模板OrderNO改为只作业务单号,去掉格式校验并按业务单号查重
需求:导入模板表格OrderNO值回显到字段"业务单号";"入库业务单号"仍由系统
原本逻辑生成;业务单号重复不允许导入并提示"业务单号已存在";模板未填单号
保持现有系统逻辑;业务单号去掉规则校验。
一、导入流程(ReservationStockInOrderImpl.parseStockInExcel):
   1. 模板OrderNO只写入业务单号(business_order_no),不再同时作为入库业务单号
   2. 删除validateTemplateOrderNo格式规则校验(R+年月日+3位序号),模板单号不再限格式
   3. 查重由按in_order_number跨两表改为按business_order_no查入库业务单表,
      Mapper新增existsByBusinessOrderNo;重复时报"业务单号已存在:xxx,请修改
      模板中的OrderNO后重新导入"
   4. 入库业务单号(in_order_number)统一由insertDomain按原逻辑生成
      (R+年月日+当日累加,跨reservation/reserve两表取号防撞)
二、insertDomain业务单号赋值改为仅在为空时默认=入库单号,导入带模板单号时不覆盖;
   模板未填单号保持现有逻辑。页面手工新增(DomainService.insert)与客户预约下发
   (ReserveStockInOrderDomainService)为独立链路,不受影响。
2026-08-27 14:10:38 +08:00
秦鸿展 e4b29858a4 南岐GPS三方接口对接 2026-08-27 13:58:10 +08:00
rcx f1dec2298d 发 31 2026-08-26 18:04:44 +08:00
rcx 7b52764ae1 发 30 2026-08-26 17:52:23 +08:00
rcx 1006860698 Merge remote-tracking branch 'origin/dev' into dev-ty1.2 2026-08-26 17:32:40 +08:00
王奎兴 1e00681289 恢复
xxl-job
2026-08-26 17:28:50 +08:00
rcx 353300b643 feat(wms):出入库导入增加料号与规格型号/SKU码一致性校验
- 按料号查物料档案后逐项比对,任何一项不符直接报对应错误:规格型号/SKU码必须与档案完全一致(trim后比较)
- Excel留空而档案有值、或Excel填值而档案为空,均视为不一致报错(提示Excel:空/档案:空)
- SKU码以档案条码(bar_code)为比对基准;出库料号已填写但货主下查不到时直接报错,不再被SKU码/商品名称静默兜底(与入库对齐
2026-08-26 16:56:27 +08:00
rcx 9eb2f347f7 发测试 2026-08-26 15:55:03 +08:00
rcx 182438e1dc fix(system): 费用科目getInfoByOrgAndCode计费单位中英文均为null时过滤,避免返回null-null 2026-08-26 15:49:58 +08:00
rcx 0be73e9bfe fix(oms): 出入库联合列表(inAndOutList)查询条件修复与补全
1. 修复 ReflectionException:mapper XML <if> 引用 inOrOut/orderNumber 但 DO 无对应字段,
   DO/DTO 新增 inOrOut、orderNumber 查询字段(BeanUtils 同名自动拷贝,前端参数直达 mapper)
2. inOrOut 排除空串与 'all'(前端"全部"约定值),避免拼出 ="all" 查空
3. orderNumber 排除空串并改为 like 模糊匹配(与出库单列表单号搜索口径一致)
4. status 新增精确筛选(0 为有效条件值,按前端约定直传,"全部"时不传)
2026-08-26 15:49:38 +08:00
秦鸿展 5e369bdd99 31 2026-08-26 14:23:36 +08:00
王奎兴 a5a222a78e Merge branch 'dev' into dev-ty1.2
# Conflicts:
#	mhd-modules/mhd-system/src/main/resources/bootstrap.yml
2026-08-26 14:11:45 +08:00
王奎兴 b1840c8965 Merge remote-tracking branch 'origin/dev' into dev 2026-08-26 14:08:38 +08:00
王奎兴 02a0b7aab6 xxl-job 2026-08-26 14:08:24 +08:00
rcx 42ab5160ed 发30 2026-08-26 14:03:42 +08:00
秦鸿展 df66287455 31 2026-08-26 12:55:44 +08:00
秦鸿展 e2ce186aba 30 2026-08-26 12:49:16 +08:00
秦鸿展 9be0de0ae7 园区月台预约车辆显示修改 2026-08-26 12:48:06 +08:00
rcx 4410162f39 发测试 2026-08-26 10:03:46 +08:00
rcx 3060fcd6a4 feat(product):新增附件原始文件名字段SQL并去掉上传错的文件 2026-08-26 09:53:19 +08:00
rcx 7d8e1c3872 feat(wms):复核详情增加合计数;库存分配新增通宇专用可分配库存查询(物料+箱号/卡板+Sheet Ref匹配
1. 复核详情(getInfo/getInfoReviewOrderNumber)头表回填totalReviewedQty/totalPlanQty/materialKindCount,
   口径与列表queryList聚合一致(计划量=Σifnull(material_plan_qty,pending+reviewed))
2. 新增 GET /materialInventoryApi/assignableList,按通宇账号分流(TongyuOrgUtil:组织ID=2830或组织名含"通宇"):
   - 通宇:启用新匹配。双模式入参——传outOrderId+materialDetailId(须成对)则匹配值全部后端自取出库单/明细;
     不传则按平铺参数(materialBaseInfoId/materialCode+boxPalletNo+sheetRefNo,多值串自动拆token OR-LIKE)。
     固定条件:del_flag=1且可分配数量(allocation_quantity)>0,不分页全量返回,不套用用户组织数据权限
   - 非通宇:保持原/list行为,内部直调list();进原查询前清除materialDetailId(新接口专用参数,防泄入
     原查询的a.material_detail_id=上架单明细ID条件导致查空)
3. autoAssign自动分配同步分流:通宇走token匹配,非通宇保持原eq精确匹配不变
4. 新增util/BatchNoTokenUtil(批次属性多值拆分)、util/TongyuOrgUtil;库存批次属性回填抽为
   fillBatchAttributes供/list与可分配查询复用,原逻辑行为不变
2026-08-26 09:30:01 +08:00
秦鸿展 59249be9b0 31 2026-08-26 00:06:41 +08:00
秦鸿展 8fe5e079dd 新增月台预约楼层车辆查询 2026-08-26 00:01:40 +08:00
秦鸿展 d1d55ce52a 30 2026-08-25 23:00:55 +08:00
秦鸿展 b12517e5b5 30 2026-08-25 22:28:57 +08:00
秦鸿展 09d24217b5 统计业务类型 2026-08-25 22:25:12 +08:00
秦鸿展 3c2f252347 统计业务类型 2026-08-25 22:23:18 +08:00
秦鸿展 940e4c56b0 31 2026-08-25 20:24:10 +08:00
秦鸿展 09ab103d1d 30 2026-08-25 20:18:31 +08:00
秦鸿展 8dcb2334d5 BI月台数据改造 2026-08-25 20:11:52 +08:00
rcx 7a5e124f98 fix(oms): 入库模板导入优化异常提示信息 2026-08-25 17:51:54 +08:00
rcx c5a2508a36 发测试 2026-08-25 16:29:15 +08:00
rcx 7353021d92 feat(oms):入库模板导入支持模板自带业务单号,重复拦截并按R+年月日规则生成
1. 模板OrderNO解析兼容无标签新模板(E1直接为单号值)
2. 导入单号优先模板自带:先校验R+年月日+3位序号格式(含年月日有效性),
   再跨reservation/reserve两表查重,重复提示"入库业务单号已存在"
3. 模板无单号时按R+年月日+当日累加生成(insertDomain不再无条件覆盖已设置单号,清理无效的仓库规则生成死代码)
2026-08-25 16:11:19 +08:00
rcx 735cf9af9f feat(oms):入库导入模板饮用日期解析修复,入库单列表联查带出饮用有效日期
1. 入库/执行入库Excel解析监听器:扩充日期格式支持(yyyy年M月d日、d/M/yyyy、M/d/yyyy、dd.MM.yyyy等16种),
   改为严格解析防止宽松解析产生公元1~99年脏数据,新增Excel日期序列号兜底及年份合理性校验,
   解析失败抛出带行号的明确提示而非静默置空
2. parse-excel接口异常时返回具体错误信息(原为空body 500)
3. 入库单列表queryList联查明细表取最早饮用日期(MIN drink_date),PO及resultMap补drinkDate映射
2026-08-25 15:07:04 +08:00
秦鸿展 f2f3fb9c19 30 2026-08-25 11:09:23 +08:00
秦鸿展 a62ed7c60f 31 2026-08-25 11:05:06 +08:00
王奎兴 4168f921f6 查询nc日志排序修改; 2026-08-25 10:52:28 +08:00
王奎兴 1916152775 查询委托方去除组织条件; 2026-08-25 10:41:58 +08:00
rcx 83f4cce451 feat(oms):App端出入库明细跳详情补入库按单号查询,预约单修改限待提交状态
需求:入库/出库明细列表点击跳详情;待提交预约单可修改(暂存/提交均走/edit,与PC共用链路)
1.ReserveStockInOrderApi新增getInfoByInOrderNumber按单号查详情:
  入库明细行只带inOrderNumber(明细表无in_order_id列),对齐出库侧getInfoOutOrderNumber;
  del_flag=1过滤已删单+getOne不抛单号重复
2.ReserveStockInOrderMapper.xml MaterialDetailResult显式映射in_order_number,
  明细行单号不再依赖驼峰自动映射开关(出库侧:363本就有,入库侧补齐)
3.入库/出库DomainService.update加状态闸门:仅status=1(已创建)且issueStatus!=3(未确认)允许修改,
  防已确认下发/已流转单据被改写(仓码确认只置issueStatus=3不改status,原校验缺此维度必然漏防);
  明细为空改报'请添加货物明细'(原getMaterialDetailList().size()空指针500);出库update补@Transactional
2026-08-24 18:12:50 +08:00
王奎兴 f5f792d3f8 发31 2026-08-24 17:03:55 +08:00
王奎兴 dbd61c0519 发30 2026-08-24 16:58:26 +08:00
王奎兴 cb5d933e0a 渗透测试修改; 2026-08-24 16:53:20 +08:00
王奎兴 5298e9d4e3 发30 2026-08-22 19:35:56 +08:00
王奎兴 06f61d7957 发31 2026-08-22 19:32:52 +08:00
王奎兴 4567f00858 发测试 2026-08-22 18:46:36 +08:00
rcx e8328b0159 Merge remote-tracking branch 'origin/dev' into dev 2026-08-22 18:39:12 +08:00
rcx bb3dfaed4a fix(oms):出库业务单线路/车次同步运输业务单,补齐触发入口与拆单时序
出库业务单与运输业务单为两张独立表,仅靠发票号经配送明细关联,
此前无字段同步逻辑,出库单填写的线路/车次不会流到运输业务单。

1. ReservationStockOutOrderDomainService新增syncLineInfoToBusinessOrder:
   按关联链 出库单号->reservation_delivery_details_link.invoiceNumber
   ->business_delivery_details_link.invoiceNumber 定位关联业务单,
   以出库业务单为源头覆盖lineCode/lineName/shuttleNo。
2. 触发入口三个:审核通过(auditState)/下发(issueOrder)/执行并下发
   (executeAndIssue);取消下发不触发。下发与执行并下发不经过审核
   动作,只挂审核入口会漏同步。
3. 同步目标同时覆盖orderId(未拆单业务单/拆单后主单)与subOrderId
   (拆单子单):仅同步subOrderId时,出库先审核而运输单尚未拆单
   (subOrderId为空)会落空,且主单无值导致后续拆单子单拷贝不到。
4. 同步失败仅记error日志,不阻断审核/下发主流程
   (状态更新与同步非同一事务,关联数据异常不应导致接口报错)。

边界:运输业务单手工创建且未录配送明细时无关联链不同步,需页面自行
填写;关联依赖发票号两侧一致,与既有退货回写为同一关联假设。
2026-08-22 18:38:39 +08:00
王奎兴 0eb2f323c7 发31 2026-08-22 18:29:36 +08:00
王奎兴 a35030e2f5 登录报三方异常处理; 2026-08-22 18:27:56 +08:00
王奎兴 d1b1b27ab0 发30 2026-08-22 17:46:47 +08:00
王奎兴 4a6a2798e8 发31 2026-08-22 17:36:27 +08:00
rcx 9068fa0e40 feat(wms):WMS出库单增加线路车次字段,App出库单详情显示线路/车次
背景:App出库单详情调wmsApi/stockOutOrderApi/getInfo,数据在WMS
stock_out_order表,该表未加线路/车次字段导致不回显。

1. mhd-api StockOutOrder(OMS下发Feign DTO)加lineCode/lineName/shuttleNo,
   OMS执行单下发为copyProperties同名拷贝,自动透传,OMS代码零改动。
2. WMS stock_out_order表加三列(脚本追加);entity/PO加字段,
   Feign接收按JSON字段名对齐落库;Mapper XML resultMap与显式列清单补列,
   getInfo(getById自动)与列表均可返回。
3. 部署需重新打包mhd_oms与mhd_wms(OMS依赖的mhd-api jar变更)。
   存量已下发WMS的老单无值,OMS/WMS跨库无法批量刷数,新下发单自动带。
2026-08-22 17:23:48 +08:00
rcx 99cb355640 发测试 2026-08-22 16:50:12 +08:00
rcx c9520c65be feat(wms):上架默认库位填充限定谷丰组织(id=2842)生效 2026-08-22 16:38:18 +08:00
rcx 2a4e39f755 Merge remote-tracking branch 'origin/dev-ty1.2' into dev-ty1.2 2026-08-22 14:10:07 +08:00
rcx a08d8a7fd5 feat(oms):出库导入校验送貨線號/車次并回填线路名称
1. 出库导入(预约/执行两侧)增加validateLineAndShuttle校验:
   送貨線號/車次缺失直接报错;线路须在WMS线路管理存在(route_code精确匹配);
   车次须在该线路车次清单(shuttle_json)内;校验通过回填lineName,
   线路/车次一并落lineCode/lineName/shuttleNo。
2. WmsServiceFeign新增listLineManagement(复用WMS /lineManagementApi/listByApp)
   供OMS跨库查线路,附降级实现;顺带移除FeignClient写死的本机url,恢复Nacos服务发现。
3. 执行侧DynamicDeliveryExcelListener(关键字版)补送貨線號/車次独立成行的解析,
   原实现仅支持与送貨日期同行取值,该模板为分行布局导致解析不到。
2026-08-22 14:08:22 +08:00
rcx ab7219e600 feat(wms):上架管理PC上传页默认填充指定上架库位(维他奶仓→2层冷凍A區A01),仅回显不落库 2026-08-22 14:06:56 +08:00
王奎兴 1b3b1a6394 Merge branch 'dev' into dev-ty1.2
# Conflicts:
#	mhd_wms/src/main/resources/bootstrap.yml
2026-08-22 13:59:22 +08:00
王奎兴 072a4f7d1f 退货验证发票号是否重复;维他奶导入单号添加校验; 2026-08-22 11:17:42 +08:00
王奎兴 63a19fbbcd 退货入库单编辑后才显示数量; 2026-08-22 10:26:54 +08:00
rcx 5fc491f612 fix(oms,wms):执行单重复下发致WMS收货明细翻倍修复,executeAndIssue获取仓库信息失败修复
一、收货明细翻倍(executionStockInOrderApi/issueOrder下发后,WMS收货管理详情明细×2):
根因:执行单下发接口无防重 + WMS接收端无幂等。executeAndIssue已自动下发过的执行单
仍可被手动再次下发(issueTime已置但无校验),重复推送使WMS插入同号入库主单+第二份
in_material_detail,再生成第二张同号收货单(收货单号"RV-"+入库单号确定性生成),
收货管理详情按单号查明细即双倍。四层防御:
1. OMS执行单issueOrder补防重:issueTime非空拒绝下发(与executeAndIssue对齐),
   inOrderIds去重防同请求重复推送
2. WMS omsOrderAdd主单幂等:同单号有效单(del_flag=1)已存在则跳过插入
3. WMS omsOrderAddDetail明细幂等:按oms_in_material_detail判重,已存在行不再插入;
   未传ID的行保持原插入行为
4. WMS autoAuditOmsInOrder取单补orderByAsc(in_order_id)消除同号取单随机性;
   auditApprove生成收货单前按收货单号查重过滤,已生成过的单不再重复生成
二、executeAndIssue报"获取仓库信息失败":
1. 明细行warehouseId=0时兜底改用主表仓库(与下发issueOrder兜底逻辑对齐),
   不再拿无效仓库ID调system服务
2. executeAndIssue/issueOrder两处报错增强为带仓库ID与错误信息,便于定位
存量已翻倍数据(重复入库单/明细/收货单)需另行软删清理,本次仅防新增
2026-08-21 18:21:03 +08:00
rcx b209d8cb6d fix(oms):出库明细materialBaseInfoId自动纠正,杜绝脏物料ID落库
问题:客户端推单把materialInventoryId传进materialBaseInfoId字段(或漏传为0),
出库明细存脏ID,编辑/保存报"物料基础信息不存在"(如DCCK034存了库存ID477/444,
真实物料ID应为233/231)。预约端校验原先静默跳过,脏数据持续入库(7-15起200+行)。

一、新增MaterialBaseInfoResolveService三级解析:
    baseId直查 → 库存ID反查纠正 → 物料编码+组织兜底,全部失败返回null
二、三处setMaterialDetailInfo改为纠正+回填(预约/业务/执行出库单):
    查不到抛错带定位信息(baseId/库存ID/物料编码/单号);
    纠正后的ID随保存落库,旧脏单重新保存即自愈;
    预约端由静默跳过改为抛错
三、两处pushOutOrderDetail推送入口(预约/业务)加纠正,
    反查不到拒绝保存,脏数据不再入库

注:存量脏数据修复SQL另行手动执行;下发复制链(预约→业务→执行)不走校验,
2026-08-21 18:20:22 +08:00
rcx 06aae196c7 发测试 2026-08-21 16:59:56 +08:00
rcx e91c5801eb 发测试 2026-08-21 15:54:46 +08:00
rcx 8704df738c Merge remote-tracking branch 'origin/dev' into dev-ty1.2 2026-08-21 15:47:44 +08:00
rcx 000092952f feat(oms,wms):出库/运输单据增加线路车次字段,线路管理支持车次清单维护
1. OMS四张表(business_document_order/execute_order/
   reservation_stock_out_order/execution_stock_out_order)加
   LINE_CODE/LINE_NAME/SHUTTLE_NO三列,entity/DO/DTO/PO同步加字段,
   出库两链路Mapper XML补列与resultMap。
   线路编码/名称冗余存line_management的route_code/route_name
   (两库不互通无法join);SHUTTLE_NO为字符串(如4或31-4),
   前端拼"编码-车次"显示(31-4车次);不复用route(存tms_route.id)
   和train_no(入库链路占用)。
   下发链路(预约单->执行单,业务单->执行单)同名拷贝自动透传。
2. WMS line_management加SHUTTLE_JSON列(车次序号JSON数组),
   四层加字段+XML;DTO加反序列化器兼容前端传数组,
   PO加序列化器返回原样输出数组。
3. LineManagementImpl.update组织/仓库名称空串兜底,
   修复编辑线路后组织名称被刷成空串、列表查不到的问题。
4. 新增建表脚本sql/20260820_oms_outbound_transport_add_line_shuttle.sql(达梦语法)。
2026-08-21 15:28:50 +08:00
rcx 22f2b66ffa feat(oms,wms):库存导出按到期日分组排序并合并同物料同到期日库存(仅wlExpiry查询生效)
需求:库存查询导出按商品到期日分组归类、相同到期日相邻显示,相同物料相同
到期日合并库存。仅在 queryRule=wlExpiry(物料+到期日汇总查询)导出时生效,
列表显示不变;同时回退 8fedb6d6 对列表默认排序的改动。

一、列表默认查询还原(回退 8fedb6d6):OMS queryList 恢复 order by a.update_time desc,
    Api 恢复 update_time 内存重排(空值最后),两侧列表排序与改动前一致。
二、导出排序(OMS/WMS queryListByWlExpiry):/list 新增可选参数 orderByExpiryDate,
    仅 queryRule=wlExpiry 时生效:
    1. wlExpiry + orderByExpiryDate=true(导出):到期日倒序(日期近的在前)、空值最后、
       0库存靠后、同到期日按更新时间倒序;排序在SQL层,跨页/全量导出分组不被打散;
       OMS Api 传参时跳过 update_time 内存重排,避免覆盖SQL排序
    2. 仅 wlExpiry 不带参数:排序保持原样(sort_order+更新时间倒序)
    3. 其他查询方式:不受影响,参数被忽略
三、合并:wlExpiry 查询 GROUP BY 物料+到期日+货主(货主隔离),相同物料相同到期日
    合并一行,库存/可用/冻结数量及净重/毛重/体积/面积 SUM 汇总(复用现成查询,未改)
四、前端导出:/list + queryRule=wlExpiry + orderByExpiryDate=true + 当前查询条件(不分页)
2026-08-21 15:13:28 +08:00
rcx 3aec384ba0 fix(wms):出库委托单导入出仓日期丢失、升列与单价回填修复
- HeaderListener:parseDate升级为parseDateSmart,兼容Excel日期序列号(20000~60000≈1954~2064年,
  POI DateUtil.getJavaDate转换)及yyyy/M/d、yyyy.M.d、yyyy年M月d日等多格式文本;
  出仓日期/完成时间/下单日期三处调用点同步切换;解析失败记入dateParseErrors不再静默
- ExcelParseService:导入校验汇总dateParseErrors,日期单元格有值但格式不识别时阻断导入并
  明确提示(为空仍放行,与原行为一致);单价回填从料号分支移至料号/SKU/名称三分支统一回填块,
  补齐SKU、商品名称匹配场景
- ItemListener:升列新增normalizeNumeric归一化,去千分位逗号、空值统一存null、纯数字去尾零,
  落库值恒为"纯数字或null",前端合计不再产生NaN/拼接
2026-08-21 14:56:12 +08:00
rcx 27f3fceb6e feat(wms):出入库导入增加料号与规格型号/SKU码一致性校验
- 料号命中物料档案后:规格型号/SKU码必须与档案一致,Excel留空且档案有值同样报错(提示Excel:空);档案值为空则跳过该项
- SKU以档案条码(bar_code)为基准;错误行一次性汇总提示,拒绝导入
- 出库料号已填写但货主下查不到时直接报错,不再被SKU码/商品名称静默兜底(与入库行为对齐)
2026-08-21 14:42:25 +08:00
王奎兴 3e5ed28d69 发30 2026-08-20 18:14:37 +08:00
王奎兴 78d40d35be 发31 2026-08-20 18:13:30 +08:00
rcx 8fedb6d6ed feat(oms):库存查询/导出按商品到期日分组排序 2026-08-20 17:54:23 +08:00
王奎兴 b8de1c00eb 发31 2026-08-20 17:41:09 +08:00
王奎兴 bf080609fe 发30 2026-08-20 17:39:44 +08:00
王奎兴 b415ed6fa0 出库预约业务类型查询; 2026-08-20 17:34:43 +08:00
王奎兴 694ed699ec 单号生成规则包含已删除; 2026-08-20 17:26:56 +08:00
王奎兴 0b26692a34 发31 2026-08-20 15:35:31 +08:00
王奎兴 c2af421c7f 发30 2026-08-20 15:31:40 +08:00
王奎兴 57f87baf85 发30 2026-08-20 15:30:59 +08:00
王奎兴 e23edadde6 发30 2026-08-20 14:59:53 +08:00
王奎兴 530254e000 发31 2026-08-20 14:57:14 +08:00
rcx 33d085f9b9 fix(oms):入库链路计划数量翻倍修复
明细batchUpdate软删条件缺陷(入/出库共6个明细实现类):软删旧明细要求本次提交
   至少一行走更新分支,"删光旧物料全部换新物料"时提交列表全为新增行,旧行漏软删
   (del_flag仍=1),下发后执行单计划数量=旧+新叠加。改为库内有明细即对账软删
2026-08-20 14:45:13 +08:00
王奎兴 21fcc24e2e 发31 2026-08-20 14:20:07 +08:00
王奎兴 64350f565b 列表查询id不对; 2026-08-20 14:16:23 +08:00
rcx ff2b1965f7 fix(oms):入库业务单单号重复与入库链路计划数量翻倍修复
一、单号重复:业务单与客户预约两套取号计数器互不可见致撞号。
取号统一为跨两表MAX+1+存在性校验,保存前校验预取号占用,下发不再换号,Mapper新增existsByOrderNumber。
二、计划数量翻倍:编辑明细为软删(del_flag=2留存),下发查明细未过滤del_flag,
软删行被复制进下游单据并计入头表数量(执行单数量≈业务单×2+修改差值)。
1. 预约→业务单下发、执行单推WMS:明细查询补del_flag=1过滤
2. executeAndIssue(执行并下发):补防重复下发校验(issueTime非空拒绝)
3. pushInOrder/pushInOrderDetail:加幂等,防Feign重试插重复单
2026-08-20 14:06:50 +08:00
王奎兴 7a769071e4 发30 2026-08-20 10:48:34 +08:00
王奎兴 b05f994e74 发31 2026-08-20 10:35:34 +08:00
rcx ef13d890be fix(oms):入库执行单列表单号搜索查不到,businessNumber死条件改单号模糊互查;库存查询货主过滤移回主表并修正委托方误判
- 入库执行单列表:businessNumber条件原为BUSINESS_NUMBER精确等值,该列无写入恒空致全条件查询0条,改为业务单号/入库单号OR模糊互查

- 入库执行单列表:inOrderNumber精确等值改模糊like;删除重复的createByName条件;补businessInOrderNumber过滤(业务单号/入库单号互查)
- 库存查询:货主过滤(shipperId/Code/Name/shipperInfo)从物料表b移回库存主表a,避免LEFT JOIN退化INNER JOIN丢行
- 库存查询:委托方判定由组织层级改为UserPo.shipperEnterpriseName,避免二级组织运营人员(2841/2842)被误判强制按本人userId过滤
2026-08-20 10:17:16 +08:00
rcx cc943d164b fix(wms):入库单导入表头字段错位、备注丢失
- 取值向右查找时误把下一个标签/选项说明当值(承运方←Tel:、生产商←客户名称:、监管方式←送货地址:、送货地址←查验选项),现遇疑似标签即停止查找
- 备注:xxx同格书写为全角冒号,原仅按半角:拆分导致备注丢失,现全角/半角兼容
- 表头列遍历上界改用getLastCellNum,防空单元格漏扫尾部列"
2026-08-20 10:06:50 +08:00
王奎兴 624b7d7d6e 发测试; 2026-08-20 09:05:10 +08:00
王奎兴 0b61b813a5 Merge branch 'dev' into dev_820 2026-08-20 09:03:05 +08:00
rcx 77420e9617 feat(sys):合同附件增加原始文件名存储字段,配合上传v2回显原名称
需求背景:合同管理-上传的文件需显示原始文件名(原显示 LOCAL:D:\upload\{uuid}.pdf 之类存储键)。
附件此前仅存 fileKey,原始文件名在上传落盘时已被 UUID 重命名丢失,回显无原名可用。
改动内容:
1. contract_manage 表新增 4 个附件原始文件名字段(见 sql/20260818_contract_attachment_original_name.sql):
   contract_original_name    合同正本附件原始文件名
   integrity_agreement_name  廉政协议附件原始文件名
   security_protocol_name    安全协议附件原始文件名
   other_attachments_name    其他附件原始文件名(多文件与 other_attachments_url 同分隔符、同顺序)
2. ContractManage / ContractManagePO / ContractManageDO / ContractManageDTO
   四个对象同步新增对应 4 个 name 字段,保存、详情、列表全链路透传。
   Assembler 与 ContractManageImpl 为 BeanUtils 同名拷贝、Mapper XML 为 SELECT a.*,均无需改动。"
 "配套依赖:
- mhd-product 新增 /menu/upload/v2 返回 { fileKey, originalName }(另一提交)
- 前端上传后成对保存 fileKey 与 originalName,回显显示 name 字段
兼容说明:
- 存量合同 name 字段为空,前端回退显示 fileKey 末段(uuid 名),属预期兼容行为
- 纯新增字段,旧代码不读写,不影响既有接口
2026-08-19 18:08:59 +08:00
rcx fa51580985 feat(product):附件上传v2返回原始文件名,下载接口支持inline预览与中文文件名 2026-08-19 18:04:57 +08:00
rcx 362f1b5e2f fix(bms):科目编码重复致新增账单失败,税率查询按编码+名称取唯一;复制账单改生成新计费流水
- getTaxRate 增加 SUBJECT_NAME 匹配,费用科目编码重复(如1003同时有运输处理费/报关费3)时不再抛 TooManyResultsException,查不到税率兜底0
- addBill、开票/NC推送共4处调用点同步调整;计费流水号为空时只处理自身明细,防空指针
- copyBill 明细清空计费流水id并按原流水映射生成新JFLS流水号,防止复制提交后把原账单的流水改挂到新账单(原账单明细丢失)
- insertAndReturnId 币种空值兜底CNY(与addCost对齐)
2026-08-19 18:02:23 +08:00
rcx b859aa99d3 fix(oms):入库业务单导入件数未回显计划数量
- 导入模版去掉Qty(cases)列(5列布局),饮用日期列位前移
- 明细计划数量由Qty箱数改为"件数"取值,件数同步落库PIECE_COUNT用于列表回显
- 物料在当前登录组织下不存在时返回明确提示,替代货主列表取值越界导致的500
2026-08-19 17:59:19 +08:00
rcx 83f05dd11d feat(bms):新增费用统计分析报表,科目按模板类别归并、仓储拆散租/固定出租两行、行级占营收比,含34列导出与智能分析归因 2026-08-19 15:36:53 +08:00
zhaoqing 6252866f7c fix(oms):明细表保额货物类型 2026-08-19 15:29:09 +08:00
rcx dd0bf32c35 feat(gateway):登录验证码改为纯数字,字符源限定0-9
需要将网关yml文件中 math 改成 char
security:
  captcha:
    enabled: true
    type: char   # math=算术题,char=纯数字
2026-08-19 14:28:45 +08:00
rcx 7ed12c9405 feat(bms):应收账单添加费用币种空值兜底CNY、费用明细增加流水备注保存与显示 2026-08-19 11:02:52 +08:00
zhaoqing 15c8a2b6e6 fix(wms):明细表入库时间 2026-08-19 09:14:44 +08:00
rcx 72e445ea16 fix(oms):出库添加货物查询不到商品,库存查询改租户+货主维度并出库列表补货主旁路
1.ReservationMaterialInventoryApplicationService.queryList原对非南光组织用户强制organization_id=用户组织且top=2827,委托方(如仓码2841货主)库存被滤空;改为按一级组织(租户)过滤,委托方自动叠加登录货主shipperId查自己的货,库存数据已核实在库
2.ReserveStockOutOrderApplicationService.queryList/detailsList增加货主直查旁路(与入库queryList对齐),委托方按shipperId查询不被组织过滤拦截
2026-08-18 18:09:53 +08:00
rcx f50a3e690a fix(oms):出库预约落库回填仓库/组织/货主,状态默认已创建
与入库侧同款修复:insert按仓库档案回填组织/一级组织/仓库编码名称(兜底2841),委托方回填shipperId/customerId,status默认1已创建(配合App订单状态只读);补fastjson import
2026-08-18 18:09:41 +08:00
rcx 8692b38671 fix(oms):入库预约App提交后各端不显示,落库回填仓库/组织/货主并支持货主维度查询
根因:App提交的预约单organization_id/shipper_id落库为空、warehouse_code全空,列表按组织与仓码过滤必然查不到
1.ReserveStockInOrderDomainService.insert:
  -新增明细非空校验,App不传明细时返回'请添加货物明细'而非NPE
  -按warehouseId查仓库档案回填组织(仓码2841/谷丰2842按仓库归属)/一级组织(2827)/仓库编码名称,仓库缺失时兜底登录人一级组织+2841
  -委托方(有货主档案)未传shipper时回填登录人userId至shipperId/customerId
  -订单状态默认'新增'/status默认1(配合App端订单状态改只读)
2.ReserveStockInOrderApplicationService:
  -detailsList增加货主直查旁路(对齐queryList既有逻辑),委托方按shipperId查询不再被组织过滤拦截
  -inAndOutList原无任何数据权限,委托方登录强制注入本人shipperId,防止传错组织(如通宇2830)导致列表滤空并防越权
2026-08-18 18:09:34 +08:00
rcx f77d89fa7f fix(thirdParty):短信验证码发送失败误包成成功响应,失败原因取result并返回error
SmsApi.sms发送失败分支原返回AjaxResult.success(发送失败)且getMessage()取的是默认文案,现改为AjaxResult.error并携带乐信通返回的失败原因,App端可感知发送失败原因
注:收不到验证码的主因(网关白名单/租户域名映射)为Nacos与DB配置项,不在代码仓库
2026-08-18 18:09:25 +08:00
rcx 0ff327a071 fix(auth):App注册接口空实现,补全手机号+短信验证码注册链路
1.AppTokenController.register改为透传完整LoginDTO
2.TokenLoginApplicationService.register原为TODO空壳(仅格式校验直接返回成功),现补全:注册短信验证码校验(SMS_REGISTER redis)→域名解析一级组织→按手机号查重→复用registerAddUser创建用户(含默认角色/YMS同步)→注册成功清验证码并记录日志
3.配套网关白名单(/auth/app/register,/auth/app/getOrganizationByPath/**)需在Nacos发布,不入库
2026-08-18 18:09:18 +08:00
rcx 6661c016e8 fix(auth):密码登录账号/密码错误无提示,登录配置读取与全局异常兜底
1.SysPasswordService.validate登录重试配置(login/maxRetryCount,lockTime)读取增加try/catch与空值保护,三方服务异常或配置缺失时降级默认值(错5次锁30分钟)并warn日志,不再NPE/NumberFormatException导致msg为空
2.GlobalExceptionHandler的RuntimeException/Exception分支对e.getMessage()为空兜底为'系统繁忙,请稍后重试',保证App端始终能拿到可展示的错误信息
2026-08-18 18:08:49 +08:00
王奎兴 4b434a2cd2 Merge branch 'refs/heads/dev' into dev_820 2026-08-18 16:36:28 +08:00
王奎兴 0376f8328c 无货主流程; 2026-08-18 16:35:33 +08:00
rcx bca8b5fbed fix(oms):入库执行单业务单号不随下发复制,执行并下发入口补充有效运输业务单回填 2026-08-18 11:36:21 +08:00
王奎兴 58e3882ef4 添加修改物料去除货主校验; 2026-08-18 10:20:26 +08:00
rcx e489015e3e fix(oms):下发过滤已删除明细,执行单不再残留已取消运输业务单号 2026-08-18 10:19:40 +08:00
王奎兴 1d96322370 添加修改物料去除货主校验; 2026-08-18 09:53:30 +08:00
zhaoqing 19857686aa fix(system):货主租赁明细定时任务开启 发30 2026-08-14 20:28:25 +08:00
王奎兴 d079e35374 发30 2026-08-14 19:25:03 +08:00
王奎兴 466a9fa31f 发31 2026-08-14 18:54:02 +08:00
zhaoqing d74a28bceb fix(oms):运输执行单排序查询报错 2026-08-14 18:21:18 +08:00
zhaoqing 1cc123917b fix(oms):运输执行单排序 2026-08-14 17:38:34 +08:00
rcx 39ebcb70ed wip(wms): 出库报关流程暂时搁置,注释相关代码恢复原出库交接流程 2026-08-14 16:53:22 +08:00
rcx e7e64252e7 feat(wms): 出库报关流程增加通宇组织限制,仅通宇(2830)启用报关判断 2026-08-14 16:38:48 +08:00
zhaoqing a400a34b0c fix(wms):出入库复制新增时清空数量相关数据 2026-08-14 16:35:29 +08:00
zhaoqing ac349ea8a8 fix(wms):出入库复制新增时清空数量相关数据 2026-08-14 15:55:28 +08:00
rcx 7356208228 发测试 2026-08-14 15:30:04 +08:00
rcx 5963f6ed3a fix(oms) : 运输管理 - 运输业务单 - 反审核订单 : 优化异常提示信息 2026-08-14 14:49:13 +08:00
王奎兴 6f28cfdda0 Merge branch 'dev' into dev-ty1.2 2026-08-14 14:40:20 +08:00
王奎兴 5c472ad04e 分配逻辑; 2026-08-14 14:39:20 +08:00
王奎兴 070cdcd5de 仓码820 2026-08-14 14:36:46 +08:00
zhaoqing 061c5bc600 fix(wms):出入库复制新增时清空数量相关数据 2026-08-14 14:08:41 +08:00
zhaoqing e5fea50466 fix(wms):修改导出 2026-08-14 11:36:08 +08:00
rcx 6a87c5a75a fix(oms): 预约入库单列表接口补充申报数量字段
reservationStockInOrderApi/list 返回缺少申报数量,原因为查询只查主表、
未关联明细表汇总,且返回对象无对应字段

- ReservationStockInOrderPO 新增 declaredQuantity 字段
- StockInOrderResult resultMap 增加 declaredQuantity 映射
- selectStockInOrderPo 片段增加 reservation_in_material_detail
  的 DECLARED_QUANTITY 汇总子查询(按 level=1 过滤主明细行)
2026-08-14 11:02:18 +08:00
zhaoqing 63dcfaf028 fix(wms):复制新增修复 2026-08-14 09:39:41 +08:00
zhaoqing c80e4b3ca3 fix(wms):尺寸赋值修改 2026-08-13 18:08:49 +08:00
rcx 3240e57c3e fix(lease): 修复仓库出租率导出总面积、日租率计算错误
导出时总面积被算成全系统所有仓库库区面积之和(6168),日租率因此也错误(0.16)。
根因:导出方法调用 warehouseOccupancyRate(),该方法在不传 warehouseId 时
totalArea 会累加所有仓库面积。

- 导出方法不再调用 warehouseOccupancyRate(),改为自行按(业务日期+仓库)维度计算
- 总面积按仓库单独累加库区面积(通宇关务测试仓库 100,不再 6168)
- 整租/散租面积按(日期+仓库)聚合
- 日租率 = (整租+散租)/该仓库总面积×100,直接输出百分比(10.00)
- 增加总面积为0的除零保护
- 查询接口 warehouseOccupancyRate() 不受影响
2026-08-13 17:43:44 +08:00
rcx e35fa7d48e Merge remote-tracking branch 'origin/dev-ty1.2' into dev-ty1.2 2026-08-13 17:21:21 +08:00
rcx d5bdb5b419 feat(oms): 运输业务单新增反审核功能
审核通过后支持反审核,恢复订单到待审核状态以便修改
- 新增 /businessDocumentOrderApi/cancelAudit 接口
- 仅"审核通过(reviewStatus=1)"且未生成执行单的订单允许反审核
- 拆单主单反审核时级联清理生成的子单、子单地址及配送明细回填
2026-08-13 17:20:41 +08:00
王奎兴 fd1436da9c Merge branch 'dev' into dev-ty1.2
# Conflicts:
#	mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/service/HandoverTaskOrderDomainService.java
#	mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/repository/todo/StockInOrderDO.java
#	mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/todo/StockOutOrderDO.java
#	mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockInOrder/StockInOrderDTO.java
#	mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockOutOrder/StockOutOrderDTO.java
2026-08-13 16:46:09 +08:00
rcx 802a2994cc Merge remote-tracking branch 'origin/dev-ty1.2' into dev-ty1.2 2026-08-13 15:07:03 +08:00
rcx 3d3036cebf feat(wms): 出库报关流程改造
1. 交接环节增加 needDeclareFlag 判断:需报关单置为「已交接(13)」不扣库存,
   不需报关单维持原逻辑直接「已出库(9)」扣库存。
2. 新增定时任务每小时调 sendDec 查报关结果,dec_status=P(海关已放行) 时
   状态 13→9 并扣库存+推OMS。
3. 新增 /stockOutOrderApi/customsConfirmOut 接口支持人工触发报关确认出库。
4. 出库单状态枚举新增 13-已交接。
5. WMS 启动类新增 @EnableScheduling 开启定时任务支持。
2026-08-13 15:06:08 +08:00
zhaoqing 123a5af241 fix(oms):运输业务单排序 2026-08-13 14:15:03 +08:00
zhaoqing da31a81415 fix(oms):复制新增报错 2026-08-13 13:54:20 +08:00
zhaoqing 84d4df0809 fix(system):修改单位返回值逻辑 2026-08-13 10:31:49 +08:00
zhaoqing d17146dc4b fix(oms):运输业务单排序 2026-08-13 10:03:39 +08:00
zhaoqing 44e9eb47bc fix(system):单位返回值修改 2026-08-12 18:34:35 +08:00
rcx bc9a4f7204 Merge remote-tracking branch 'origin/dev-ty1.2' into dev-ty1.2 2026-08-12 18:18:09 +08:00
rcx b37edf7c63 feat(oms): 业务单号改为yyMMdd+每日序号(每日重置,对齐TMS长度)
对应需求#072703,单号规则:年月日001,后面001每天重置
2026-08-12 18:17:29 +08:00
zhaoqing f6125e68bf fix(bms):sql 2026-08-12 18:04:51 +08:00
zhaoqing d6037d5846 fix(bms):单位 数量 单价 2026-08-12 18:01:34 +08:00
zhaoqing df51abe33f fix(wms):total_volume,total_area字段可为空 2026-08-12 17:53:31 +08:00
zhaoqing 5cf46604fa feat(system):查询信息根据编码和组织ID 2026-08-12 16:44:47 +08:00
王奎兴 208024a6cc Merge remote-tracking branch 'origin/dev' into dev 2026-08-12 15:20:46 +08:00
王奎兴 1d01431354 货主账号查询入库业务单报错处理; 2026-08-12 15:20:36 +08:00
高正杨 cbaab0ffee 收货上架单号规则; 2026-08-12 15:09:13 +08:00
王奎兴 a310c9dfa6 Merge remote-tracking branch 'origin/dev' into dev 2026-08-12 14:02:09 +08:00
王奎兴 3866bfee05 生成单号规则处理;+ 2026-08-12 14:01:56 +08:00
zhaoqing 5032cf2413 fix(bms):收款时间查询 2026-08-12 11:40:13 +08:00
zhaoqing a10cfb0f55 fix(bms):收款设置收款时间 2026-08-12 10:19:57 +08:00
秦鸿展 59ede5ceb7 31 2026-08-12 00:04:33 +08:00
秦鸿展 de4d4fa70d 30 2026-08-12 00:00:43 +08:00
秦鸿展 7e496834ae 30 2026-08-11 23:16:20 +08:00
秦鸿展 300b5ac239 角色信息分配错误 2026-08-11 23:11:25 +08:00
秦鸿展 9519d8610b 31 2026-08-11 18:20:37 +08:00
秦鸿展 064a87e751 委托方导入修改 2026-08-11 18:15:58 +08:00
rcx 9e2dc508a8 feat(lease): 新增仓库出租率及客户租赁明细导出功能
- 新增 WarehouseLeaseExportVO(10列:仓库/业务日期/整租面积/散租面积/总面积/日租率/组织/货主/租赁方式/租赁面积)
- LeaseApplicationService 新增 exportOccupancyRate 方法,复用出租率与明细查询,按日期+仓库映射拼接汇总列
- ShipperLeaseDetailsApi 新增 GET /export 接口,入参与查询接口一致,使用项目通用 ExcelUtil 导出
- 业务日期按降序排序,日期格式 yyyy-MM-dd
对应需求:仓库出租率 - 增加导出功能(出租率+客户租赁明细)
2026-08-11 18:05:00 +08:00
rcx 6a84abf6dd feat(system模块lease): 租赁管理增加停用功能,停用后不参与出租率计算
- LEASE 表新增 status 字段(1=启用,0=停用)
- Lease/LeasePO/LeaseDO/LeaseDTO 新增 status 字段
- LeaseMapper.xml 增加 status 查询字段与过滤条件
- 新增 LeaseApi.updateStatus 接口(PUT /updateStatus/{leaseIds}/{status})
- 出租率计算(shipperLeaseDetails)过滤 status=1,停用租赁不再生成出租率数据
一个SQL文件,增加了一个字段,在测试和生产环境都需要执行
对应需求:仓库出租率 - 租赁管理增加停用功能
2026-08-11 18:03:09 +08:00
zhaoqing 8b4e785de3 fix(wms):出入库查询和导出修改 2026-08-11 17:46:49 +08:00
赵辉 c95fdfc067 委托方查询修改 2026-08-11 11:50:40 +08:00
zhaoqing 40a906a9fb fix(system):修改库区库位查询 添加nullify条件 2026-08-11 11:07:40 +08:00
rcx d91aadca0b feat(oms): 入仓委托单「下发到WMS」功能开发
实现 issueOrder 下发逻辑,推送主单与明细至 WMS;增加已审核校验、防重复下发、仓库必填校验
2026-08-11 09:16:28 +08:00
王奎兴 898cc32452 发测30 2026-08-11 02:03:10 +08:00
王奎兴 6cf2a8bc74 发测31 2026-08-11 02:01:20 +08:00
王奎兴 bce9969589 发测30 2026-08-11 01:58:44 +08:00
王奎兴 b73eb84b87 发测30 2026-08-10 22:32:58 +08:00
王奎兴 7d0d24ea77 发测31 2026-08-10 22:26:36 +08:00
秦鸿展 dd5280ab78 30 2026-08-10 21:51:08 +08:00
秦鸿展 bc6b2ba777 BI月台动态真实数据 2026-08-10 21:20:35 +08:00
秦鸿展 f58691615b BI月台动态真实数据 2026-08-10 21:01:04 +08:00
王奎兴 15fdace0bc 发测试 2026-08-10 20:59:25 +08:00
王奎兴 0904b78846 调整备注无效修改; 2026-08-10 20:56:12 +08:00
秦鸿展 734b51bfec BI月台动态真实数据 2026-08-10 20:10:54 +08:00
王奎兴 784d04ebec Merge remote-tracking branch 'origin/dev' into dev 2026-08-10 20:04:08 +08:00
王奎兴 b29632cebc 发30 2026-08-10 20:03:59 +08:00
秦鸿展 3211cfe892 Merge remote-tracking branch 'origin/dev' into dev 2026-08-10 20:00:38 +08:00
秦鸿展 32e8be5363 BI月台动态真实数据 2026-08-10 20:00:20 +08:00
王奎兴 207734c75e 发31 2026-08-10 20:00:10 +08:00
秦鸿展 8eb280f2b9 BI月台动态真实数据 2026-08-10 19:58:05 +08:00
王奎兴 14a5aedf15 Merge branch 'dev' into feature/dev-0729 2026-08-10 18:14:55 +08:00
秦鸿展 d4f660bc7e BI月台动态真实数据 2026-08-10 17:59:59 +08:00
秦鸿展 64bb96c97c BI月台动态真实数据 2026-08-10 17:36:04 +08:00
王奎兴 9df65779ad 保存电子签名id重复; 2026-08-10 17:26:48 +08:00
王奎兴 176a0aa879 已审核入库单电子签名也显示; 2026-08-10 10:03:35 +08:00
王奎兴 1241256787 电子签名签名方式修改; 2026-08-10 09:57:51 +08:00
王奎兴 5e65d63a4f 出入库单按规则生成; 2026-08-08 18:36:36 +08:00
王奎兴 296176c85e 出入库单按规则生成; 2026-08-08 18:02:30 +08:00
王奎兴 993746ee41 出库单按规则生成; 2026-08-08 17:47:59 +08:00
王奎兴 6a0818350a 出库单按规则生成;执行单回显通知单备注; 2026-08-08 16:41:22 +08:00
王奎兴 1b8a75aea5 入库单按规则生成; 2026-08-08 16:04:46 +08:00
zhaoqing 76a290dc58 Merge branch 'dev-ty1.2' into dev 2026-08-08 15:12:27 +08:00
rcx 969d90fff5 fix(wms 库存模块): 修复库存查询各页签分组维度不符合需求的问题
1. queryListByWl(物料查询):原按单物料分组会把同一物料跨仓库库存合并成一行,丢失仓库维度。子查询 partition by 增加 warehouse_id、join 增加 warehouse_id 关联、外层 GROUP BY 增加 warehouse_id,改为按"物料+仓库"汇总。
2. queryListByWlKw(物料/库位查询):GROUP BY 增加 shipper_id,改为按"货主+库位+物料"汇总,避免不同货主在同库位同物料的库存被错误合并。
3. queryListByHz(按货主查询):GROUP BY 增加 warehouse_id,改为按"货主+仓库"汇总;hzwl 分支改走 queryListByHz,符合"按货主查询:货主+仓库"需求。
2026-08-08 15:08:01 +08:00
王奎兴 23b5f96a0c Merge branch 'dev-ty1.2' into dev 2026-08-08 14:26:11 +08:00
zhaoqing 02de8706e2 fix(wms): 复核状态逻辑修改 2026-08-08 11:46:55 +08:00
王奎兴 e6aa8d59e2 发测试 2026-08-08 11:41:13 +08:00
王奎兴 4b29406701 Merge branch 'dev' into feature/dev-0729
# Conflicts:
#	mhd_bms/src/main/resources/bootstrap.yml
2026-08-08 11:39:21 +08:00
王奎兴 1c29c7e5e4 入库调整备注; 2026-08-08 11:36:58 +08:00
王奎兴 add7ef60db 签名方式修改; 2026-08-08 10:27:35 +08:00
王奎兴 d14cea759a 签名方式修改; 2026-08-08 10:25:59 +08:00
rcx 4fde6e1a9c Merge remote-tracking branch 'origin/dev-ty1.2' into dev-ty1.2 2026-08-08 10:08:22 +08:00
rcx 0f88ad75b9 fix(wms 库存模块): 修复库存汇总分组拆分bug并补充库存调整仓库空值校验
1. queryListByHzWlUnit、queryListByWlExpiry 的 GROUP BY 移除
   shipper_code/material_code 等描述列,只保留ID列;对应SELECT
   描述列改用MAX()聚合,避免同ID明细因描述列NULL/值不一致被错误拆分。
2. 库存调整接口新增 ObjectUtil.isNotNull(warehousePO) 空值校验。
2026-08-08 10:07:39 +08:00
王奎兴 067fe1c2c9 签名方式修改; 2026-08-08 10:04:06 +08:00
zhaoqing 6b2adce82f fix(system): 复核状态逻辑修改 2026-08-08 10:01:54 +08:00
王奎兴 bee31cf944 签名方式修改; 2026-08-08 09:59:00 +08:00
王奎兴 552a685bb1 pda签名; 2026-08-08 09:41:29 +08:00
高正杨 1c46de4fb7 pda签名; 2026-08-07 20:46:54 +08:00
王奎兴 a66177e21b pda签名; 2026-08-07 20:25:05 +08:00
王奎兴 fedeece533 扫二维码签名;入库单号规则; 2026-08-07 20:01:01 +08:00
zhaoqing ae138915ae fix(system): 库位库区排序修改 2026-08-07 18:51:04 +08:00
王奎兴 57b8dcfb02 feign查询仓库信息添加字段; 2026-08-07 18:13:24 +08:00
王奎兴 b45af55cdd 生成入库单同步生成电子签名; 2026-08-07 17:54:32 +08:00
zhaoqing 3991496617 发测试bms wms system 2026-08-07 17:32:11 +08:00
王奎兴 261bb07fb0 Merge branch 'dev-ty1.2' into dev 2026-08-07 17:23:38 +08:00
王奎兴 b18fa5938a 样品出库不修改库存; 2026-08-07 17:13:05 +08:00
zhaoqing ba3a90471a feat(bms):计费规格 查询条件 添加费用科目 2026-08-07 15:56:47 +08:00
rcx c5a39d23f2 feat: wms - 库存管理 - 库存查询 -库存调整推送逻辑优化
- 推送 OMS 逻辑增加仓库启用状态判定,未启用 OMS 则不推送
2026-08-07 15:13:19 +08:00
rcx cb136a19b4 feat: 「库存管理」-「库存查询」增加按货主/物料查询
- 实现按(货主 + 物料 + 仓库 + 包装单位)组合聚合逻辑,更新日期取组内最新时间
2026-08-07 15:08:05 +08:00
zhaoqing 0f26cd3d0d feat(bms):新增账单费用支持修改(包含税费相关修改) 2026-08-07 09:40:32 +08:00
rcx 57649dbdfa fix(库存模块): 修复库存调整无法生效 bug
库存调整:修复所有商品调整点击确认之后未生效 bug
2026-08-06 18:07:38 +08:00
王奎兴 b55c890f7e 仓库管理添加单号生成规则字段; 2026-08-06 17:12:40 +08:00
rcx 315d96063a fix(库存模块): 修复库存调整逻辑并优化即时库存接口
库存调整:修复部分商品在点击“完成库存调整”后数据未更新的问题。

即时库存:移除 JSON 返回列表中每个对象冗余的库存数量合计字段,改为在最外层统一返回,优化并缩短接口整体响应时间。
2026-08-06 17:08:54 +08:00
秦鸿展 897e5f195f 测试 2026-08-06 16:57:20 +08:00
秦鸿展 b5b7143d7c 30 2026-08-06 16:41:13 +08:00
王奎兴 f06c210ae9 仓库管理添加单号生成规则字段; 2026-08-06 16:40:56 +08:00
秦鸿展 4f38ac7cd6 ID重复问题 2026-08-06 16:39:36 +08:00
王奎兴 488fdfc50e 业务单添加执行单号; 2026-08-06 15:42:22 +08:00
秦鸿展 1cdc1878a0 31 2026-08-06 15:40:20 +08:00
秦鸿展 2c91368278 ID错误问题 2026-08-06 15:37:42 +08:00
秦鸿展 c0f70715c7 测试 2026-08-06 15:30:04 +08:00
王奎兴 c93445ca4c 业务单添加执行单号回显; 2026-08-06 15:18:15 +08:00
秦鸿展 cb9d09c899 30 2026-08-06 14:22:16 +08:00
王奎兴 f3aec5d42f 系统超时; 2026-08-06 14:14:22 +08:00
王奎兴 bcd7991725 推送nc结算币种; 2026-08-06 13:43:50 +08:00
王奎兴 db5e0e1a66 推送nc结算币种; 2026-08-06 13:39:12 +08:00
王奎兴 ba8dbdd859 推送nc结算币种; 2026-08-06 13:35:24 +08:00
王奎兴 f1967dd40f 发31 2026-08-06 09:15:16 +08:00
王奎兴 505f0aff5e 发31 2026-08-05 20:44:46 +08:00
王奎兴 b9dd2999f1 发30 2026-08-05 20:40:57 +08:00
王奎兴 091c971f30 发30 2026-08-05 20:40:12 +08:00
王奎兴 2de4efbe65 发测试 2026-08-05 20:18:40 +08:00
zhaoqing e5ef8740de 发测试system 2026-08-05 20:02:19 +08:00
王奎兴 661e57ce62 发30 2026-08-05 19:23:05 +08:00
王奎兴 49233cf19b 发31 2026-08-05 19:20:52 +08:00
王奎兴 b96db591f2 发31 2026-08-05 19:19:00 +08:00
王奎兴 236b047f5e 发30 2026-08-05 19:05:43 +08:00
王奎兴 feba6ff672 发31 2026-08-05 19:01:46 +08:00
王奎兴 8caf83b823 回显应收应付; 2026-08-05 18:38:30 +08:00
rcx 789c9ac29c Merge remote-tracking branch 'origin/dev' into dev 2026-08-05 18:33:44 +08:00
rcx 925eeba899 Merge branch 'dev-ty1.2' into dev 2026-08-05 18:32:42 +08:00
王奎兴 568ce3f96d Merge branch 'dev' into dev-bms-0723
# Conflicts:
#	mhd_bms/src/main/resources/bootstrap.yml
#	mhd_bms/src/main/resources/mapper/SettlementCustomersMapper.xml
2026-08-05 18:19:19 +08:00
rcx 56b39702b5 feat:WMS 模块 「库存查询」-「即时库存」
1. 完成即时库存列表接口改造:JSON 返回每个对象中补充规格型号与库存数量合计字段。
     2. 支持前端基于规格型号进行即时库存的组合条件查询
2026-08-05 18:18:08 +08:00
王奎兴 0ee27d796f 回显应收应付; 2026-08-05 18:16:25 +08:00
王奎兴 7842ceaf71 回显应收应付; 2026-08-05 18:13:30 +08:00
王奎兴 987a7c564d 发31 2026-08-05 17:54:11 +08:00
王奎兴 18c8c4d18d 发31 2026-08-05 17:32:17 +08:00
王奎兴 0f4da97358 新增应收账单推送nc 2026-08-05 17:30:17 +08:00
秦鸿展 2787f7651e 30 2026-08-05 17:14:03 +08:00
王奎兴 b9fe4bc4d2 新增应收账单推送nc 2026-08-05 17:01:52 +08:00
王奎兴 7a6c570a88 查货主卡死; 2026-08-05 15:17:00 +08:00
王奎兴 f1567eb81e 查货主卡死; 2026-08-05 14:48:09 +08:00
王奎兴 885d38565c 业务单详情添加执行单信息; 2026-08-05 14:45:32 +08:00
王奎兴 8414fa1509 业务单详情添加执行单信息; 2026-08-05 14:00:11 +08:00
hjx 4b382e4d8f Merge remote-tracking branch 'origin/dev-ty1.2' into dev-ty1.2 2026-08-05 09:55:47 +08:00
hjx b80668145a feat:参照 WMS 入库单规则,通宇「入仓委托单」需新增「入库仓库」字段,并设置为必填项,设置「入库仓库」校验具体
fix:修复【入库管理-收货管理】中批量设置货物参数(数量/面积/体积/尺寸)时,部分字段留空导致已有数据被重置丢失的问题。
2026-08-05 09:49:19 +08:00
王奎兴 476d7c8b0e 发测试 2026-08-04 17:18:22 +08:00
秦鸿展 93dd653ca9 31 2026-08-04 16:35:35 +08:00
秦鸿展 f84c7b0843 BI月台字段修改 2026-08-04 16:34:41 +08:00
秦鸿展 3feb3851e4 30 2026-08-04 14:27:17 +08:00
秦鸿展 38a04d6d30 BI月台新增字段 2026-08-04 14:12:00 +08:00
王奎兴 81841b7ad0 发测试 2026-08-04 14:00:34 +08:00
王奎兴 e366f78081 发测试 2026-08-04 13:58:31 +08:00
王奎兴 a12ac94dd3 bms结算对象同步; 2026-08-04 11:46:59 +08:00
zhaoqing d1ce20abae feat(sys):合同导出 2026-08-04 10:29:48 +08:00
王奎兴 df6b11a8bb 本地 测试文件上传下载; 2026-08-04 09:30:13 +08:00
秦鸿展 c58112a719 正式31 2026-08-03 20:43:22 +08:00
秦鸿展 a4a29c7c8e 正式30 2026-08-03 20:33:23 +08:00
秦鸿展 9283cc9df8 BI报表增加字段 2026-08-03 18:23:21 +08:00
王奎兴 076c915a4c 发31 2026-08-03 16:23:38 +08:00
王奎兴 55c958bde5 发30 2026-08-03 16:13:10 +08:00
秦鸿展 ef53355b87 发测试 2026-08-03 11:47:29 +08:00
zhaoqing c5babe103e feat(sys):合同新增报错 2026-07-31 23:57:48 +08:00
王奎兴 287ae8f22b Merge branch 'dev' into dev-ty1.2 2026-07-31 22:39:30 +08:00
王奎兴 04545a8219 Merge branch 'dev' into feature/dev-0729 2026-07-31 18:05:59 +08:00
王奎兴 1779bc2b23 发30 2026-07-31 18:02:30 +08:00
王奎兴 2a56ce433f 发31 2026-07-31 17:57:50 +08:00
王奎兴 2dd8e7f0a2 发30 2026-07-31 17:51:26 +08:00
王奎兴 b8605c6b43 预约单老系统数据导入; 2026-07-31 17:12:24 +08:00
秦鸿展 5fec54ac63 发测试 2026-07-31 16:41:19 +08:00
秦鸿展 564b8ff8aa 发测试 2026-07-31 16:07:17 +08:00
王奎兴 76a5c987b2 预约单老系统数据导入; 2026-07-31 15:53:35 +08:00
王奎兴 f6ee1a3eee 预约单老系统数据导入; 2026-07-31 15:47:20 +08:00
zhaoqing 1297f920be fix(bms):单据计费查询条件添加 2026-07-31 14:59:20 +08:00
王奎兴 d4ba4f0c0b Merge remote-tracking branch 'origin/dev' into dev 2026-07-30 17:22:11 +08:00
王奎兴 0ed45fee69 仓库出租率计算定时任务重复执行问题;发30; 2026-07-30 17:21:59 +08:00
秦鸿展 69412f7293 发测试 2026-07-30 11:43:06 +08:00
秦鸿展 2bd4d5bb63 发测试 2026-07-30 10:08:24 +08:00
秦鸿展 8b9b29dbf1 发测试 2026-07-30 10:04:03 +08:00
zhaoqing 5890660fe4 feat(bms):导出应收账单 2026-07-29 18:39:05 +08:00
zhaoqing fa6ccad965 feat(bms):导出应收账单 2026-07-29 18:29:54 +08:00
王奎兴 95d232623b Merge branch 'dev' into feature/dev-0729 2026-07-29 18:09:54 +08:00
秦鸿展 e12beb1e0c 发30 2026-07-29 17:23:52 +08:00
秦鸿展 8c722deac6 发测试 2026-07-29 16:34:59 +08:00
秦鸿展 a1494846db 编辑库区 2026-07-29 16:33:40 +08:00
秦鸿展 0d70450997 费用修改 2026-07-29 15:51:11 +08:00
zhaoqing 6c6649368c sql(bms) 2026-07-29 15:24:41 +08:00
zhaoqing 92d53ad90d fix(bms):新增合同(费用类别) 2026-07-29 15:21:36 +08:00
秦鸿展 8b9cd8c749 复制订单 2026-07-29 14:57:31 +08:00
秦鸿展 498574763b OMS批量签名 2026-07-29 14:34:54 +08:00
王奎兴 c200645a15 发30 2026-07-29 14:32:11 +08:00
秦鸿展 c852ef1b8b OMS批量签名 2026-07-29 14:29:56 +08:00
王奎兴 674f56b2c2 库存数量和单位名称 2026-07-29 14:25:12 +08:00
王奎兴 44e7581b2c 发31 2026-07-29 11:02:00 +08:00
王奎兴 01b2723e1f 维他奶导入添加库存信息; 2026-07-29 10:54:22 +08:00
秦鸿展 489515f865 30 2026-07-28 21:18:04 +08:00
秦鸿展 d8aa1e9490 31 2026-07-28 21:10:15 +08:00
秦鸿展 07d9dacded 31 2026-07-28 16:10:37 +08:00
秦鸿展 538a3b42bd 登录校验手机号格式注释 2026-07-28 16:07:00 +08:00
秦鸿展 f660c66027 修复启动报错 2026-07-28 15:50:17 +08:00
秦鸿展 c1e062082a OMS的签名表以及详情,WMS的批量签名 2026-07-28 15:43:38 +08:00
赵辉 55dfb6f4a1 30 2026-07-28 14:47:06 +08:00
赵辉 1f84ad71d8 单点登录修改 2026-07-28 14:43:31 +08:00
赵辉 4d0eb901c9 单点登录修改 2026-07-28 14:43:24 +08:00
秦鸿展 23984e69d6 上架库存货主显示异常,出库复核数量显示BUG 2026-07-28 11:06:07 +08:00
秦鸿展 a1f4953fb5 30 2026-07-25 22:08:20 +08:00
秦鸿展 25ed516000 31 2026-07-25 21:55:16 +08:00
秦鸿展 9f2e8f1855 测试 2026-07-25 21:02:13 +08:00
秦鸿展 1488405397 31 2026-07-25 19:51:53 +08:00
秦鸿展 ad55d49d6b 测试 2026-07-25 19:49:47 +08:00
秦鸿展 7aa7576799 测试 2026-07-25 19:37:11 +08:00
秦鸿展 96c95dabc6 测试 2026-07-25 19:31:11 +08:00
秦鸿展 f3fc2b3093 31 2026-07-25 17:54:17 +08:00
秦鸿展 a112aa1163 30 2026-07-25 17:21:22 +08:00
秦鸿展 e77937fb89 批量电子签名 2026-07-25 17:15:04 +08:00
秦鸿展 6b78248531 出库签名列表查询以及详情 2026-07-25 13:32:26 +08:00
秦鸿展 57cce338b1 导入物料BUG修改 2026-07-25 13:13:32 +08:00
秦鸿展 33a6e875ce 导入物料BUG修改 2026-07-25 10:16:17 +08:00
秦鸿展 cdc098fdd3 导入物料BUG修改 2026-07-25 10:09:26 +08:00
秦鸿展 e544b76db6 导入物料BUG修改 2026-07-25 10:05:12 +08:00
秦鸿展 4f727fadc1 导入物料BUG修改 2026-07-24 20:01:18 +08:00
秦鸿展 5b98ae9435 导入物料BUG修改 2026-07-24 19:42:40 +08:00
秦鸿展 82909efe6b 导入物料BUG修改 2026-07-24 18:49:14 +08:00
秦鸿展 21db85ef2b 入库查询签名列表以及详情 2026-07-24 16:46:42 +08:00
zhaoqing f32f43ab18 feat(oms):出入库明细查询 2026-07-24 15:46:30 +08:00
zhaoqing eb3ada8335 feat(oms):出入库明细查询 2026-07-24 14:19:04 +08:00
zhaoqing 49f6832d3f feat(oms):出库明细查询 2026-07-24 11:24:10 +08:00
zhaoqing 60bc140195 feat(oms):入库明细查询 2026-07-24 10:10:57 +08:00
zhaoqing d268718f9b fix(oms):入库/出库 预约/业务单号生成 2026-07-23 17:53:32 +08:00
王奎兴 895c8d6a4b 发测试; 2026-07-23 17:48:19 +08:00
王奎兴 914a751d96 bms2.0应收单和收款单推送nc修改; 2026-07-23 17:46:32 +08:00
王奎兴 fc16c1edf2 发30 2026-07-23 14:54:15 +08:00
王奎兴 4bd655e4da nc推送改造(进行中); 2026-07-23 14:51:14 +08:00
王奎兴 a96b03a060 nc推送改造(进行中); 2026-07-23 14:49:19 +08:00
zhaoqing 8681042a32 发测试 2026-07-23 11:47:53 +08:00
高正杨 44c9953875 oms启动报错 2026-07-23 11:00:06 +08:00
zhaoqing c48b8aa39a fix(oms):预约确认后,物料明细查询问题 2026-07-23 10:50:57 +08:00
王奎兴 36b31e5d52 Merge branch 'dev' into dev_crkbh_260721
# Conflicts:
#	mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/persistence/ReservationStockInOrderImpl.java
#	mhd_oms/src/main/resources/bootstrap.yml
2026-07-23 10:44:31 +08:00
秦鸿展 f5c096fe39 发30 2026-07-23 00:39:52 +08:00
秦鸿展 75e77c0476 发31 2026-07-23 00:18:41 +08:00
王奎兴 709b151e3f 参数类型 2026-07-22 22:45:08 +08:00
王奎兴 fa731e1fa5 发30 2026-07-22 22:44:26 +08:00
王奎兴 d1448b2746 发30 2026-07-22 22:42:39 +08:00
王奎兴 32d38b7721 发30 2026-07-22 22:08:21 +08:00
王奎兴 ebc7bee5be 发31 2026-07-22 22:06:05 +08:00
王奎兴 19ca4bbe6c 物料根据组织查询; 2026-07-22 21:53:09 +08:00
王奎兴 2f6988abac 修改预约单更新预约数量 2026-07-22 21:46:28 +08:00
王奎兴 e322e28d05 修改预约单更新预约数量 2026-07-22 21:44:22 +08:00
zhaoqing 9f70b236a0 fix(oms):修改导入的单号 2026-07-22 21:35:29 +08:00
秦鸿展 7dcedab498 委托方导入修改 2026-07-22 21:03:07 +08:00
zhaoqing e2f5896be2 fix(oms):修改预约确认的单号生成 2026-07-22 20:14:19 +08:00
秦鸿展 effa681709 导入修改 2026-07-22 19:01:18 +08:00
秦鸿展 8ea6a82acd 发测试 2026-07-22 16:26:45 +08:00
秦鸿展 e7f2a79dee 委托方导入修改 2026-07-22 14:31:15 +08:00
秦鸿展 8a78122fcb 委托方导入修改以及OMS库存查询调整 2026-07-22 14:10:29 +08:00
zhaoqing 49b3722328 发测试 2026-07-22 13:43:29 +08:00
zhaoqing cb96a3700d 区分预约单和业务单 2026-07-22 11:45:06 +08:00
秦鸿展 9250d03ab1 委托方导入 2026-07-22 11:26:19 +08:00
秦鸿展 494f49ee1b 库存查询按照过期日期来过滤查询 2026-07-22 10:39:34 +08:00
zhaoqing be597775d9 fix(oms):修改预约单 2026-07-21 22:10:27 +08:00
zhaoqing 9eff15e483 fix(oms):修改orderNo 2026-07-21 21:51:33 +08:00
zhaoqing 496548558b fix(oms):出入库预约单单号 2026-07-21 21:20:56 +08:00
zhaoqing 7bd2e0b87c fix(oms):出入库执行单修改 2026-07-21 20:29:38 +08:00
zhaoqing 266d416912 fix(oms):出入库预约确认 2026-07-21 20:00:06 +08:00
zhaoqing f2216adb06 fix(oms):出库执行修改 2026-07-21 19:08:43 +08:00
zhaoqing b825f1a789 fix(oms):入库执行修改 2026-07-21 18:51:53 +08:00
zhaoqing 6177b70b34 feat(oms):出库预约单号 2026-07-21 17:57:35 +08:00
zhaoqing 30dd4abe43 feat(oms):入库预约单号 2026-07-21 17:34:24 +08:00
王奎兴 5dd23e9f42 Merge branch 'dev_jinji' into dev 2026-07-21 16:53:01 +08:00
秦鸿展 f91a2248af 调整账单时间为保存修改 2026-07-21 16:49:53 +08:00
王奎兴 b4db0a8cdb 修改预约单更新预约数量 2026-07-21 15:42:52 +08:00
秦鸿展 65fd1e6a19 31 2026-07-20 16:18:19 +08:00
秦鸿展 bab7f048eb 31 2026-07-20 16:18:12 +08:00
秦鸿展 f543c4a00f 新增费用科目BUG修改 2026-07-20 16:16:33 +08:00
秦鸿展 98004ba989 30 2026-07-20 15:40:18 +08:00
秦鸿展 76c8b1f5aa 备注字段修改 2026-07-20 15:38:34 +08:00
秦鸿展 8542a25238 31 2026-07-20 14:43:33 +08:00
秦鸿展 22590abbb8 调整账单报错 2026-07-20 14:40:11 +08:00
秦鸿展 bb68e118fa 30 2026-07-20 12:51:19 +08:00
秦鸿展 1d28170d46 新增账单金额不一致报错 2026-07-20 12:47:00 +08:00
秦鸿展 1b85098063 发31 2026-07-17 22:18:59 +08:00
秦鸿展 d6d9ee1d5e 发30 2026-07-17 22:14:14 +08:00
秦鸿展 2d9a4eaad2 发30 2026-07-17 21:44:52 +08:00
秦鸿展 1423d5d140 发30 2026-07-17 21:39:53 +08:00
秦鸿展 80e1639b83 发测试 2026-07-17 20:37:17 +08:00
秦鸿展 07862301e6 应收账单新增报错 2026-07-17 20:31:35 +08:00
秦鸿展 d6fae412cd 应收账单新增报错 2026-07-17 20:17:04 +08:00
秦鸿展 7ee70dd06c 应收账单新增报错 2026-07-17 20:11:34 +08:00
秦鸿展 6f33fc3b64 应收账单添加明细报错 2026-07-17 19:40:49 +08:00
王奎兴 a9e3d6cb6b Merge branch 'dev' into dev_jinji 2026-07-17 18:06:41 +08:00
王奎兴 5fe5ce7e82 复核添加货主id查询; 2026-07-17 18:04:56 +08:00
秦鸿展 5cc987c2c4 应收账单明细修改 2026-07-17 16:14:21 +08:00
秦鸿展 9ed1797b59 紧急任务修改 2026-07-17 15:32:11 +08:00
秦鸿展 2373be59e6 紧急任务修改 2026-07-17 15:27:17 +08:00
王奎兴 587550025d 发30 2026-07-17 14:29:43 +08:00
王奎兴 9dfcf4ef5a 发31 2026-07-17 14:22:38 +08:00
秦鸿展 914957e683 新增账单 2026-07-17 11:41:39 +08:00
王奎兴 a852c0844e 发测试 2026-07-17 01:55:08 +08:00
王奎兴 50b10ad19f 发30 2026-07-17 01:51:20 +08:00
王奎兴 aff19e1536 发30 2026-07-17 01:48:15 +08:00
王奎兴 4c58838842 发30 2026-07-17 00:48:43 +08:00
王奎兴 d27cca0217 发31 2026-07-17 00:44:34 +08:00
王奎兴 6f5fa138d9 添加批次号; 2026-07-17 00:11:53 +08:00
王奎兴 cf0a42ec8a 添加批次号; 2026-07-16 23:13:30 +08:00
王奎兴 5c591d3b57 添加批次号; 2026-07-16 22:53:45 +08:00
王奎兴 165927bc3d 执行单下发分发组织; 2026-07-16 20:55:11 +08:00
王奎兴 2d03084f0c 分批上架多余数据处理; 2026-07-16 19:00:49 +08:00
王奎兴 1f0703bc64 分批上架多余数据处理; 2026-07-16 18:35:32 +08:00
王奎兴 9bb5a7c2cf 库位条码; 2026-07-16 18:19:15 +08:00
王奎兴 a7eed8590f 库位条码; 2026-07-16 14:11:33 +08:00
王奎兴 4fad415cb7 库位条码; 2026-07-16 13:51:59 +08:00
王奎兴 a23a4acef3 发测试 2026-07-16 12:21:57 +08:00
王奎兴 0cd0a9535d Merge branch 'dev' into cangmapda_260710 2026-07-16 12:18:51 +08:00
王奎兴 71765b339f 明细上架单号为空问题; 2026-07-16 10:10:51 +08:00
王奎兴 521e4ca5bd 生成任务; 2026-07-16 09:50:09 +08:00
王奎兴 47688bfe34 生成任务; 2026-07-16 09:44:13 +08:00
王奎兴 b0999402cd 生成任务; 2026-07-16 08:58:00 +08:00
高正杨 dde4698fc6 更新1 2026-07-15 22:34:27 +08:00
秦鸿展 5513b0af08 31 2026-07-15 21:19:25 +08:00
秦鸿展 357fb0bd65 30 2026-07-15 21:17:42 +08:00
秦鸿展 16627950e2 港澳服务专区增加字段 2026-07-15 19:06:35 +08:00
王奎兴 81dc017b68 生成任务; 2026-07-15 18:17:46 +08:00
王奎兴 80b96b0f17 复核逻辑修改; 2026-07-15 16:34:03 +08:00
王奎兴 d683774b88 复核逻辑修改; 2026-07-15 16:19:46 +08:00
王奎兴 20f60d490f 复核逻辑修改; 2026-07-15 16:07:16 +08:00
王奎兴 73f7bbd803 复核逻辑修改; 2026-07-15 15:14:45 +08:00
王奎兴 5029ae8d42 复核逻辑修改; 2026-07-15 15:10:51 +08:00
王奎兴 87eea6a8cd 复核逻辑修改; 2026-07-15 14:56:58 +08:00
王奎兴 72b2a153a0 复核逻辑修改; 2026-07-15 14:41:21 +08:00
王奎兴 7326407d13 复核逻辑修改; 2026-07-15 14:36:19 +08:00
王奎兴 4091f20e7a pda任务下发; 2026-07-14 18:09:53 +08:00
王奎兴 7bcf11baaf pda任务下发; 2026-07-14 18:08:28 +08:00
王奎兴 11ad2ea20f 回显出库重量等; 2026-07-14 17:54:17 +08:00
王奎兴 b303c78b39 回显出库重量等; 2026-07-14 17:53:09 +08:00
王奎兴 2fb7d117c0 回显出库重量等; 2026-07-14 17:30:35 +08:00
王奎兴 cdb21fe961 回显出库重量等; 2026-07-14 17:18:57 +08:00
王奎兴 2151555f31 发测试; 2026-07-14 15:10:17 +08:00
王奎兴 ce4f56962f 拣货数量 2026-07-14 15:07:37 +08:00
王奎兴 c3b4923ce9 类型转换异常 2026-07-14 13:52:36 +08:00
王奎兴 c536d2c5c6 类型转换异常 2026-07-14 09:33:45 +08:00
王奎兴 fad5eb66fa 类型转换异常 2026-07-14 09:29:02 +08:00
王奎兴 52172dc3d7 简易模式收货及上架; 2026-07-13 18:04:43 +08:00
王奎兴 34a146514f 简易模式收货及上架; 2026-07-13 17:45:22 +08:00
秦鸿展 8377d9f2a5 同步过滤逻辑修改3 2026-07-13 17:42:04 +08:00
王奎兴 0f2e2e769b 简易模式收货及上架; 2026-07-13 17:34:44 +08:00
王奎兴 73b1a76cb6 简易模式收货及上架; 2026-07-13 16:47:05 +08:00
王奎兴 81c30d752d 简易模式收货及上架; 2026-07-13 16:42:18 +08:00
秦鸿展 38b2de852b 同步过滤逻辑修改2 2026-07-13 16:18:53 +08:00
王奎兴 35122c0fca 简易模式收货及上架; 2026-07-13 15:17:16 +08:00
秦鸿展 f1c7dd453b 同步过滤逻辑修改1 2026-07-13 14:47:10 +08:00
秦鸿展 f1aa799809 同步过滤逻辑修改 2026-07-13 11:36:06 +08:00
秦鸿展 d5dfa96859 查询三方主数据接口修复1 2026-07-13 11:27:51 +08:00
秦鸿展 23fe5eca9c 查询三方主数据接口修复 2026-07-13 11:15:08 +08:00
赵辉 69d5276bd9 30财务 2026-07-11 20:09:21 +08:00
王奎兴 876430874c 发31 2026-07-11 19:32:17 +08:00
王奎兴 24c234bcb7 发30 2026-07-11 19:30:34 +08:00
王奎兴 c52b9f092e 发31 2026-07-11 19:21:11 +08:00
赵辉 61b68804f0 测试 2026-07-11 18:11:58 +08:00
赵辉 23bffb32b3 测试 2026-07-11 18:01:42 +08:00
秦鸿展 9f9b0867ac 客商BUG修复 2026-07-11 16:49:21 +08:00
赵辉 1a309cb042 客商修改 2026-07-11 13:58:37 +08:00
赵辉 226360ef3a 客商修改 2026-07-11 11:48:35 +08:00
王奎兴 444b6add0a 移除任务人员空指针处理; 2026-07-11 10:51:14 +08:00
王奎兴 46757ed2f1 移除任务人员空指针处理; 2026-07-11 10:39:32 +08:00
王奎兴 1548a28c9e 移除任务人员空指针处理; 2026-07-11 10:32:33 +08:00
王奎兴 2755ed1a33 出入库移交任务及移除任务项; 2026-07-10 17:08:24 +08:00
王奎兴 5030ca2a8a 出入库移交任务及移除任务项; 2026-07-10 17:06:29 +08:00
王奎兴 4852b4496a pda任务接收 2026-07-10 16:30:49 +08:00
王奎兴 e2bfb032a7 作业人员名称 2026-07-10 16:20:53 +08:00
王奎兴 762c9d4bf4 配送明细客户id值; 2026-07-10 15:57:01 +08:00
王奎兴 f4f2573af7 仓码pda改造; 2026-07-10 15:26:06 +08:00
王奎兴 1381bcee72 入库单pda查询; 2026-07-10 14:17:46 +08:00
王奎兴 bbe8ce3523 入库单pda查询; 2026-07-10 14:15:34 +08:00
王奎兴 7ae6ed2aac 出入库添加物料数量; 2026-07-10 10:42:38 +08:00
王奎兴 d45206a644 按客户预约库存分配库存; 2026-07-09 18:11:02 +08:00
王奎兴 f7faed5e44 Merge remote-tracking branch 'origin/dev' into dev 2026-07-09 16:00:24 +08:00
王奎兴 fa5f8d68cc 按客户预约库存分配库存; 2026-07-09 16:00:11 +08:00
赵辉 b0a28a101e 30 2026-07-09 15:18:12 +08:00
赵辉 b24d02f4a6 正式环境单点登录地址修改 2026-07-09 15:05:57 +08:00
赵辉 a9aba71e0c 31 2026-07-09 11:12:58 +08:00
赵辉 687404b47f 测试 2026-07-08 19:03:51 +08:00
赵辉 d4e3b36974 30 2026-07-08 18:55:34 +08:00
赵辉 162f35b752 31 2026-07-08 18:47:32 +08:00
赵辉 9cb99c915d oss单点登录 2026-07-08 18:42:53 +08:00
王奎兴 9a58a7b41c 发31 2026-07-07 14:04:44 +08:00
王奎兴 3c594d4a91 库存查询报错; 2026-07-07 13:58:17 +08:00
王奎兴 dc9d491d61 pda查询报错; 2026-07-07 10:00:09 +08:00
王奎兴 d0cde81dcd 发30 2026-07-07 09:39:17 +08:00
王奎兴 81cd4b3317 发31 2026-07-07 09:34:59 +08:00
王奎兴 442ca4977c 发31 2026-07-07 09:14:30 +08:00
王奎兴 2abdb6e8d1 发31 2026-07-07 09:09:37 +08:00
王奎兴 53e9f977a1 库存查询报错; 2026-07-07 09:08:18 +08:00
王奎兴 1dcd38aaa2 30 2026-07-06 22:50:42 +08:00
王奎兴 50b7be1e4f 回显客户预约物料名; 2026-07-06 22:42:52 +08:00
王奎兴 4ce7b3afec 回显客户预约物料名; 2026-07-06 22:00:46 +08:00
王奎兴 aeff793901 发30 2026-07-06 21:40:13 +08:00
王奎兴 187bddc820 发31 o 2026-07-06 21:35:50 +08:00
王奎兴 360cb8d95c 发30 2026-07-06 21:22:09 +08:00
王奎兴 a589cfd3af 预约单组织修改; 2026-07-06 21:19:30 +08:00
秦鸿展 f80b0bbddb 关务推送增加字段 2026-07-06 20:59:55 +08:00
王奎兴 76596ac927 预约单组织修改; 2026-07-06 20:55:09 +08:00
秦鸿展 2a33823ef2 关务推送增加字段 2026-07-06 20:45:27 +08:00
秦鸿展 930894b37e 关务推送增加字段,发测试 2026-07-06 19:56:54 +08:00
王奎兴 02acda9e23 预约单组织修改; 2026-07-06 19:01:30 +08:00
赵辉 41fa3991d9 31 2026-07-06 18:50:08 +08:00
赵辉 a221c05ec9 31 2026-07-06 18:44:02 +08:00
王奎兴 57fb245715 发测试; 2026-07-06 17:45:50 +08:00
王奎兴 79cda62fb4 发测试; 2026-07-06 17:32:48 +08:00
王奎兴 0fba417b77 Merge remote-tracking branch 'origin/dev' into dev 2026-07-06 17:23:41 +08:00
王奎兴 ed8d3fafd9 bug; 2026-07-06 17:23:23 +08:00
秦鸿展 fea9ac6277 30 2026-07-06 13:02:23 +08:00
秦鸿展 8e1cd9b185 31 2026-07-06 12:48:46 +08:00
秦鸿展 bc2fc833a2 财务结算结算币种按照组织管理来查询 2026-07-06 11:41:18 +08:00
王奎兴 196410331b 测试o 2026-07-04 01:07:56 +08:00
赵辉 9351bd8816 30 2026-07-04 00:24:31 +08:00
赵辉 429c279b78 Merge remote-tracking branch 'origin/dev' into dev 2026-07-04 00:08:36 +08:00
赵辉 4a6421c9cf 31 2026-07-04 00:08:18 +08:00
王奎兴 9e71401716 Merge remote-tracking branch 'origin/dev' into dev 2026-07-04 00:01:34 +08:00
王奎兴 fceaf38db9 测试o 2026-07-04 00:01:21 +08:00
赵辉 4a90bbd9ad user30 2026-07-03 23:50:22 +08:00
赵辉 4ced5f9b65 user30 2026-07-03 23:01:46 +08:00
赵辉 07d43b393d w30 2026-07-03 22:44:22 +08:00
王奎兴 ab0c0fdc17 测试o 2026-07-03 22:40:22 +08:00
王奎兴 0425b41cf4 Merge remote-tracking branch 'origin/dev' into dev 2026-07-03 22:37:40 +08:00
王奎兴 9e3cedb596 账单调整计算税额; 2026-07-03 22:37:29 +08:00
赵辉 5678399a34 w31 2026-07-03 22:36:59 +08:00
赵辉 dc0416510b w31 2026-07-03 22:10:48 +08:00
王奎兴 cf85ffa37f Merge remote-tracking branch 'origin/dev' into dev 2026-07-03 22:08:48 +08:00
王奎兴 7d26d7915c 账单调整计算税额; 2026-07-03 22:08:34 +08:00
赵辉 185b68bde9 w30 2026-07-03 22:07:24 +08:00
赵辉 553e0eebee bug修改 2026-07-03 22:05:37 +08:00
王奎兴 fb4c508873 新增预约单查不到; 2026-07-03 21:57:17 +08:00
王奎兴 ebfd3c3f2e 收款单同步失败 2026-07-03 21:37:50 +08:00
王奎兴 62ecfddb95 账单修改; 2026-07-03 21:04:19 +08:00
王奎兴 19696cbb6a bug修改; 2026-07-03 19:15:14 +08:00
王奎兴 40c16f17cc bug修改; 2026-07-03 19:10:27 +08:00
王奎兴 bd2170e0be Merge remote-tracking branch 'origin/dev' into dev 2026-07-03 17:49:55 +08:00
王奎兴 e4a3835ee0 bug修改; 2026-07-03 17:49:31 +08:00
赵辉 98e94682eb 30 2026-07-03 16:51:52 +08:00
赵辉 eb07b799f6 nc修改 2026-07-03 16:49:27 +08:00
赵辉 615e0d34e4 nc修改 2026-07-03 15:11:41 +08:00
王奎兴 8b66aea296 Merge remote-tracking branch 'origin/dev' into dev 2026-07-03 11:29:38 +08:00
王奎兴 eec6752b9a 物料查询历史数据; 2026-07-03 11:29:24 +08:00
秦鸿展 2907a55c96 O新增订单增加字段 2026-07-03 11:01:18 +08:00
王奎兴 08762490dd 测试 2026-07-03 09:53:37 +08:00
王奎兴 9e2d84fc5c 测试 2026-07-02 19:51:45 +08:00
王奎兴 1c2bb30c44 Merge branch 'dev' into dev_v3.0.5 2026-07-02 19:39:40 +08:00
王奎兴 268c00074f 多仓 2026-07-02 19:38:43 +08:00
赵辉 7f38da20e1 bms修改 2026-07-02 19:29:23 +08:00
王奎兴 176bdbc633 Merge branch 'dev' into dev_user0622
# Conflicts:
#	mhd_wms/src/main/resources/mapper/pickingOrder/PickingOrderMapper.xml
2026-07-02 19:09:31 +08:00
王奎兴 c2a4b981e6 Merge branch 'dev' into dev_v3.0.5 2026-07-02 19:07:55 +08:00
王奎兴 ecd5e89172 3.0.5 2026-07-02 18:32:23 +08:00
王奎兴 22ff97e045 3.0.5 2026-07-02 17:44:36 +08:00
王奎兴 afc26a798f 3.0.5 2026-07-02 17:25:09 +08:00
王奎兴 b5914940df 3.0.5 2026-07-02 16:22:49 +08:00
王奎兴 01ec70e3c2 3.0.5 2026-07-02 15:59:58 +08:00
王奎兴 b178e79c8f 3.0.5 2026-07-02 15:04:20 +08:00
王奎兴 0d70cc8b4c 入库业务单编辑报错; 2026-07-02 09:09:43 +08:00
王奎兴 55f089a7d6 入库业务单编辑报错; 2026-07-02 09:03:15 +08:00
王奎兴 b432ab0ac3 入库业务单编辑报错; 2026-07-02 08:56:55 +08:00
王奎兴 08b930e6d4 Merge branch 'dev_v3.0.4' into dev_user0622 2026-07-02 08:35:43 +08:00
赵辉 1ed10bf71b Merge remote-tracking branch 'origin/dev_user0622' into dev_user0622 2026-07-01 21:04:25 +08:00
赵辉 4772395daf 发31 2026-07-01 21:04:08 +08:00
秦鸿展 11fa915e0e 发31 2026-07-01 20:57:18 +08:00
秦鸿展 8c9ef2f083 默认用户是本组织的 2026-07-01 19:34:28 +08:00
王奎兴 193db96e63 v3.0.5 2026-07-01 18:19:03 +08:00
秦鸿展 ec43b3be8a 发30 2026-07-01 18:16:19 +08:00
秦鸿展 9511a38946 一般贸易推送添加字段 2026-07-01 15:28:30 +08:00
秦鸿展 bc962c3131 复核数量检验 2026-07-01 14:20:57 +08:00
王奎兴 4f24096a0c Merge branch 'dev' into dev_user0622 2026-07-01 13:45:20 +08:00
王奎兴 20a7978729 上架报错; 2026-07-01 11:43:32 +08:00
王奎兴 7c18ccf3bb 上架报错; 2026-07-01 11:36:59 +08:00
王奎兴 78c9ab191a 出库拣货单打印 2026-07-01 11:35:22 +08:00
王奎兴 8bec065f69 物料编辑货主查询匹配多组织信息; 2026-07-01 10:14:19 +08:00
王奎兴 d82abe15bf 业务单到执行单不分发组织; 2026-07-01 09:47:23 +08:00
王奎兴 4017c0a60d v3.0.4 2026-06-30 18:06:42 +08:00
秦鸿展 da0dae5f40 发测试包 2026-06-30 14:55:08 +08:00
秦鸿展 8b186907e1 发测试包 2026-06-29 20:05:58 +08:00
王奎兴 183c84cb5b Merge remote-tracking branch 'refs/remotes/origin/dev' into dev_user0622
# Conflicts:
#	mhd-user-center/src/main/resources/bootstrap.yml
2026-06-29 18:24:48 +08:00
王奎兴 9ca77a7d57 出库单执行生成拣货单及取消执行删除拣货单; 2026-06-29 18:04:51 +08:00
王奎兴 40ff9808b8 出库单执行生成拣货单及取消执行删除拣货单; 2026-06-29 18:02:40 +08:00
秦鸿展 4afe929020 APP菜单权限 2026-06-29 17:21:09 +08:00
秦鸿展 d982cc41c3 小程序登录同步YMS用户BUG修改1 2026-06-29 15:47:24 +08:00
秦鸿展 0497d8e96e 小程序登录同步YMS用户BUG修改 2026-06-29 15:32:48 +08:00
秦鸿展 b51bc17838 小程序登录同步YMS用户BUG修改 2026-06-29 15:27:11 +08:00
秦鸿展 2516d86226 小程序新增默认角色信息BUG修改 2026-06-29 15:04:15 +08:00
秦鸿展 287575c622 小程序新增默认角色BUG修改1 2026-06-29 14:55:33 +08:00
秦鸿展 374b26d023 小程序新增默认角色BUG修改 2026-06-29 14:34:38 +08:00
王奎兴 a5489ceb5a 新增修改库存添加组织信息; 2026-06-29 11:07:57 +08:00
王奎兴 de1ef5dec7 预约改造;pda报错; 2026-06-29 10:56:57 +08:00
秦鸿展 8be0813e21 新增角色BUG修改 2026-06-27 19:00:43 +08:00
秦鸿展 dc589fdf3f 新增角色 2026-06-27 18:17:43 +08:00
王奎兴 8f0e71fe2a 预约单改造; 2026-06-27 18:06:31 +08:00
秦鸿展 c6366ef728 司机APP注册是默认用户角色 2026-06-27 17:22:27 +08:00
秦鸿展 2d424847c3 对接微信小程序接口 2026-06-27 14:06:34 +08:00
王奎兴 8893eda62d 执行及取消执行;nc推送客户nc编码查询逻辑修改; 2026-06-26 18:27:24 +08:00
王奎兴 293fedda12 执行及取消执行; 2026-06-26 14:15:33 +08:00
王奎兴 ed4d6111a5 执行及取消执行; 2026-06-26 10:52:57 +08:00
王奎兴 92acdb4f20 货主更新角色变管理员处理; 2026-06-25 14:37:03 +08:00
王奎兴 f933aa9234 货主更新角色变管理员处理; 2026-06-25 14:35:55 +08:00
王奎兴 f704038362 根据组织ids查询仓库; 2026-06-25 11:04:58 +08:00
王奎兴 3e90a8c5c4 货主查询组织; 2026-06-25 10:36:34 +08:00
王奎兴 db198dd2a2 货主查询组织; 2026-06-25 10:28:29 +08:00
王奎兴 a6e727e04a 仓储执行单; 2026-06-24 17:45:44 +08:00
赵辉 ce8e340116 同步委托方修改 2026-06-24 16:07:56 +08:00
王奎兴 42e9f79b10 Merge branch 'dev' into dev_user0622 2026-06-24 13:58:38 +08:00
王奎兴 e966726a0c 加货主是否支持多仓;物料组织模糊查询; 2026-06-24 09:57:20 +08:00
王奎兴 89c3f398b8 加货主是否支持多仓; 2026-06-24 09:48:08 +08:00
王奎兴 84174a6639 Merge remote-tracking branch 'origin/dev' into dev_user0622 2026-06-24 09:39:56 +08:00
赵辉 0ae37ac795 信用修改 2026-06-23 14:39:05 +08:00
赵辉 a14c7776e8 信用修改 2026-06-23 14:00:32 +08:00
赵辉 41fc2d1805 修改字段 2026-06-23 11:30:30 +08:00
赵辉 7ccb06ad79 测试环境 2026-06-23 11:11:11 +08:00
赵辉 21aab4f17e 三方信用修改 2026-06-23 10:27:57 +08:00
赵辉 3224e87814 三方信用修改 2026-06-23 10:14:06 +08:00
赵辉 31247d7faa 委托方增加组织代码,与查询修改 2026-06-23 08:57:06 +08:00
768 changed files with 64572 additions and 3166 deletions
BIN
View File
Binary file not shown.
@@ -3,6 +3,7 @@ package com.mhd.system.api;
import com.mhd.common.core.constant.ServiceNameConstants;
import com.mhd.common.core.domain.dto.BusinessDataPushDTO;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.system.api.domain.BusinessDocumentFeign;
import com.mhd.system.api.factory.RemoteBmsFeignFallbackFactory;
import com.mhd.system.api.feign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
@@ -18,7 +19,8 @@ import java.util.Set;
/**
* bms财务结算系统feign调用接口
*/
@FeignClient(contextId = "BmsService", value = ServiceNameConstants.BMS_SERVICE, url = "http://10.102.192.3:8019",fallbackFactory = RemoteBmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
// 目标地址由 nacos 配置项 feign.url.mhd-bms-service 指定,未配置时按服务名走服务发现
@FeignClient(contextId = "BmsService", value = ServiceNameConstants.BMS_SERVICE, url = "http://10.102.192.32:8019",fallbackFactory = RemoteBmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface BmsServiceFeign {
@@ -68,4 +70,17 @@ public interface BmsServiceFeign {
*/
@PostMapping("/businessDocumentApi/wholeRentSynchronizationZXF")
public AjaxResult wholeRentSynchronizationZXF(@RequestBody BusinessDataPushDTO businessDataPushDTO);
@PostMapping("/businessDocumentApi/feignSave")
public AjaxResult feignSaveBusinessDocument(@RequestBody BusinessDocumentFeign businessDocumentFeign);
/**
* 根据结算对象id查询结算对象参数列表
*/
@GetMapping("/settlementCustomersParametersApi/getListBySettlementCustomersId")
AjaxResult getListBySettlementCustomersId(@RequestParam("settlementCustomersId") Long settlementCustomersId);
@PostMapping("/settlementCustomersApi/updatePushContractManageJobId")
AjaxResult updatePushContractManageJobId(@RequestParam("settlementCustomersId") Long settlementCustomersId,
@RequestParam("jobId") Integer jobId);
}
@@ -12,11 +12,13 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@FeignClient(contextId = "OmsService", value = ServiceNameConstants.OMS_SERVICE,url = "http://10.102.192.4:8017", fallbackFactory = RemoteOmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
// 目标地址由 nacos 配置项 feign.url.mhd-oms-service 指定,未配置时按服务名走服务发现
@FeignClient(contextId = "OmsService", value = ServiceNameConstants.OMS_SERVICE,url = "http://10.102.192.33:8017",fallbackFactory = RemoteOmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface OmsServiceFeign {
@@ -28,6 +30,10 @@ public interface OmsServiceFeign {
@PostMapping(value = "/reservationStockInOrderApi/pushInOrderDetail")
public AjaxResult pushInOrderDetail(@RequestBody InMaterialDetailTZPD inMaterialDetail);
@ApiOperation("wms回传入库结果:按入库单号同步入库状态(3-收货中 4-上架中 5-已入库)到OMS入库业务单,type非1为入库")
@GetMapping(value = "/executionStockInOrderApi/returnResult")
public AjaxResult returnInResult(@RequestParam("orderNumber") String orderNumber, @RequestParam("status") Long status, @RequestParam("type") String type);
@ApiOperation("wms推送入库单")
@PostMapping(value = "/reservationStockOutOrderApi/pushOutOrder")
@@ -66,4 +72,8 @@ public interface OmsServiceFeign {
@ApiOperation("批量推送")
@PostMapping("/reservationStockOutOrderApi/batchPushByNumber")
public AjaxResult batchPushByNumber(@RequestBody List<String> numberList);
@ApiOperation("保存电子签名记录")
@PostMapping("/electronicSignatureApi/saveSignature")
public AjaxResult saveSignature(@RequestBody ElectronicSignatureSyncDTO saveDTO);
}
@@ -12,6 +12,8 @@ import com.mhd.common.core.domain.entity.R;
import com.mhd.common.core.domain.po.SysMultistageDictPo;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.system.api.domain.ContainerFeignPO;
import com.mhd.system.api.domain.ContractManageFeignDTO;
import com.mhd.system.api.domain.ContractManageParametersFeign;
import com.mhd.system.api.domain.SysDictData;
import com.mhd.system.api.factory.RemoteSystemFeignFallbackFactory;
import com.mhd.system.api.feign.FeignAutoConfiguration;
@@ -237,6 +239,12 @@ public interface SystemServiceFeign {
@GetMapping("/warehouseApi/getInfo/{warehouseId}")
public AjaxResult getWarehouseInfoByWarehouseId(@PathVariable("warehouseId") Long warehouseId);
/**
* 根据warehouseId获取仓库及下库区及库位树(与前端 warehouseApi/getWarehouseChildren 一致,用于PC上架页默认库位回显)
*/
@GetMapping("/warehouseApi/getWarehouseChildren")
public AjaxResult getWarehouseChildren(@RequestParam("warehouseId") Long warehouseId);
/**
* 根据storageSectionId获取对应库区信息
*/
@@ -357,6 +365,10 @@ public interface SystemServiceFeign {
@GetMapping("/contractManageApi/getInfoByCustomer")
public AjaxResult getInfoByCustomer(@RequestParam("settlementCustomersCode") String settlementCustomersCode,@RequestParam("contractType") Integer contractType);
@ApiOperation("根据结算主体和费用科目获取合同信息")
@GetMapping(value = "/contractManageApi/getInfoByCustomerAndSecondSubjectCode")
public AjaxResult getInfoByCustomerAndSecondSubjectCode(@RequestParam("settlementCustomersCode") String settlementCustomersCode,@RequestParam("contractType") Integer contractType,@RequestParam("firstSubjectCode") String firstSubjectCode,@RequestParam("topOrganizationId") Long topOrganizationId,@RequestParam("organizationId") Long organizationId);
/**
* 根据结算主体获取合同信息
*/
@@ -380,4 +392,13 @@ public interface SystemServiceFeign {
public AjaxResult matchForMaterialImport(@RequestParam("keyword") String keyword,
@RequestParam("organizationId") Long organizationId);
@ApiOperation("保存临时合同管理")
@PostMapping("/contractManageApi/feignSave")
public AjaxResult feignSave(@RequestBody ContractManageFeignDTO contractManageFeignDTO);
@ApiOperation("Feign保存合约信息规则维护")
@PostMapping("/contractManageParametersApi/feignSave")
public AjaxResult feignSaveContractParameters(@RequestBody ContractManageParametersFeign contractManageParametersFeign);
}
@@ -165,6 +165,10 @@ public interface UserServiceFeign {
@GetMapping("/userShipperApi/userShipperListAll")
public AjaxResult<?> userShipperListAll();
@ApiOperation("查询租户下全部托运人")
@GetMapping("/userShipperApi/userShipperListAllByOrg")
public AjaxResult<?> userShipperListAllByOrg(@RequestParam("orgCode") Long orgCode);
@ApiOperation("查询租户下全部承运人")
@GetMapping("/userDriverApi/userDriverListAll")
public AjaxResult<?> userDriverListAll();
@@ -223,4 +227,7 @@ public interface UserServiceFeign {
@ApiOperation("查询赊销额度")
@PostMapping("/userShipperApi/querySaleCreditLimitFeign")
public AjaxResult querySaleCreditLimitFeign(@RequestBody UserShipperFeignDTO userShipperDTO);
@GetMapping("/userApi/getUserByUserAccount")
R<LoginUser> getUserByUserAccount(@RequestParam("userAccount") String account);
}
@@ -26,7 +26,8 @@ import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@FeignClient(contextId = "commonWlhyServiceFeign",value = ServiceNameConstants.WLHY_SERVICE,url = "http://10.102.192.30:8014",configuration = FeignAutoConfiguration.class)
// 目标地址由 nacos 配置项 feign.url.mhd-wlhy-service 指定,未配置时按服务名走服务发现
@FeignClient(contextId = "commonWlhyServiceFeign",value = ServiceNameConstants.WLHY_SERVICE,url = "http://10.102.192.31:8014",configuration = FeignAutoConfiguration.class)
public interface WlhyServiceFeign {
/**
@@ -1,5 +1,6 @@
package com.mhd.system.api;
import cn.hutool.json.JSONUtil;
import com.mhd.common.core.constant.ServiceNameConstants;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.core.web.page.TableDataInfo;
@@ -20,7 +21,8 @@ import java.util.Map;
* @description: TODO
* @date 2024/5/10 8:58
**/
@FeignClient(contextId = "remoteWmsServiceFeign",value = ServiceNameConstants.WMS_SERVICE, url = "http://10.102.192.3:8016", fallbackFactory = RemoteWmsFallbackFactory.class, configuration = FeignAutoConfiguration.class)
// 目标地址由 nacos 配置项 feign.url.mhd-wms-service 指定,未配置时按服务名走服务发现
@FeignClient(contextId = "remoteWmsServiceFeign",value = ServiceNameConstants.WMS_SERVICE,url = "http://10.102.192.32:8016",fallbackFactory = RemoteWmsFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface WmsServiceFeign {
/**
@@ -91,18 +93,46 @@ public interface WmsServiceFeign {
/**
* oms下发单保存
* oms下发单保存(返回执行结果,失败时OMS据此回滚下发标记,避免"OMS已下发/WMS无数据"的阻断)
*/
@ApiOperation("oms下发单保存")
@PostMapping(value = "/stockInOrderApi/omsInOrderAdd")
public void omsInOrderAdd(@RequestBody StockInOrder stockInOrder);
public AjaxResult omsInOrderAdd(@RequestBody StockInOrder stockInOrder);
@ApiOperation("oms取消下发单保存")
@PostMapping(value = "/stockOutOrderApi/cancelExecutionOrder")
public AjaxResult omsCancelExecutionOrder(@RequestBody StockOutOrder stockOutOrder);
@ApiOperation("oms取消下发单自动分配")
@PostMapping(value = "/stockOutOrderApi/omsAutoAssign")
public void omsAutoAssign(@RequestBody StockOutOrderDTO stockOutOrderDTO);
@ApiOperation("oms出库执行")
@PostMapping(value = "/stockOutOrderApi/execution")
public AjaxResult execution(@RequestBody com.mhd.system.api.domain.StockOutOrderDTO stockOutOrderDTO);
/**
* oms下发单明细保存
* oms下发前库存校验:可用库存不足时返回错误,OMS据此在推送前拦截下发,
* 避免单据先落库、分配才失败而在WMS残留"已审核"状态的垃圾单
*/
@ApiOperation("oms下发前库存校验")
@PostMapping(value = "/stockOutOrderApi/checkOmsAssignInventory")
public AjaxResult checkOmsAssignInventory(@RequestBody List<OutMaterialDetail> outMaterialDetails);
/**
* oms下发单明细保存(返回执行结果,明细保存含自动审核链路,失败时OMS据此回滚)
*/
@ApiOperation("oms下发单明细保存")
@PostMapping(value = "/stockInOrderApi/omsInOrderAddDetail")
public void omsInOrderAddDetail(@RequestBody List<InMaterialDetail> inMaterialDetails);
public AjaxResult omsInOrderAddDetail(@RequestBody List<InMaterialDetail> inMaterialDetails);
/**
* oms取消下发入库执行单:WMS侧一个事务内逻辑删除下发链路产生的全部数据
* (入库单/明细、收货单/明细、收货任务、收货作业单/明细、质检单),已开始收货则报错拦截
*/
@ApiOperation("oms取消下发入库单清理")
@PostMapping(value = "/stockInOrderApi/omsCancelInOrder")
public AjaxResult omsCancelInOrder(@RequestBody StockInOrder stockInOrder);
@ApiOperation("oms查询物料列表")
@GetMapping("/materialBaseInfoApi/queryList")
@@ -121,4 +151,29 @@ public interface WmsServiceFeign {
*/
@GetMapping("/materialBaseInfoApi/getBatchByIds")
public TableDataInfo getBatchByIds(@RequestParam("materialBaseInfoIds") List<Long> materialBaseInfoIds);
/**
* 生成拣货单
*/
@ApiOperation("生成拣货单")
@PostMapping("/stockOutOrderApi/genPickingOrderByOms")
public AjaxResult genPickingOrderByOms(@RequestBody com.mhd.system.api.domain.StockOutOrderDTO stockOutOrderDTO);
/**
* OMS批量签名:更新WMS入/出库单签名字段
*
* <p>OMS端勾选记录批量签名后,通过此Feign调用WMS的 /stockSignatureApi/batchSign 接口,
* 同步更新WMS stock_in_order / stock_out_order 表的签名状态、签名时间、签名图片、签名备注。</p>
*/
@ApiOperation("OMS批量签名-同步WMS入/出库单签名字段")
@PostMapping("/stockSignatureApi/batchSign")
public AjaxResult batchSignWms(@RequestBody SignatureBatchFeignDTO dto);
/**
* OMS查询WMS线路管理列表(按线路编码模糊查,OMS侧自行精确匹配),
* 出库导入时校验送貨線號/車次并回填线路名称
*/
@ApiOperation("OMS查询WMS线路管理列表")
@GetMapping("/lineManagementApi/listByApp")
public AjaxResult listLineManagement(@RequestParam("routeCode") String routeCode);
}
@@ -0,0 +1,24 @@
package com.mhd.system.api;
import com.mhd.common.core.constant.ServiceNameConstants;
import com.mhd.common.core.domain.entity.R;
import com.mhd.common.core.domain.dto.YmsSysUserDTO;
import com.mhd.system.api.domain.YmsLoginUser;
import com.mhd.system.api.factory.RemoteBmsFeignFallbackFactory;
import com.mhd.system.api.factory.RemoteXxlJobFeignFallbackFactory;
import com.mhd.system.api.feign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
// 目标地址由 nacos 配置项 feign.url.xxl-job-service 指定,未配置时按服务名走服务发现
@FeignClient(contextId = "XxlJobService", value = ServiceNameConstants.XXL_JOB_SERVICE,url = "http://10.102.192.32:8020",fallbackFactory = RemoteXxlJobFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface XxlJobServiceFeign {
@GetMapping("/user/openFeignTest")
public R<Map<String, Object>> openFeignTest(@RequestParam("param") String string);
}
@@ -9,7 +9,8 @@ import com.mhd.system.api.feign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
@FeignClient(contextId = "YmsService", value = ServiceNameConstants.YMS_SERVICE,fallbackFactory = RemoteBmsFeignFallbackFactory.class,url = "http://10.102.192.4:8018", configuration = FeignAutoConfiguration.class)
// 目标地址由 nacos 配置项 feign.url.mhd-yms-service 指定,未配置时按服务名走服务发现
@FeignClient(contextId = "YmsService", value = ServiceNameConstants.YMS_SERVICE,url = "http://10.102.192.32:8018",fallbackFactory = RemoteBmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface YmsServiceFeign {
/**
@@ -0,0 +1,203 @@
package com.mhd.system.api.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.mhd.common.core.annotation.Excel;
import com.mhd.common.core.web.domain.BaseVOEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 业务单据对象 business_document
*
* @author gen
* @date 2024-06-21
*/
@Data
public class BusinessDocumentFeign extends BaseVOEntity{
private static final long serialVersionUID = 1L;
@ApiModelProperty("业务单据记录id")
@TableId(type = IdType.AUTO)
private Long businessDocumentId;
@ApiModelProperty("一级组织表ID")
@Excel(name = "一级组织表ID")
private Long topOrganizationId;
@ApiModelProperty("组织表ID")
@Excel(name = "组织表ID")
private Long organizationId;
@ApiModelProperty("组织名称")
@Excel(name = "组织名称")
private String organizationName;
@ApiModelProperty("业务流水")
@Excel(name = "业务流水")
private String businessFlow;
@ApiModelProperty("状态(1-未生效,2-已生效,3-已计费,4-已驳回,5-已作废")
@Excel(name = "状态", readConverterExp = "状态(1-未生效,2-已生效,3-已计费,4-已驳回,5-已作废")
private Integer businessState;
@ApiModelProperty("来源模块")
@Excel(name = "来源模块")
private String belongModule;
@ApiModelProperty("来源模块code")
@Excel(name = "来源模块code")
private String belongModuleCode;
@ApiModelProperty("数据来源(1-系统生成,2-手工录入)")
@Excel(name = "数据来源", readConverterExp = "1=-系统生成,2-手工录入")
private Integer dataSources;
@ApiModelProperty("单据类型id")
@Excel(name = "单据类型id")
private Long documentTypeId;
@ApiModelProperty("单据类型code")
@Excel(name = "单据类型code")
private String documentTypeCode;
@ApiModelProperty("单据类型")
@Excel(name = "单据类型")
private String documentType;
@ApiModelProperty("原始业务单号")
@Excel(name = "原始业务单号")
private String originalBusinessNum;
@ApiModelProperty("项目编码")
@Excel(name = "项目编码")
private String projectCode;
@ApiModelProperty("项目名称")
@Excel(name = "项目名称")
private String projectName;
@ApiModelProperty("合同编号")
@Excel(name = "合同编号")
private String contractNumber;
@ApiModelProperty("合同名称")
@Excel(name = "合同名称")
private String contractName;
@ApiModelProperty("账单金额")
@Excel(name = "账单金额")
private BigDecimal billAmount;
@ApiModelProperty("预计费金额")
@Excel(name = "预计费金额")
private BigDecimal estimatedCost;
@ApiModelProperty("一级费用科目code")
@Excel(name = "一级费用科目code")
private String firstSubjectCode;
@ApiModelProperty("一级费用科目(结算项)")
@Excel(name = "一级费用科目")
private String firstSubjectName;
@ApiModelProperty("二级费用科目code")
@Excel(name = "二级费用科目code")
private String secondSubjectCode;
@ApiModelProperty("二级费用科目(结算项)")
@Excel(name = "二级费用科目")
private String secondSubjectName;
@ApiModelProperty("结算对象id")
@Excel(name = "结算对象id")
private Long settlementCustomersId;
@ApiModelProperty("结算对象code")
@Excel(name = "结算对象code")
private String settlementCustomersCode;
@ApiModelProperty("结算对象")
@Excel(name = "结算对象")
private String settlementEntity;
@ApiModelProperty("计费时间")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "计费时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date billingTime;
@ApiModelProperty("单据表单json数据")
@Excel(name = "单据表单json数据")
private String documentFormJson;
@ApiModelProperty("合同管理id")
@Excel(name = "合同管理id", readConverterExp = "合同管理id")
private Long contractManageId;
@ApiModelProperty("项目管理id")
@Excel(name = "项目管理id", readConverterExp = "项目管理id")
private Long projectManageId;
@ApiModelProperty("原始流水号")
@Excel(name = "原始流水号")
private String originalSerialNumber;
@ApiModelProperty("费用类型code(服务项)")
@Excel(name = "费用类型code(服务项)")
private String serviceItemsCode;
@ApiModelProperty("费用类型")
@Excel(name = "费用类型")
private String serviceItemsName;
@ApiModelProperty("费用类型id(服务项)")
@Excel(name = "费用类型id(服务项)")
private Long serviceItemsManageId;
@ApiModelProperty("单据备注")
@Excel(name = "单据备注")
private String remark;
@ApiModelProperty("审核备注")
@Excel(name = "审核备注")
private String reviewRemarks;
@ApiModelProperty("结算方式(1-现金,2-油卡)")
private Integer settlementWay;
@ApiModelProperty("结算币种")
private String settlementCurrency;
@ApiModelProperty("业务员ID")
private String salesmanId;
@ApiModelProperty("业务员名称")
private String salesmanName;
@ApiModelProperty("税率")
private Double taxRate;
@ApiModelProperty("收款帐户")
private String paymentAccountId;
@ApiModelProperty("收款帐户名称")
private String paymentAccountName;
@ApiModelProperty("计费单位")
private String billingUnit;
@ApiModelProperty("计费单位2")
private String billingUnit2;
@ApiModelProperty("计费数量")
private BigDecimal billingNum;
@ApiModelProperty("计费单价")
private BigDecimal billingUnitPrice;
@ApiModelProperty("nc科目编码")
private String ncSubjectCode;
@ApiModelProperty("是否推送")
private Integer isPush;
@ApiModelProperty("仓库类型")
private String warehouseType;
}
@@ -0,0 +1,110 @@
package com.mhd.system.api.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.mhd.common.core.annotation.Excel;
import com.mhd.common.core.web.domain.BaseVOEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 合同管理详情对象 contract_manage_detail
*
* @author gen
* @date 2024-06-07
*/
@Data
public class ContractManageDetailFeignDTO extends BaseVOEntity{
private static final long serialVersionUID = 1L;
@ApiModelProperty("合同管理详情id")
private Long contractManageDetailId;
@ApiModelProperty("合同管理id")
@Excel(name = "合同管理id")
private Long contractManageId;
@ApiModelProperty("一级组织表ID")
@Excel(name = "一级组织表ID")
private Long topOrganizationId;
@ApiModelProperty("组织表ID")
@Excel(name = "组织表ID")
private Long organizationId;
@ApiModelProperty("组织名称")
@Excel(name = "组织名称")
private String organizationName;
@ApiModelProperty("结算科目类型(1-通用,2-临时)")
@Excel(name = "结算科目类型", readConverterExp = "1=-通用,2-临时")
private Integer subjectType;
@ApiModelProperty("一级费用科目code")
@Excel(name = "一级费用科目code")
private String firstSubjectCode;
@ApiModelProperty("一级费用科目")
@Excel(name = "一级费用科目")
private String firstSubjectName;
@ApiModelProperty("二级费用科目code")
@Excel(name = "二级费用科目code")
private String secondSubjectCode;
@ApiModelProperty("二级费用科目")
@Excel(name = "二级费用科目")
private String secondSubjectName;
@ApiModelProperty("计费策略id")
@Excel(name = "计费策略id")
private Long accountingStrategyId;
@ApiModelProperty("计费策略")
@Excel(name = "计费策略")
private String accountingStrategy;
@ApiModelProperty("计费策略编码")
@Excel(name = "计费策略编码")
private String accountingStrategyCode;
@ApiModelProperty("计费周期")
@Excel(name = "计费周期")
private String billingAttributes;
@ApiModelProperty("计费周期编码")
@Excel(name = "计费周期编码")
private String billingAttributesCode;
@ApiModelProperty("合同有效日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "合同有效日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date subjectEffectiveDate;
@ApiModelProperty("合同到期日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "合同到期日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date subjectExpirationDate;
@ApiModelProperty(name = "组织ID集合")
private List<Long> organizationIdList;
@ApiModelProperty(name = "权限菜单ID")
private Long permissionMenuId;
@ApiModelProperty("单据类型code")
private String documentTypeCode;
@ApiModelProperty("单据类型")
private String documentType;
@ApiModelProperty("费用类别编码")
private String serviceItemsCode;
@ApiModelProperty("费用类别名称")
private String serviceItemsName;
}
@@ -0,0 +1,228 @@
package com.mhd.system.api.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.mhd.common.core.annotation.Excel;
import com.mhd.common.core.web.domain.BaseVOEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 合同管理对象 contract_manage
*
* @author gen
* @date 2024-06-07
*/
@Data
public class ContractManageFeignDTO extends BaseVOEntity{
private static final long serialVersionUID = 1L;
@ApiModelProperty("合同管理id")
private Long contractManageId;
@ApiModelProperty("一级组织表ID")
@Excel(name = "一级组织表ID")
private Long topOrganizationId;
@ApiModelProperty("组织表ID")
@Excel(name = "组织表ID")
private Long organizationId;
@ApiModelProperty("组织名称")
@Excel(name = "组织名称")
private String organizationName;
@ApiModelProperty("原始合同编号")
@Excel(name = "原始合同编号")
private String originalContractNumber;
@ApiModelProperty("合同编号")
@Excel(name = "合同编号")
private String contractNumber;
@ApiModelProperty("合同名称")
@Excel(name = "合同名称")
private String contractName;
@ApiModelProperty("是否通用合同(1-是,2-否)")
@Excel(name = "是否通用合同", readConverterExp = "1=-是,2-否")
private Integer commonContractFlag;
@ApiModelProperty("合同类型(1-仓储,2-运输,3-其他)")
@Excel(name = "合同类型", readConverterExp = "1=-仓储,2-运输,3=-其他")
private Integer contractType;
@ApiModelProperty("合同状态(1-未生效,2-使用中,3-已过期,4-已作废)")
@Excel(name = "合同状态", readConverterExp = "1=-未生效,2-使用中,3-已过期,4-已作废")
private Integer contractState;
@ApiModelProperty("签订单位")
@Excel(name = "签订单位")
private String signingUnit;
@ApiModelProperty("结算主体")
@Excel(name = "结算主体")
private String settlementCustomers;
@ApiModelProperty("结算主体id")
@Excel(name = "结算主体id")
private Long settlementCustomersId;
@ApiModelProperty("结算主体code")
@Excel(name = "结算主体code")
private String settlementCustomersCode;
@ApiModelProperty("我司身份(1-甲方,2-乙方)")
@Excel(name = "我司身份", readConverterExp = "1=-甲方,2-乙方")
private Integer ourIdentity;
@ApiModelProperty("账期(1-每月,2-双月,3-季度)")
@Excel(name = "账期", readConverterExp = "1=-每月,2-双月,3-季度")
private Integer accountingPeriod;
@ApiModelProperty("合同签订日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "合同签订日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date signingDate;
@ApiModelProperty("合同生效日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "合同生效日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date effectiveDate;
@ApiModelProperty("合同到期日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "合同到期日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date expirationDate;
@ApiModelProperty("备注")
@Excel(name = "备注")
private String remark;
@ApiModelProperty("合同正本附件地址")
@Excel(name = "合同正本附件地址")
private String contractOriginalUrl;
@ApiModelProperty("廉政协议附件地址")
@Excel(name = "廉政协议附件地址")
private String integrityAgreementUrl;
@ApiModelProperty("安全协议附件地址")
@Excel(name = "安全协议附件地址")
private String securityProtocolUrl;
@ApiModelProperty("其他附件地址")
@Excel(name = "其他附件地址")
private String otherAttachmentsUrl;
@ApiModelProperty("合同正本附件原始文件名")
private String contractOriginalName;
@ApiModelProperty("廉政协议附件原始文件名")
private String integrityAgreementName;
@ApiModelProperty("安全协议附件原始文件名")
private String securityProtocolName;
@ApiModelProperty("其他附件原始文件名(多文件时与 otherAttachmentsUrl 同分隔符、同顺序)")
private String otherAttachmentsName;
@ApiModelProperty("我司签订人")
@Excel(name = "我司签订人")
private String ourSinged;
@ApiModelProperty("我司签订人联系方式")
@Excel(name = "我司签订人联系方式")
private String ourSingedPhone;
@ApiModelProperty("我司经办人")
@Excel(name = "我司经办人")
private String ourOperator;
@ApiModelProperty("我司经办人联系方式")
@Excel(name = "我司经办人联系方式")
private String ourOperatorPhone;
@ApiModelProperty("对方签订人")
@Excel(name = "对方签订人")
private String theySinged;
@ApiModelProperty("对方签订人联系方式")
@Excel(name = "对方签订人联系方式")
private String theySingedPhone;
@ApiModelProperty("对方经办人")
@Excel(name = "对方经办人")
private String theyOperator;
@ApiModelProperty("对方经办人联系方式")
@Excel(name = "对方经办人联系方式")
private String theyOperatorPhone;
@ApiModelProperty(name = "组织ID集合")
private List<Long> organizationIdList;
@ApiModelProperty(name = "权限菜单ID")
private Long permissionMenuId;
@ApiModelProperty(name = "合同科目详情列表")
private List<ContractManageDetailFeignDTO> contractManageDetailDTOList;
@ApiModelProperty("合同管理ids")
private String contractManageIds;
@ApiModelProperty(name = "合同签订查询条件开始日期")
private String signingDateStart;
@ApiModelProperty(name = "合同签订查询条件结束日期")
private String signingDateEnd;
@ApiModelProperty(name = "合同生效查询条件开始日期")
private String effectiveDateStart;
@ApiModelProperty(name = "合同生效查询条件结束日期")
private String effectiveDateEnd;
@ApiModelProperty(name = "合同到期查询条件开始日期")
private String expirationDateStart;
@ApiModelProperty(name = "合同到期查询条件结束日期")
private String expirationDateEnd;
@ApiModelProperty(name = "结算主体基础数据id(可以是用户id也可以是企业id)")
private String settlementId;
@ApiModelProperty(name = "是否自动出账(1-是,2-否)")
private Integer automaticFlag;
@ApiModelProperty("出账日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date paymentDate;
@ApiModelProperty(name = "出账天数")
private Integer billDays;
@ApiModelProperty(name = "主体类型(1-货主,2-客户,3-承运商)")
private Integer principalType;
@ApiModelProperty("客户类型")
private String customerType;
@ApiModelProperty("客户类型编码")
private String customerTypeCode;
@ApiModelProperty(name = "是否包含运输费用(1-包含,2-包含)")
private Integer transportationCosts;
@ApiModelProperty("客户类型")
private String contractRentType;
@ApiModelProperty("客户类型编码")
private String contractRentTypeName;
@ApiModelProperty("仓库温层类型")
private String warehouseTempLayerType;
@ApiModelProperty("仓库温层类型编码")
private String warehouseTempLayerTypeName;
}
@@ -0,0 +1,52 @@
package com.mhd.system.api.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.mhd.common.core.annotation.Excel;
import com.mhd.common.core.web.domain.BaseVOEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 合约信息规则维护表
*
* @author gen
* @date 2024-06-07
*/
@Data
public class ContractManageParametersFeign extends BaseVOEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("合同管理id")
@TableId(type = IdType.AUTO)
private Long id;
@ApiModelProperty("合同管理id")
private Long contractManageId;
@ApiModelProperty("一级组织表ID")
@Excel(name = "一级组织表ID")
private Long topOrganizationId;
@ApiModelProperty("组织表ID")
@Excel(name = "组织表ID")
private Long organizationId;
@ApiModelProperty("组织名称")
@Excel(name = "组织名称")
private String organizationName;
@ApiModelProperty("合同编号")
@Excel(name = "合同编号")
private String contractNumber;
@ApiModelProperty("合同名称")
@Excel(name = "合同名称")
private String contractName;
@ApiModelProperty("合约信息规则维护")
@Excel(name = "合约信息规则维护表")
private String parametersJson;
}
@@ -0,0 +1,108 @@
package com.mhd.system.api.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
* 电子签名同步DTOWMS端通过Feign调用OMS
*/
@Data
public class ElectronicSignatureSyncDTO {
@ApiModelProperty("订单ID")
private Long orderId;
@ApiModelProperty("订单号")
private String orderNumber;
@ApiModelProperty("订单类型:IN-入库 OUT-出库")
private String orderType;
@ApiModelProperty("组织ID")
private Long organizationId;
@ApiModelProperty("组织名称")
private String organizationName;
@ApiModelProperty("一级组织ID")
private Long topOrganizationId;
@ApiModelProperty("仓库ID")
private Long warehouseId;
@ApiModelProperty("仓库编码")
private String warehouseCode;
@ApiModelProperty("仓库名称")
private String warehouseName;
@ApiModelProperty("创建人")
private Long createBy;
@ApiModelProperty("创建人姓名")
private String createByName;
@ApiModelProperty("物料明细列表")
private List<MaterialDetailItem> materialDetailList;
@Data
public static class MaterialDetailItem {
@ApiModelProperty("物料基础信息ID")
private Long materialBaseInfoId;
@ApiModelProperty("物料编码")
private String materialCode;
@ApiModelProperty("物料名称")
private String materialName;
@ApiModelProperty("数量")
private BigDecimal quantity;
@ApiModelProperty("单位代码")
private String unitCode;
@ApiModelProperty("单位名称")
private String unitName;
@ApiModelProperty("批次号")
private String batchNumber;
@ApiModelProperty("LOT编号")
private String lotNumber;
@ApiModelProperty("仓库ID")
private Long warehouseId;
@ApiModelProperty("仓库编码")
private String warehouseCode;
@ApiModelProperty("仓库名称")
private String warehouseName;
@ApiModelProperty("库区ID")
private Long storageSectionId;
@ApiModelProperty("库区编码")
private String storageSectionCode;
@ApiModelProperty("库区名称")
private String storageSectionName;
@ApiModelProperty("库位ID")
private Long storageLocationId;
@ApiModelProperty("库位编码")
private String storageLocationCode;
@ApiModelProperty("库位名称")
private String storageLocationName;
@ApiModelProperty("业务唯一ID")
private Long uniqueId;
}
}
@@ -240,9 +240,7 @@ public class InMaterialDetail extends BaseVOEntity {
@ApiModelProperty("父级唯一Id")
private Long parentUniqueId;
@ApiModelProperty("备注")
@Excel(name = "备注")
private String remark;
@ApiModelProperty("越库单id")
private Long overStockId;
@@ -376,4 +374,29 @@ public class InMaterialDetail extends BaseVOEntity {
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date drinkDate;
@ApiModelProperty("过期日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date expiryDate;
@ApiModelProperty("来货验收是否合格;1 合格,0 不合格")
@Excel(name = "来货验收是否合格;1 合格,0 不合格")
private String arrivalAcceptQualified;
@ApiModelProperty("包装是否破损;1 破损,0 完好")
@Excel(name = "包装是否破损;1 破损,0 完好")
private String packageDamaged;
@ApiModelProperty("是否解冻 / 水渍;1 是,0 否")
@Excel(name = "是否解冻 / 水渍;1 是,0 否")
private String isThawWaterstain;
@ApiModelProperty("问题货是否已通知客户;1 已通知,0 未通知")
@Excel(name = "问题货是否已通知客户;1 已通知,0 未通知")
private String notifyCustomerAbnormal;
@ApiModelProperty("备注")
@Excel(name = "备注")
private String remark;
}
@@ -244,4 +244,26 @@ public class MaterialBaseInfoFeign extends BaseVOEntity{
@ApiModelProperty(name = "单位")
private String unit;
@ApiModelProperty(name = "组织(多个用,分开)")
private String orgId;
@ApiModelProperty(name = "是否正常物料: 0-是 1-否")
private Integer isNormalMaterial;
@ApiModelProperty("每月仓租")
@Excel(name = "每月仓租")
private BigDecimal monthlyWarehouseRent;
@ApiModelProperty("半月仓租")
@Excel(name = "半月仓租")
private BigDecimal halfMonthWarehouseRent;
@ApiModelProperty("每月仓租单位")
@Excel(name = "每月仓租单位")
private String monthlyWarehouseRentUnit;
@ApiModelProperty("半月仓租单位")
@Excel(name = "半月仓租单位")
private String halfMonthWarehouseRentUnit;
}
@@ -83,5 +83,9 @@ public class MaterialInventoryOmsParamDO extends BaseVOEntity {
private Date productionDate;
//过期日期
private Date expiryDate;
//进货日期
private Date purchaseDate;
private String executioOrderNumber;
}
@@ -0,0 +1,42 @@
package com.mhd.system.api.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;
/**
* OMS→WMS 批量签名 Feign DTO
*
* <p>OMS端批量签名时,通过此DTO调用WMS的批量签名接口,
* 更新WMS stock_in_order / stock_out_order 表的签名字段。</p>
*/
@Data
public class SignatureBatchFeignDTO {
@ApiModelProperty("入库单ID列表")
private List<Long> inOrderIds;
@ApiModelProperty("出库单ID列表")
private List<Long> outOrderIds;
@ApiModelProperty("签名状态:2-已签名")
private Integer signatureStatus;
@ApiModelProperty("签名时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date signatureTime;
@ApiModelProperty("手写签名图片(base64或URL,单张)")
private String signaturePic;
@ApiModelProperty("拍照取证图片(逗号分隔多张URL")
private String evidencePics;
@ApiModelProperty("签名备注")
private String signatureRemark;
}
@@ -50,8 +50,8 @@ public class StockOutOrder extends BaseVOEntity {
@Excel(name = "出库单号")
private String outOrderNumber;
@ApiModelProperty("出库状态: 1-已创建 2-已审核 3-部分分配 4-已分配 5-波次中 6-拣货中 7-拣货完成 8-复核中 9-已出库 10-已取消 11-已关闭 12-已复核")
@Excel(name = "出库状态: 1-已创建 2-已审核 3-部分分配 4-已分配 5-波次中 6-拣货中 7-拣货完成 8-复核中 9-已出库 10-已取消 11-已关闭 12-已复核")
@ApiModelProperty("出库状态: 1-已创建 2-已审核 3-部分分配 4-已分配 5-波次中 6-拣货中 7-拣货完成 8-复核中 9-已出库 10-已取消 11-已关闭 12-已复核 13-已交接")
@Excel(name = "出库状态: 1-已创建 2-已审核 3-部分分配 4-已分配 5-波次中 6-拣货中 7-拣货完成 8-复核中 9-已出库 10-已取消 11-已关闭 12-已复核 13-已交接")
private Integer status;
@ApiModelProperty("出库单审核状态: 1-未审核 2-审核不通过 3-审核通过")
@@ -405,4 +405,13 @@ public class StockOutOrder extends BaseVOEntity {
@Excel(name = "车次")
private Integer trainNo;
@ApiModelProperty("线路编码(取自WMS线路管理)")
private String lineCode;
@ApiModelProperty("线路名称(冗余存储)")
private String lineName;
@ApiModelProperty("车次序号(显示: 线路编码-车次, 如31-4)")
private String shuttleNo;
}
@@ -0,0 +1,486 @@
package com.mhd.system.api.domain;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.mhd.common.core.annotation.Excel;
import com.mhd.common.core.web.domain.BaseVOEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* 出库单对象 stock_out_order
*
* @author gen
* @date 2024-05-28
*/
@Data
public class StockOutOrderDTO extends BaseVOEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("出库单id")
private Long outOrderId;
@ApiModelProperty("组织表ID")
@Excel(name = "组织表ID")
private Long organizationId;
@ApiModelProperty("组织名称")
@Excel(name = "组织名称")
private String organizationName;
@ApiModelProperty("一级组织表ID")
@Excel(name = "一级组织表ID")
private Long topOrganizationId;
@ApiModelProperty("通知单号")
@Excel(name = "通知单号")
private String noticeNumber;
@ApiModelProperty("出库单号")
@Excel(name = "出库单号")
private String outOrderNumber;
@ApiModelProperty("出库状态: 1-已创建 2-已审核 3-部分分配 4-已分配 5-波次中 6-拣货中 7-拣货完成 8-复核中 9-已出库 10-已取消 11-已关闭")
@Excel(name = "出库状态: 1-已创建 2-已审核 3-部分分配 4-已分配 5-波次中 6-拣货中 7-拣货完成 8-复核中 9-已出库 10-已取消 11-已关闭")
private Integer status;
@ApiModelProperty("出库单审核状态: 1-未审核 2-审核不通过 3-审核通过")
@Excel(name = "出库单审核状态: 1-未审核 2-审核不通过 3-审核通过")
private Integer auditStatus;
@ApiModelProperty("出库单审核备注")
@Excel(name = "出库单审核备注")
private String auditRemark;
@ApiModelProperty("出库单审核人")
@Excel(name = "出库单审核人")
private Long auditBy;
@ApiModelProperty("出库单审核人姓名")
@Excel(name = "出库单审核人姓名")
private String auditByName;
@ApiModelProperty("出库单审核时间")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "出库单审核时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date auditTime;
@ApiModelProperty("仓库id")
@Excel(name = "仓库id")
private Long warehouseId;
@ApiModelProperty("仓库编码")
@Excel(name = "仓库编码")
private String warehouseCode;
@ApiModelProperty("仓库名称")
@Excel(name = "仓库名称")
private String warehouseName;
@ApiModelProperty("货主id")
@Excel(name = "货主id")
private Long shipperId;
@ApiModelProperty("货主编码")
@Excel(name = "货主编码")
private String shipperCode;
@ApiModelProperty("货主名称")
@Excel(name = "货主名称")
private String shipperName;
@ApiModelProperty("出库单类型编码")
@Excel(name = "出库单类型编码")
private String orderTypeCode;
@ApiModelProperty("出库单类型名称")
@Excel(name = "出库单类型名称")
private String orderTypeName;
@ApiModelProperty("客户id")
@Excel(name = "客户id")
private Long customerId;
@ApiModelProperty("客户编码")
@Excel(name = "客户编码")
private String customerCode;
@ApiModelProperty("客户名称")
@Excel(name = "客户名称")
private String customerName;
@ApiModelProperty("预计出货时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Excel(name = "预计出货时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date expectTime;
@ApiModelProperty("供应链订单号")
@Excel(name = "供应链订单号")
private String supplyChainNumber;
@ApiModelProperty("优先级别编码")
@Excel(name = "优先级别编码")
private String priorityLevelCode;
@ApiModelProperty("优先级别名称")
@Excel(name = "优先级别名称")
private String priorityLevelName;
@ApiModelProperty("是否直接出库: 1-是 2-否")
@Excel(name = "是否直接出库: 1-是 2-否")
private Integer directWarehouse;
@ApiModelProperty("是否复核: 1-是 2-否")
@Excel(name = "是否复核: 1-是 2-否")
private Integer review;
@ApiModelProperty("附件url")
@Excel(name = "附件url")
private String annexUrl;
@ApiModelProperty("物料种数")
@Excel(name = "物料种数")
private Integer materialQuantity;
@ApiModelProperty("计划数量")
@Excel(name = "计划数量")
private BigDecimal quantity;
@ApiModelProperty("净重 单位:千克")
@Excel(name = "净重 单位:千克")
private BigDecimal weightLimit;
@ApiModelProperty("体积 单位:立方米")
@Excel(name = "体积 单位:立方米")
private BigDecimal volumeLimit;
@ApiModelProperty("分配数量")
@Excel(name = "分配数量")
private BigDecimal allocationQuantity;
@ApiModelProperty("已生成拣货单数量")
@Excel(name = "已生成拣货单分配数量")
private BigDecimal alreadyAllocationQuantity;
@ApiModelProperty("拣货数量")
@Excel(name = "拣货数量")
private BigDecimal pickingQuantity;
@ApiModelProperty("复核数量")
@Excel(name = "复核数量")
private BigDecimal checkQuantity;
@ApiModelProperty("是否取消订单: 1-是 2-否")
@Excel(name = "是否取消订单: 1-是 2-否")
private Integer cancelOrder;
@ApiModelProperty("取消订单备注")
@Excel(name = "取消订单备注")
private String cancelRemark;
@ApiModelProperty("取消订单人")
@Excel(name = "取消订单人")
private Long cancelBy;
@ApiModelProperty("取消订单人姓名")
@Excel(name = "取消订单人姓名")
private String cancelByName;
@ApiModelProperty("取消订单时间")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "取消订单时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date cancelTime;
@ApiModelProperty("是否关闭订单: 1-是 2-否")
@Excel(name = "是否关闭订单: 1-是 2-否")
private Integer closeOrder;
@ApiModelProperty("关闭订单备注")
@Excel(name = "关闭订单备注")
private String closeRemark;
@ApiModelProperty("关闭订单人")
@Excel(name = "关闭订单人")
private Long closeBy;
@ApiModelProperty("关闭订单人姓名")
@Excel(name = "关闭订单人姓名")
private String closeByName;
@ApiModelProperty("关闭订单时间")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "关闭订单时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date closeTime;
@ApiModelProperty("复核状态: 1-未复核 2-复核中 3-已复核")
@Excel(name = "复核状态: 1-未复核 2-复核中 3-已复核")
private Integer checkStatus;
@ApiModelProperty("复核任务是否下发: 1-是 2-否")
@Excel(name = "复核任务是否下发: 1-是 2-否")
private Integer checkTaskDistribution;
@ApiModelProperty("复核任务下发时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "复核任务下发时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date checkTaskDistributionTime;
@ApiModelProperty("复核作业人用户ID")
@Excel(name = "复核作业人用户ID")
@JsonAlias({"checkOperatorId", "operatorId"})
private Long checkOperatorsBy;
@ApiModelProperty("复核作业人姓名")
@Excel(name = "复核作业人姓名")
private String checkOperatorsName;
@ApiModelProperty("调度单号")
@Excel(name = "调度单号")
private String mobilizeCode;
@ApiModelProperty("备注")
@Excel(name = "备注")
private String remark;
@ApiModelProperty(name = "组织ID集合")
private List<Long> organizationIdList;
@ApiModelProperty(name = "权限菜单ID")
private Long permissionMenuId;
@ApiModelProperty("出库单id集合")
private List<Long> outOrderIds;
// @ApiModelProperty("物料明细")
// private List<OutMaterialDetailDTO> materialDetailList;
@ApiModelProperty("物料条形码")
@Excel(name = "物料条形码")
private String barCode;
@ApiModelProperty("物料审核数量")
@Excel(name = "物料审核数量")
private BigDecimal actualQuantity;
@ApiModelProperty("波次类型编码")
private String waveOrderTypeCode;
@ApiModelProperty("大于复核状态: 1-未复核 2-复核中 3-已复核")
private Integer gtCheckStatus;
@ApiModelProperty("小于复核状态: 1-未复核 2-复核中 3-已复核")
private Integer ltCheckStatus;
@ApiModelProperty("PDA复核查询tab: 1-列表(待复核) 2-历史记录(已复核)")
private Integer tabType;
@ApiModelProperty("to")
@Excel(name = "to")
private String to;
@ApiModelProperty("联系人")
@Excel(name = "联系人")
private String contactPerson;
@ApiModelProperty("车型及车牌")
@Excel(name = "车型及车牌")
private String vehicleModelPlate;
@ApiModelProperty("委托编号")
@Excel(name = "委托编号")
private String entrustNo;
@ApiModelProperty("Tel")
@Excel(name = "Tel")
private String tel;
@ApiModelProperty("司机签名")
@Excel(name = "司机签名")
private String driverSign;
@ApiModelProperty("Fax")
@Excel(name = "Fax")
private String fax;
@ApiModelProperty("申报地关区")
@Excel(name = "申报地关区")
private String declareCustoms;
@ApiModelProperty("生产商")
@Excel(name = "生产商")
private String manufacturer;
@ApiModelProperty("报关员姓名及联系方式")
@Excel(name = "报关员姓名及联系方式")
private String customsDeclarerInfo;
@ApiModelProperty("送货地址")
@Excel(name = "送货地址")
private String deliveryAddr;
@ApiModelProperty("进出境关别")
@Excel(name = "进出境关别")
private String entryExitCustoms;
@ApiModelProperty("起运/运抵国(地区)")
@Excel(name = "起运/运抵国(地区)")
private String departureArrivalCountry;
@ApiModelProperty("承运商")
@Excel(name = "承运商")
private String carrier;
@ApiModelProperty("柜号")
@Excel(name = "柜号")
private String containerNo;
@ApiModelProperty("")
@Excel(name = "")
private String containerNoName;
@ApiModelProperty("出仓日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "出仓日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date outboundDate;
@ApiModelProperty("完成时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "完成时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date completeTime;
@ApiModelProperty("orderDate")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "orderDate", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date orderDate;
@ApiModelProperty("运输方式")
@Excel(name = "运输方式")
private String transportModeCode;
@ApiModelProperty("运输方式")
@Excel(name = "运输方式")
private String transportModeName;
@ApiModelProperty("监管方式")
@Excel(name = "监管方式")
private String supervisionModeCode;
@ApiModelProperty("监管方式")
@Excel(name = "监管方式")
private String supervisionModeName;
@ApiModelProperty("海关是否查验货物")
@Excel(name = "海关是否查验货物")
private String customsInspectionFlag;
@ApiModelProperty("是否需要报关")
@Excel(name = "是否需要报关")
private String needDeclareFlag;
@ApiModelProperty("是否需要运输")
@Excel(name = "是否需要运输")
private String needTransportFlag;
@ApiModelProperty(name = "创建时间查询条件开始日期")
private String createTimeStart;
@ApiModelProperty(name = "创建时间查询条件结束日期")
private String createTimeEnd;
@ApiModelProperty(name = "审核时间查询条件开始日期")
private String auditTimeStart;
@ApiModelProperty(name = "审核时间查询条件结束日期")
private String auditTimeEnd;
@ApiModelProperty("出库明细-物料名称(商品名称),模糊匹配,与前端参数 materialName 一致")
private String materialName;
@ApiModelProperty("出库明细-物料编码,模糊匹配,与前端参数 materialCode 一致")
private String materialCode;
@ApiModelProperty("出库交接图片,PDA出库交接时上传的照片,多张图片以逗号隔开")
private String pictureApp;
@ApiModelProperty("业务单号")
@Excel(name = "业务单号")
private String businessOrderNo;
@ApiModelProperty("业务类型")
@Excel(name = "业务类型")
private String businessType;
@ApiModelProperty("制单人")
@Excel(name = "制单人")
private String documentCreator;
@ApiModelProperty("制单人名称")
@Excel(name = "制单人名称")
private String documentCreatorName;
@ApiModelProperty("制单日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@Excel(name = "制单日期", width = 30, dateFormat = "yyyy-MM-dd")
private Date documentDate;
@ApiModelProperty("承运商名称")
@Excel(name = "承运商名称")
private String carrierName;
@ApiModelProperty("计费信息")
private String billingJson;
@ApiModelProperty("结算币种")
private String settlementCurrency;
@ApiModelProperty("业务员ID")
private String salesmanId;
@ApiModelProperty("业务员名称")
private String salesmanName;
// @ApiModelProperty("费用")
// List<ReceiptOrderAccount> receiptOrderAccountList;
@ApiModelProperty("退货数量")
@Excel(name = "退货数量")
private BigDecimal returnQuantity;
/**
* 提货单打印所选模版(与图5单选项文案一致即可)。可传副标题如「谷丰--营销部」,或整段「提货单--谷丰--营销部」;不传则标题为「提货单」
*/
@ApiModelProperty("提货单打印模版名/弹窗选项全文;后端生成 printTitle(-- 会规范为 ——)")
private String noticePrintTemplateName;
@ApiModelProperty("车次")
@Excel(name = "车次")
private Integer trainNo;
@ApiModelProperty("推送状态:1-未推送,2-推送中,3-推送成功,4-推送失败")
private Integer pushStatus;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("推送时间")
private Date pushTime;
@ApiModelProperty("推送人")
private Long pushBy;
@ApiModelProperty("推送人姓名")
private String pushByName;
@ApiModelProperty(value = "推送时间起")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date pushTimeFrom;
@ApiModelProperty(value = "推送时间止")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date pushTimeTo;
@ApiModelProperty(value = "推送时间起")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTimeFrom;
@ApiModelProperty(value = "推送时间止")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTimeTo;
}
@@ -46,8 +46,8 @@ TmsOrderAddDTO implements Serializable {
@ApiModelProperty(value = "装货电话")
private String loadingPhone="";
@ApiModelProperty(value = "装货时间日期(年月日)",required = true)
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern="yyyy-MM-dd")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
private java.util.Date loadingDate;
// @ApiModelProperty(value = "装货时间(上午、下午、24小时)")
// private String loadingTime="";
@@ -116,6 +116,28 @@ public class WarehouseFeignPO extends BaseVOEntity{
@Excel(name = "是否作废: 1-否 2-是")
private Integer nullify;
@ApiModelProperty("任务模式")
@Excel(name = "任务模式")
private String taskMode;
@ApiModelProperty("作业模式")
@Excel(name = "作业模式")
private String workMode;
}
@ApiModelProperty("订单号生成规则(0-日期累加 1-历史累加)")
@Excel(name = "单号生成规则")
private String orderNoGenerateRule;
@ApiModelProperty("入库单号首字母前缀")
@Excel(name = "入库单号首字母前缀")
private String inOrderNoPrefix;
@ApiModelProperty("出库单号首字母前缀")
@Excel(name = "出库单号首字母前缀")
private String outOrderNoPrefix;
@ApiModelProperty("样品出库单号首字母前缀")
@Excel(name = "样品出库单号首字母前缀")
private String sampleOutOrderNoPrefix;
}
@@ -0,0 +1,30 @@
package com.mhd.system.api.domain;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 仓库联动树节点(Feign侧)
* 镜像system端WarehouseLinkagePO/StorageSectionLinkagePO/StorageLocationLinkagePO三级结构:仓库→库区→库位
*
* @author rcx
* @date 2026-08-22
*/
@Data
public class WarehouseLinkageFeignPO implements Serializable {
private static final long serialVersionUID = 1L;
/** 仓库id / 库区id(storageSectionId) / 库位id(storageLocationId) */
private Long id;
/** warehouseCode / storageCode / storageLocationCode */
private String code;
/** warehouseName / storageName / storageLocationName */
private String name;
/** 下级节点:仓库下为库区列表,库区下为库位列表,库位无children */
private List<WarehouseLinkageFeignPO> children;
}
@@ -6,6 +6,7 @@ import com.mhd.common.core.domain.po.OrganizationPo;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.system.api.BmsServiceFeign;
import com.mhd.system.api.ProductServiceFeign;
import com.mhd.system.api.domain.BusinessDocumentFeign;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
@@ -66,6 +67,21 @@ public class RemoteBmsFeignFallbackFactory implements FallbackFactory<BmsService
public AjaxResult wholeRentSynchronizationZXF(BusinessDataPushDTO businessDataPushDTO) {
return null;
}
@Override
public AjaxResult feignSaveBusinessDocument(BusinessDocumentFeign businessDocumentFeign) {
return AjaxResult.error("保存业务单据失败");
}
@Override
public AjaxResult getListBySettlementCustomersId(Long settlementCustomersId) {
return AjaxResult.error(throwable.getMessage());
}
@Override
public AjaxResult updatePushContractManageJobId(Long settlementCustomersId, Integer jobId) {
return AjaxResult.error(throwable.getMessage());
}
};
}
}
}
@@ -41,6 +41,11 @@ public class RemoteOmsFeignFallbackFactory implements FallbackFactory<OmsService
return null;
}
@Override
public AjaxResult returnInResult(String orderNumber, Long status, String type) {
return null;
}
@Override
public AjaxResult pushOutOrder(StockOutOrderTZPD stockOutOrder) {
return null;
@@ -90,6 +95,11 @@ public class RemoteOmsFeignFallbackFactory implements FallbackFactory<OmsService
public AjaxResult batchPushByNumber(List<String> numberList) {
return null;
}
@Override
public AjaxResult saveSignature(ElectronicSignatureSyncDTO saveDTO) {
return null;
}
};
}
}
@@ -13,6 +13,8 @@ import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.system.api.AssociationWarehouseFeign;
import com.mhd.system.api.SystemServiceFeign;
import com.mhd.system.api.domain.ContainerFeignPO;
import com.mhd.system.api.domain.ContractManageFeignDTO;
import com.mhd.system.api.domain.ContractManageParametersFeign;
import com.mhd.system.api.domain.SysDictData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -20,6 +22,7 @@ import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@@ -184,6 +187,11 @@ public class RemoteSystemFeignFallbackFactory implements FallbackFactory<SystemS
return AjaxResult.error("根据仓库ID获取仓库信息失败");
}
@Override
public AjaxResult getWarehouseChildren(@RequestParam("warehouseId") Long warehouseId) {
return AjaxResult.error("根据仓库ID获取仓库及下库区及库位树失败");
}
@Override
public AjaxResult getStorageSectionInfoByStorageSectionId(@PathVariable("storageSectionId") Long storageSectionId) {
return AjaxResult.error("根据库区ID获取库区信息失败");
@@ -284,6 +292,10 @@ public class RemoteSystemFeignFallbackFactory implements FallbackFactory<SystemS
return AjaxResult.error("查询失败");
}
@Override
public AjaxResult getInfoByCustomerAndSecondSubjectCode(String settlementCustomersCode, Integer contractType, String firstSubjectCode, Long topOrganizationId, Long organizationId) {
return null;
}
@Override
public AjaxResult getInfoByCustomer2(String settlementCustomersCode, Integer contractType, Long topOrganizationId) {
return AjaxResult.error("查询失败");
@@ -308,6 +320,16 @@ public class RemoteSystemFeignFallbackFactory implements FallbackFactory<SystemS
public AjaxResult matchForMaterialImport(String keyword, Long organizationId) {
return AjaxResult.error("物料分类匹配失败");
}
@Override
public AjaxResult feignSave(ContractManageFeignDTO contractManageFeignDTO) {
return AjaxResult.error("新增合同失败");
}
@Override
public AjaxResult feignSaveContractParameters(ContractManageParametersFeign contractManageParametersFeign) {
return AjaxResult.error("保存合同参数失败");
}
};
}
}
}
@@ -140,6 +140,11 @@ public class RemoteUserFeignFallbackFactory implements FallbackFactory<UserServi
return AjaxResult.error("获取租户托运人失败");
}
@Override
public AjaxResult<?> userShipperListAllByOrg(Long orgCode) {
return null;
}
@Override
public AjaxResult<?> userDriverListAll() {
return AjaxResult.error("获取租户承运人失败");
@@ -170,6 +175,11 @@ public class RemoteUserFeignFallbackFactory implements FallbackFactory<UserServi
return R.fail("获取组织用户失败:" + throwable.getMessage());
}
@Override
public R<LoginUser> getUserByUserAccount(String userAccount) {
return R.fail("获取用户失败:" + throwable.getMessage());
}
@Override
public R<LoginUser> getUserByTopOrganizationUserPhone(@RequestBody UserDTO userDTO, String source) {
return R.fail("获取组织用户失败:" + throwable.getMessage());
@@ -70,11 +70,44 @@ public class RemoteWmsFallbackFactory implements FallbackFactory<WmsServiceFeign
}
@Override
public void omsInOrderAdd(StockInOrder stockInOrder) {
public AjaxResult omsInOrderAdd(StockInOrder stockInOrder) {
//返回错误而非静默成功:下发主单保存失败必须让OMS感知并回滚下发标记,
//否则OMS显示已下发、WMS无数据,下游收货流程无从进行(流程阻断)
return AjaxResult.error("WMS入库单保存失败(服务降级):" + cause.getMessage());
}
@Override
public void omsInOrderAddDetail(List<InMaterialDetail> inMaterialDetails) {
public AjaxResult omsCancelExecutionOrder(StockOutOrder stockOutOrder) {
//返回错误而非静默成功,让OMS侧补偿清理能感知失败并记录告警
return AjaxResult.error("WMS取消下发清理失败:" + cause.getMessage());
}
@Override
public void omsAutoAssign(StockOutOrderDTO stockOutOrderDTO) {
}
@Override
public AjaxResult execution(StockOutOrderDTO stockOutOrderDTO) {
return AjaxResult.error(cause.getMessage());
}
@Override
public AjaxResult checkOmsAssignInventory(List<OutMaterialDetail> outMaterialDetails) {
//校验接口本身不可用时返回错误,OMS会阻止下发(不能在WMS状态未知时盲目推送)
return AjaxResult.error("WMS库存校验服务不可用:" + cause.getMessage());
}
@Override
public AjaxResult omsInOrderAddDetail(List<InMaterialDetail> inMaterialDetails) {
//返回错误而非静默成功:明细保存(含自动审核)失败必须让OMS感知并回滚下发标记
return AjaxResult.error("WMS入库单明细保存失败(服务降级):" + cause.getMessage());
}
@Override
public AjaxResult omsCancelInOrder(StockInOrder stockInOrder) {
//返回错误而非静默成功,让OMS侧取消下发能感知清理失败并整体回滚(取消下发可重试,WMS清理幂等)
return AjaxResult.error("WMS取消下发清理失败:" + cause.getMessage());
}
@Override
@@ -99,6 +132,23 @@ public class RemoteWmsFallbackFactory implements FallbackFactory<WmsServiceFeign
tableDataInfo.setCode(500);
return tableDataInfo;
}
@Override
public AjaxResult genPickingOrderByOms(StockOutOrderDTO stockOutOrderDTO) {
return null;
}
@Override
public AjaxResult batchSignWms(SignatureBatchFeignDTO dto) {
log.error("WMS批量签名调用失败");
return AjaxResult.error("WMS批量签名调用失败:" + cause.getMessage());
}
@Override
public AjaxResult listLineManagement(String routeCode) {
log.error("OMS查询WMS线路管理失败, routeCode:{}", routeCode);
return AjaxResult.error("WMS线路管理查询失败:" + cause.getMessage());
}
};
}
}
@@ -0,0 +1,44 @@
package com.mhd.system.api.factory;
import com.mhd.common.core.domain.dto.BusinessDataPushDTO;
import com.mhd.common.core.domain.entity.R;
import com.mhd.common.core.domain.po.OrganizationPo;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.system.api.BmsServiceFeign;
import com.mhd.system.api.ProductServiceFeign;
import com.mhd.system.api.XxlJobServiceFeign;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @Description
* @Author zg
* @Version 1.0
* @Date 2023/11/3 14:37
*/
@Component
public class RemoteXxlJobFeignFallbackFactory implements FallbackFactory<XxlJobServiceFeign> {
private static final Logger log = LoggerFactory.getLogger(RemoteXxlJobFeignFallbackFactory.class);
@Override
public XxlJobServiceFeign create(Throwable throwable) {
log.error("系统服务调用失败:{}", throwable.getMessage());
return new XxlJobServiceFeign() {
@Override
public R<Map<String, Object>> openFeignTest(String string) {
return null;
}
};
}
}
@@ -40,6 +40,7 @@ import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@@ -107,11 +108,14 @@ public class TokenLoginApplicationService {
//租户一级组织ID
SysTenantsPo sysTenantsPo = JSON.parseObject(JSON.toJSONString(topOrganizationIdR.get("data")), SysTenantsPo.class);
Long topOrganizationId = sysTenantsPo.getOrganizationId();
// 获取用户选择的组织ID未选则使用一级组织ID
Long selectedOrgId = loginDTO.getOrganizationId();
Long organizationId = (selectedOrgId != null) ? selectedOrgId : topOrganizationId;
//获取用户信息组装dto
UserDTO userDTO = new UserDTO();
userDTO.setUserPhone(userPhone);
userDTO.setTopOrganizationId(topOrganizationId);
userDTO.setOrganizationId(topOrganizationId);
userDTO.setOrganizationId(organizationId);
// 查询用户信息查询组织下用户是否存在
R<LoginUser> userResult = userServiceFeign.getUserByTopOrganizationUserPhone(userDTO, SecurityConstants.INNER);
if (R.FAIL == userResult.getCode()) {
@@ -126,9 +130,11 @@ public class TokenLoginApplicationService {
//验证码登录校验验证码
String key = CacheConstants.SMS_LOGIN + userPhone;
Object object = redisService.getCacheObject(key) == null ? "":redisService.getCacheObject(key);
if(!ObjectUtil.equal(String.valueOf(object),verificationCode) && !ObjectUtil.equal(verificationCode, SmsConstants.universalCode)){
recordLogininfor(userPhone, Constants.LOGIN_FAIL, "验证码错误", 1);
throw new ServiceException("验证码错误");
if (loginDTO.getWechatFlag() != 1) {
// if (!ObjectUtil.equal(String.valueOf(object), verificationCode) && !ObjectUtil.equal(verificationCode, SmsConstants.universalCode)) {
// recordLogininfor(userPhone, Constants.LOGIN_FAIL, "验证码错误", 1);
throw new ServiceException("验证码错误");
// }
}
//获取包名对应的业务(存在需要查询业务不存在保存为无业务模式)
@@ -153,7 +159,8 @@ public class TokenLoginApplicationService {
}else {
userDTO.setBusinessType(4);
}
userDTO.setOrganizationName(sysTenantsPo.getOrganizationName());
userDTO.setOrganizationName(StringUtils.isNotBlank(loginDTO.getOrganizationName())
? loginDTO.getOrganizationName() : sysTenantsPo.getOrganizationName());
userResult = userServiceFeign.registerAddUser(userDTO, SecurityConstants.INNER);
userInfo = userResult.getData();
} else {
@@ -163,7 +170,13 @@ public class TokenLoginApplicationService {
throw new ServiceException("对不起,您的账号:" + userPhone + " 已停用");
}
//校验验证码是否正确
sysPasswordService.validate(userPo, verificationCode, 1, null);
if (loginDTO.getWechatFlag() != 1) {
// if (!ObjectUtil.equal(String.valueOf(object), verificationCode) && !ObjectUtil.equal(verificationCode, SmsConstants.universalCode)) {
// recordLogininfor(userPhone, Constants.LOGIN_FAIL, "验证码错误", 1);
throw new ServiceException("验证码错误");
// }
}
// sysPasswordService.validate(userPo, verificationCode, 1, null);
}
return userInfo;
}
@@ -174,34 +187,67 @@ public class TokenLoginApplicationService {
}
/**
* 注册
* App注册手机号 + 注册短信验证码 + 密码
*/
public void register(String username, String password) {
// 用户名或密码为空 错误
if (StringUtils.isAnyBlank(username, password)) {
throw new ServiceException("用户/密码必须填写");
public void register(LoginDTO loginDTO) {
String userPhone = loginDTO.getUserPhone(); // LoginDTO.java:27-28
String verificationCode = loginDTO.getVerificationCode(); // LoginDTO.java:30-31
String password = loginDTO.getPassword();
// 1. 基础校验
if (StringUtils.isAnyBlank(userPhone, verificationCode, password)) {
throw new ServiceException("手机号、验证码、密码必须填写");
}
if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|| username.length() > UserConstants.USERNAME_MAX_LENGTH) {
throw new ServiceException("账户长度必须在2到20个字符之间");
}
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
throw new ServiceException("密码长度必须在5到20个字符之间");
if (!RegexUtil.isPhoneLegal(userPhone)) {
throw new DigitalLogisticsException(UserError.USER_PHONE_REG_ERROR);
}
// 注册用户信息
SysUser sysUser = new SysUser();
sysUser.setUserName(username);
sysUser.setNickName(username);
sysUser.setPassword(SecurityUtils.encryptPassword(password));
//TODO app注册没写
/*R<?> registerResult = userServiceFeign.registerUserInfo(sysUser, SecurityConstants.INNER);
// 2. 校验注册短信验证码发送时写入 redis SmsApplicationService.java:112, :165
String key = CacheConstants.SMS_REGISTER + userPhone; // "sms_register:" CacheConstants.java:51
Object cache = redisService.getCacheObject(key);
if (cache == null || !ObjectUtil.equal(String.valueOf(cache), verificationCode)) {
recordLogininfor(userPhone, Constants.LOGIN_FAIL, "注册验证码错误", 1);
throw new ServiceException("验证码错误或已过期");
}
// 3. 域名 一级组织 loginByVerificationCode :103-110 一致
String path = loginDTO.getPath();
AjaxResult topOrganizationIdR = organizationServiceFeign.getOrganizationByPath(path);
if (ObjectUtil.isNull(topOrganizationIdR) || ObjectUtil.isNull(topOrganizationIdR.get("data"))) {
throw new ServiceException("组织不存在,请检查登录域名");
}
SysTenantsPo sysTenantsPo = JSON.parseObject(JSON.toJSONString(topOrganizationIdR.get("data")), SysTenantsPo.class);
Long topOrganizationId = sysTenantsPo.getOrganizationId();
Long selectedOrgId = loginDTO.getOrganizationId(); // LoginDTO.java:37-38App 选择组织时传
Long organizationId = (selectedOrgId != null) ? selectedOrgId : topOrganizationId;
// 4. 手机号已注册则直接提示UserMapper.xml:199 user_phone+top_organization_id
UserDTO query = new UserDTO();
query.setUserPhone(userPhone);
query.setTopOrganizationId(topOrganizationId);
R<LoginUser> exist = userServiceFeign.getUserByTopOrganizationUserPhone(query, SecurityConstants.INNER);
if (exist != null && exist.getData() != null && exist.getData().getUserPo() != null) {
throw new ServiceException("该手机号已注册,请直接登录");
}
// 5. 创建用户复用验证码登录自动注册的同一链路
// auth feign UserServiceFeign.java:47-48 user-center UserAPI.java:332-336
// UserApplicationService.registerAddUser:1820-1927内部已处理默认角色/YMS同步
UserDTO userDTO = new UserDTO();
userDTO.setUserPhone(userPhone);
userDTO.setUserPassword(SecurityUtils.encryptPassword(password));
userDTO.setTopOrganizationId(topOrganizationId);
userDTO.setOrganizationId(organizationId);
userDTO.setOrganizationName(StringUtils.isNotBlank(loginDTO.getOrganizationName())
? loginDTO.getOrganizationName() : sysTenantsPo.getOrganizationName());
R<LoginUser> registerResult = userServiceFeign.registerAddUser(userDTO, SecurityConstants.INNER);
if (R.FAIL == registerResult.getCode()) {
throw new ServiceException(registerResult.getMsg());
}*/
// recordLogininfor(username, Constants.REGISTER, "注册成功");
}
// 6. 注册成功后清掉验证码并记日志
redisService.deleteObject(key);
recordLogininfor(userPhone, Constants.REGISTER, "注册成功", 2);
}
/**
@@ -379,6 +425,10 @@ public class TokenLoginApplicationService {
throw new ServiceException("用户不存在/密码错误");
}
}
// 验证码登录时 userInfo.getUserPo() 可能为null加保护
if (userInfo == null || userInfo.getUserPo() == null || userInfo.getUserPo().getOrganizationId() == null) {
throw new ServiceException("登录用户组织信息不完整,请联系管理员");
}
R<OrganizationPo> organizationInfo = organizationServiceFeign.getInfoForIdList(userInfo.getUserPo().getOrganizationId());
if (ObjectUtil.isNull(organizationInfo) || ObjectUtil.isNull(organizationInfo.getData())) {
throw new ServiceException("登录用户组织不存在");
@@ -569,4 +619,29 @@ public class TokenLoginApplicationService {
sysPasswordService.validateByWms(userPo, verificationCode, 1);
return userInfo;
}
/**
* 根据域名获取组织信息免Token供司机APP注册时选择组织用
*/
public AjaxResult getOrganizationByPath(String path) {
if (StringUtils.isBlank(path)) {
return AjaxResult.error("域名不能为空");
}
try {
AjaxResult result = organizationServiceFeign.getOrganizationByPath(path);
if (ObjectUtil.isNull(result) || ObjectUtil.isNull(result.get("data"))) {
return AjaxResult.error("未找到对应组织");
}
SysTenantsPo sysTenantsPo = JSON.parseObject(JSON.toJSONString(result.get("data")), SysTenantsPo.class);
Long topOrganizationId = sysTenantsPo.getOrganizationId();
// 返回一级组织ID和名称前端可据此展示组织选择
Map<String, Object> data = new java.util.HashMap<>();
data.put("organizationId", topOrganizationId);
data.put("organizationName", sysTenantsPo.getOrganizationName());
return AjaxResult.success(data);
} catch (Exception e) {
log.error("获取组织信息失败, path={}", path, e);
return AjaxResult.error("获取组织信息失败:" + e.getMessage());
}
}
}
@@ -34,4 +34,13 @@ public class LoginDTO {
@ApiModelProperty(name = "APP包名")
private String appMark;
@ApiModelProperty(name = "组织ID(司机选择组织,不传默认一级组织)")
private Long organizationId;
@ApiModelProperty(name = "组织名称(司机选择组织时传入)")
private String organizationName;
@ApiModelProperty(name = "微信标识")
private Integer wechatFlag;
}
@@ -9,11 +9,13 @@ import com.mhd.common.core.domain.po.UserPo;
import com.mhd.common.core.utils.JwtUtils;
import com.mhd.common.core.utils.StringUtils;
import com.mhd.common.core.web.controller.BaseController;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.security.annotation.RepeatSubmit;
import com.mhd.common.security.auth.AuthUtil;
import com.mhd.common.security.utils.SecurityUtils;
import com.mhd.system.api.model.LoginUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@@ -70,9 +72,18 @@ public class AppTokenController extends BaseController {
@PostMapping("register")
public R<?> register(@RequestBody LoginDTO loginDTO) {
// 用户注册
tokenLoginApplicationService.register(loginDTO.getUsername(), loginDTO.getPassword());
return R.ok();
// 用户注册手机号+短信验证码+密码
tokenLoginApplicationService.register(loginDTO);
return R.ok("注册成功");
}
/**
* 根据域名获取组织信息免Token供司机APP注册时选择组织用
*/
@ApiOperation("根据域名获取组织信息")
@GetMapping("/getOrganizationByPath/{path}")
public AjaxResult getOrganizationByPath(@PathVariable("path") String path) {
return tokenLoginApplicationService.getOrganizationByPath(path);
}
@@ -0,0 +1,90 @@
package com.mhd.auth.system.controller;
import com.mhd.auth.system.service.SsoAuthorizeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* SSO单点登录控制器
* 子系统端实现接收中台传递的签名参数验签后自动登录并重定向
*
* @author mhd
*/
@Slf4j
@RestController
@RequestMapping("/auth")
@CrossOrigin
public class SsoAuthorizeController {
@Autowired
private SsoAuthorizeService ssoAuthorizeService;
/**
* SSO单点登录授权接口
* 中台点击子系统链接后将签名参数传递给此接口
* 验签通过后自动登录并重定向到前端页面携带token
*
* @param signature 签名信息Base64编码后再URL编码签名源数据格式appkey=xxx&account=xxx&timestamp=xxxxxx
* @param appkey 对方的应用key值固定为nanguang
* @param account 账号
* @param timestamp 当前时间戳毫秒用于防止签名被盗用超过24小时视为失效
*/
@GetMapping("/sso-authorize")
public void ssoAuthorize(@RequestParam("signature") String signature,
@RequestParam("appkey") String appkey,
@RequestParam("account") String account,
@RequestParam("timestamp") Long timestamp,
HttpServletResponse response) throws IOException {
log.info("SSO单点登录请求, appkey={}, account={}, timestamp={}", appkey, account, timestamp);
String redirectUrl = ssoAuthorizeService.getRedirectUrl();
try {
// 1. 校验时间戳是否超过24小时防止签名被盗用
long ONE_DAY_MILLIS = 24L * 60 * 60 * 1000;
long currentTime = System.currentTimeMillis();
if ((currentTime - timestamp) > ONE_DAY_MILLIS) {
log.warn("SSO签名已过期, appkey={}, account={}, timestamp={}, 距今{}小时",
appkey, account, timestamp, (currentTime - timestamp) / (60 * 60 * 1000));
response.sendRedirect(redirectUrl + "?msg=" + URLEncoder.encode("登录失败:签名已超过24小时,请重新发起", StandardCharsets.UTF_8.name()));
return;
}
// 2. 构造签名源数据包含timestamp
String sourceData = "appkey=" + appkey + "&account=" + account + "&timestamp=" + timestamp;
// 3. 验证签名
boolean verifyResult = ssoAuthorizeService.verifySignature(sourceData, signature);
if (!verifyResult) {
log.warn("SSO验签失败, appkey={}, account={}, timestamp={}", appkey, account, timestamp);
response.sendRedirect(redirectUrl + "?msg=" + URLEncoder.encode("登录失败:签名验证不通过", StandardCharsets.UTF_8.name()));
return;
}
// 4. 验签通过使用account进行登录获取token
Map<String, Object> loginResult = ssoAuthorizeService.ssoLogin(account);
String accessToken = (String) loginResult.get("access_token");
// 5. 重定向到前端页面token通过URL参数传递
// 前端页面需读取URL中的token参数并存入localStorage
log.info("SSO单点登录成功, account={}", account);
log.info("SSO单点登录成功, account={}, token={} , redirectUrl={}", account, accessToken, redirectUrl);
response.sendRedirect(redirectUrl + "?token=" + URLEncoder.encode(accessToken, StandardCharsets.UTF_8.name()));
} catch (Exception e) {
log.error("SSO单点登录异常, appkey={}, account={}, timestamp={}", appkey, account, timestamp, e);
response.sendRedirect(redirectUrl + "?msg=" + URLEncoder.encode("登录失败:" + e.getMessage(), StandardCharsets.UTF_8.name()));
}
}
}
@@ -0,0 +1,200 @@
package com.mhd.auth.system.service;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.mhd.common.core.constant.CacheConstants;
import com.mhd.common.core.constant.Constants;
import com.mhd.common.core.constant.SecurityConstants;
import com.mhd.common.core.domain.entity.R;
import com.mhd.common.core.domain.po.OrganizationPo;
import com.mhd.common.core.domain.po.RolePO;
import com.mhd.common.core.domain.po.UserPo;
import com.mhd.common.core.enums.UserStatus;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.utils.ServletUtils;
import com.mhd.common.core.utils.ip.IpUtil;
import com.mhd.common.core.utils.ip.IpUtils;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.log.service.AsyncLogService;
import com.mhd.common.security.service.TokenService;
import com.mhd.system.api.SystemServiceFeign;
import com.mhd.system.api.UserServiceFeign;
import com.mhd.system.api.domain.UserDTO;
import com.mhd.system.api.domain.UserUpdateDTO;
import com.mhd.system.api.model.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* SSO单点登录服务
*
* @author mhd
*/
@Slf4j
@Service
public class SsoAuthorizeService {
@Value("${sso.public-key}")
private String publicKeyStr;
@Value("${sso.redirect-url}")
private String redirectUrl;
@Resource
private UserServiceFeign userServiceFeign;
@Resource
private TokenService tokenService;
@Autowired
private AsyncLogService asyncLogService;
@Autowired
private SystemServiceFeign systemServiceFeign;
@Resource
private com.mhd.auth.app.infrastructure.feign.OrganizationServiceFeign organizationServiceFeign;
/**
* 验证RSA签名
*
* @param sourceData 签名源数据格式appkey=xxx&account=xxx&timestamp=xxxxxx
* @param signatureStr Base64编码的签名可能经过URL编码
* @return 验签结果
*/
public boolean verifySignature(String sourceData, String signatureStr) {
try {
// Spring @RequestParam 已自动完成 URL 解码此处直接 Base64 解码即可
byte[] signatureBytes = Base64.getDecoder().decode(signatureStr);
PublicKey publicKey = generatePublicKey(publicKeyStr);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(sourceData.getBytes("UTF-8"));
return signature.verify(signatureBytes);
} catch (Exception e) {
log.error("SSO验签失败, sourceData={}, signature={}", sourceData, signatureStr, e);
return false;
}
}
/**
* 根据公钥字符串生成PublicKey对象
*/
private PublicKey generatePublicKey(String keyStr) throws Exception {
// 去除头尾标记和空白字符
String publicKeyContent = keyStr
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s+", "");
byte[] keyBytes = Base64.getDecoder().decode(publicKeyContent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
java.security.spec.X509EncodedKeySpec keySpec = new java.security.spec.X509EncodedKeySpec(keyBytes);
return keyFactory.generatePublic(keySpec);
}
/**
* SSO登录根据account查找用户并创建token
*
* @param account 账号
* @return 包含token等信息的Map
*/
public Map<String, Object> ssoLogin(String account) {
// 根据账号查找用户SSO登录不区分组织仅通过userAccount查询
R<LoginUser> userResult = userServiceFeign.getUserByUserAccount(account);
if (R.FAIL == userResult.getCode()) {
throw new ServiceException(userResult.getMsg());
}
if (userResult.getData() == null) {
throw new ServiceException("SSO登录用户不存在:" + account);
}
LoginUser userInfo = userResult.getData();
UserPo userPo = userInfo.getUserPo();
// 校验用户状态
if (userPo == null) {
throw new ServiceException("SSO登录用户信息异常:" + account);
}
// 删除标记
if (UserStatus.DELETED.getCode().equals(String.valueOf(userPo.getDelFlag()))) {
throw new ServiceException("对不起,您的账号:" + account + " 已被删除");
}
// 用户状态
if (UserStatus.DELETED.getCode().equals(String.valueOf(userPo.getUserStatus()))) {
throw new ServiceException("对不起,您的账号:" + account + " 已停用");
}
// 获取组织信息
com.mhd.common.core.domain.entity.R<OrganizationPo> organizationInfo = organizationServiceFeign.getInfoForIdList(userPo.getOrganizationId());
if (ObjectUtil.isNull(organizationInfo) || ObjectUtil.isNull(organizationInfo.getData())) {
throw new ServiceException("登录用户组织不存在");
}
userInfo.setOrganizationPo(organizationInfo.getData());
// 查询用户角色
AjaxResult roleListAjaxResult = userServiceFeign.getRoleListByUserId(userPo.getUserId());
if ("200".equals(String.valueOf(roleListAjaxResult.get("code"))) && ObjectUtil.isNotNull(roleListAjaxResult.get("data"))) {
List<RolePO> rolePOS = JSONUtil.toList(JSONUtil.toJsonStr(roleListAjaxResult.get("data")), RolePO.class);
if (rolePOS != null && !rolePOS.isEmpty()) {
userInfo.setRoleList(rolePOS.stream().map(RolePO::getRoleName).collect(Collectors.toList()));
userInfo.setRoleIdList(rolePOS.stream().map(RolePO::getRoleId).collect(Collectors.toList()));
}
}
// 更新登录信息
UserUpdateDTO userUpdateDTO = new UserUpdateDTO();
userUpdateDTO.setLastLoginTime(new Date());
userUpdateDTO.setLastLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
userUpdateDTO.setUserName(account);
userServiceFeign.updateWhenLogin(userUpdateDTO, SecurityConstants.INNER);
// 创建token
Map<String, Object> result = tokenService.createTokenApi(userInfo);
// 记录登录日志
recordLogininfor(userPo, Constants.LOGIN_SUCCESS, "SSO单点登录成功", 1);
return result;
}
/**
* 记录登录信息
*/
private void recordLogininfor(UserPo userPo, String status, String message, Integer behaviorType) {
com.mhd.system.api.domain.SysLogininforPo logininfor = new com.mhd.system.api.domain.SysLogininforPo();
logininfor.setUserAccount(userPo.getUserAccount());
logininfor.setUserName(userPo.getUserName());
logininfor.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
logininfor.setLocation(StrUtil.isNotEmpty(logininfor.getIpaddr()) ? IpUtil.getLocationSplicing(logininfor.getIpaddr()) : "");
logininfor.setBehaviorType(behaviorType);
logininfor.setMsg(message);
logininfor.setOrganizationId(userPo.getOrganizationId());
logininfor.setOrganizationName(userPo.getOrganizationName());
logininfor.setTopOrganizationId(userPo.getTopOrganizationId());
logininfor.setAccessTime(cn.hutool.core.date.DateUtil.date());
if (org.apache.commons.lang3.StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
logininfor.setStatus(Constants.LOGIN_SUCCESS_STATUS);
} else if (Constants.LOGIN_FAIL.equals(status)) {
logininfor.setStatus(Constants.LOGIN_FAIL_STATUS);
}
asyncLogService.saveLogininfor(logininfor);
}
public String getRedirectUrl() {
return redirectUrl;
}
}
@@ -550,11 +550,11 @@ public class SysLoginService {
throw new ServiceException("请输入手机号和短信验证码");
}
//调用工具类校验校验手机号格式错误
if (!RegexUtil.isPhoneLegal(userPhone)) {
recordLogininfor(userPhone, Constants.LOGIN_FAIL, UserError.USER_PHONE_REG_ERROR.errmsg(), 1);
throw new DigitalLogisticsException(UserError.USER_PHONE_REG_ERROR);
}
// //调用工具类校验校验手机号格式错误
// if (!RegexUtil.isPhoneLegal(userPhone)) {
// recordLogininfor(userPhone, Constants.LOGIN_FAIL, UserError.USER_PHONE_REG_ERROR.errmsg(), 1);
// throw new DigitalLogisticsException(UserError.USER_PHONE_REG_ERROR);
// }
//根据域名获取一级组织ID
AjaxResult topOrganizationIdR = organizationServiceFeign.getOrganizationByPath(path, SecurityConstants.INNER);
@@ -28,6 +28,7 @@ import com.mhd.common.redis.service.RedisService;
import com.mhd.common.security.utils.password.PasswordUtil;
import com.mhd.system.api.RemoteLogService;
import com.mhd.system.api.domain.SysLogininforPo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -39,6 +40,7 @@ import javax.annotation.Resource;
* @description: 登录密码方法
* @date 2023/12/26 15:33
**/
@Slf4j
@Component
public class SysPasswordService
{
@@ -76,29 +78,31 @@ public class SysPasswordService
if (retryCount == null) {
retryCount = 0;
}
//TODO 从三方配置表中取值
SysDepartInterfaceInfoDTO sysDepartInterfaceInfoDTO = new SysDepartInterfaceInfoDTO();
sysDepartInterfaceInfoDTO.setTopOrganizationId(userPo.getTopOrganizationId());
sysDepartInterfaceInfoDTO.setInterfaceType("login");
sysDepartInterfaceInfoDTO.setInterfaceTypeKey("maxRetryCount");
List<SysDepartInterfaceInfoPo> sysDepartInterfaceInfoPos = thirdPartyServiceFeign.queryListByFeign(sysDepartInterfaceInfoDTO);
if (sysDepartInterfaceInfoPos.isEmpty()){
String errMsg = "缺少登录信息配置,请联系管理员";
recordLogininfor(userPo, Constants.LOGIN_FAIL, errMsg, 1);
throw new ServiceException(errMsg);
//TODO 从三方配置表中取值失败时用默认值保证登录错误提示可用
int maxRetryCount = 5; // 默认密码错5次锁定
long lockTime = 30L; // 默认锁定30分钟
try {
SysDepartInterfaceInfoDTO dto = new SysDepartInterfaceInfoDTO();
dto.setTopOrganizationId(userPo.getTopOrganizationId());
dto.setInterfaceType("login");
dto.setInterfaceTypeKey("maxRetryCount");
List<SysDepartInterfaceInfoPo> pos = thirdPartyServiceFeign.queryListByFeign(dto);
if (pos != null && !pos.isEmpty()) {
maxRetryCount = Integer.parseInt(pos.get(0).getInterfaceTypeValue());
} else {
log.warn("组织[{}]缺少登录配置 login/maxRetryCount,使用默认值{}", userPo.getTopOrganizationId(), maxRetryCount);
}
dto.setInterfaceTypeKey("lockTime");
pos = thirdPartyServiceFeign.queryListByFeign(dto);
if (pos != null && !pos.isEmpty()) {
lockTime = Long.parseLong(pos.get(0).getInterfaceTypeValue());
} else {
log.warn("组织[{}]缺少登录配置 login/lockTime,使用默认值{}", userPo.getTopOrganizationId(), lockTime);
}
} catch (Exception e) {
log.warn("读取登录配置失败,使用默认重试策略", e);
}
SysDepartInterfaceInfoPo sysDepartInterfaceInfoPo = sysDepartInterfaceInfoPos.get(0);
Integer maxRetryCount = Integer.valueOf(sysDepartInterfaceInfoPo.getInterfaceTypeValue());
sysDepartInterfaceInfoDTO.setInterfaceTypeKey("lockTime");
sysDepartInterfaceInfoPos = thirdPartyServiceFeign.queryListByFeign(sysDepartInterfaceInfoDTO);
if (sysDepartInterfaceInfoPos.isEmpty()){
String errMsg = "缺少登录信息配置,请联系管理员";
recordLogininfor(userPo, Constants.LOGIN_FAIL, errMsg, 1);
throw new ServiceException(errMsg);
}
sysDepartInterfaceInfoPo = sysDepartInterfaceInfoPos.get(0);
Long lockTime = Long.valueOf(sysDepartInterfaceInfoPo.getInterfaceTypeValue());
if (retryCount >= maxRetryCount){
if (retryCount >= maxRetryCount) {
String errMsg = String.format("密码输入错误%s次,帐户锁定%s分钟", maxRetryCount, lockTime);
recordLogininfor(userPo, Constants.LOGIN_FAIL, errMsg, 1);
throw new ServiceException(errMsg);
+20 -2
View File
@@ -14,7 +14,8 @@ spring:
discovery:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
server-addr: 10.33.0.129:6010
# server-addr: 10.33.0.129:6010
server-addr: 10.102.192.31:6848
username: nacos
password: manhuoda@2023
#线上正式环境
@@ -23,8 +24,9 @@ spring:
# password: manhuoda@2023
config:
# server-addr: 127.0.0.1:8848
server-addr: 10.102.192.31:6848
# 测试环境配置 容器名+端口号
server-addr: 10.33.0.129:6010
# server-addr: 10.33.0.129:6010
# 线上测试环境配置 容器名+端口号
# server-addr: 10.102.192.5:6848
username: nacos
@@ -35,3 +37,19 @@ spring:
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# SSO单点登录配置
sso:
# RSA公钥(由中台openssl私钥导出)
public-key: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA62dYkl2Nvy2wW9028dQ7
HdxFNhwEriFNzFMFq+m1jTvZWdU6e9a1iCGWTVV2fTo4PWSyhjWyzv2ZBEuanWBq
y/bfh/jOTjT/tlWvMeJZ1TV4suCbigHq5TGxDsY6ZC6if9ULhU3NWkgnPNn6HfO9
NVvBTfx9MgWtCtT33kq30KgxC6LqVdCe08+gD0KB3df0DK8OJorVFfxYVc7TjGEL
xqUuE7PcgZgDb8KvdgO66OxBqFIB0qfc73oALKGoq/8kvjrqE/amaIZPv3jE2Rc7
0rIhGHrFcoA3W01nNRGQKY/E/VKOGBn/uDNdi5iMXsFjKxiBbXB07bBxdhUH7698
AwIDAQAB
-----END PUBLIC KEY-----
# SSO登录成功后跳转的前端页面地址
redirect-url: "https://diglog.namkwong.com.mo/main_app/sso"
@@ -0,0 +1,58 @@
package com.mhd.bi.domain.biPlatformRealData.repository.mapper;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformVehiclePO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformOverviewPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealVehicleStatusPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealTaskLoadPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealBusinessTypeStatPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformFloorStatPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformInfoPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealOnTimeStatPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealTaskTypeStatPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealMonthlyTaskDurationPO;
import java.util.List;
/**
* 月台监测-真实数据 Mapper
* 数据来源TEST_NGWL_YMS 达梦跨库访问
* 列名按达梦默认大写规则若实际库中小写请反馈调整
*/
public interface BiPlatformRealDataMapper {
/** 作业车辆状态列表 */
List<RealPlatformVehiclePO> queryVehicles();
/** 月台实时概览(总数 / 当前作业中) */
RealPlatformOverviewPO queryPlatformOverview();
/** 今日作业任务数 */
Long countTodayTasks();
/** 车辆状态统计(今日,含叫号状态合计 callStatusTotal = 已签到+已叫号+已过号) */
RealVehicleStatusPO queryVehicleStatusToday();
/** 本月任务量 */
Long countMonthTasks();
/** 本月任务平均时长 / 完成率统计 */
RealMonthlyTaskDurationPO queryMonthTaskStats();
/** 任务负荷(今日 24 小时) */
List<RealTaskLoadPO> queryTaskLoadToday();
/** 今日预约-业务类型统计(按 businessName 分组统计今日预约数量) */
List<RealBusinessTypeStatPO> queryTodayBusinessTypeStats();
/** 今日作业准时率统计(total 今日预约总数;onTimeCount 今日准时车辆数) */
RealOnTimeStatPO queryTodayOnTimeStats();
/** 任务类型统计(本月 YMS QMS_MAIN_BUSINESS 预约按业务类型 BUSINESS_NAME 分组) */
List<RealTaskTypeStatPO> queryMonthTransportOrderByType();
/** 月台监控-按楼层统计月台车辆(楼层、月台数量、今日预约车辆、当前作业车辆) */
List<RealPlatformFloorStatPO> queryPlatformFloorStats();
/** 月台管理列表(YMS qms_window_info,含机构/鹤位/状态/楼层/UUID 等完整信息) */
List<RealPlatformInfoPO> queryPlatformInfoList();
}
@@ -0,0 +1,20 @@
package com.mhd.bi.domain.biPlatformRealData.repository.po;
import lombok.Data;
import java.io.Serializable;
/**
* 今日预约-业务类型统计真实数据来自 TEST_NGWL_YMS.QMS_MAIN_BUSINESS
* 按业务类型分组统计今日预约数量
*/
@Data
public class RealBusinessTypeStatPO implements Serializable {
private static final long serialVersionUID = 1L;
/** 业务类型名称(qms_main_business.businessName */
private String businessName;
/** 今日预约数量 */
private Long count;
}
@@ -0,0 +1,29 @@
package com.mhd.bi.domain.biPlatformRealData.repository.po;
import lombok.Data;
import java.io.Serializable;
/**
* 本月任务平均时长 / 完成率统计真实数据来自 TEST_NGWL_YMS.QMS_MAIN_BUSINESS
* avgDurationHours累计 (EXIT_TIME - ENTRY_TIME) 小时数 ENTRY_TIME/EXIT_TIME 都不为空时参与
* durationCount参与平均时长统计的有效条数
* completedCount已出场EXIT_TIME IS NOT NULL且预约日期在本月的数量
* totalCount本月TARGET_DATE预约总数量
*/
@Data
public class RealMonthlyTaskDurationPO implements Serializable {
private static final long serialVersionUID = 1L;
/** 平均作业时长(小时) */
private Double avgDurationHours;
/** 参与平均时长统计的有效条数 */
private Long durationCount;
/** 本月已出场数量 */
private Long completedCount;
/** 本月预约总数量(按 TARGET_DATE 统计) */
private Long totalCount;
}
@@ -0,0 +1,20 @@
package com.mhd.bi.domain.biPlatformRealData.repository.po;
import lombok.Data;
import java.io.Serializable;
/**
* 今日作业准时率统计真实数据来自 TEST_NGWL_YMS.QMS_MAIN_BUSINESS
* 准时率 = 今日实际进场时间在预约日期当天的车辆数 / 今日预约总车辆数 × 100%
*/
@Data
public class RealOnTimeStatPO implements Serializable {
private static final long serialVersionUID = 1L;
/** 今日预约总车辆数 */
private Long total;
/** 今日准时车辆数(已进场且实际进场日期 = 预约日期) */
private Long onTimeCount;
}
@@ -0,0 +1,26 @@
package com.mhd.bi.domain.biPlatformRealData.repository.po;
import lombok.Data;
import java.io.Serializable;
/**
* 月台监控-月台车辆统计按楼层分组
* 数据来源TEST_NGWL_YMS.QMS_WINDOW_INFO楼层+月台 QMS_MAIN_BUSINESS当日预约/作业
*/
@Data
public class RealPlatformFloorStatPO implements Serializable {
private static final long serialVersionUID = 1L;
/** 楼层(从叫号月台 WINDOW_NAME 解析,如 S1-01 -> F1 */
private String floorNo;
/** 该楼层的月台数量 */
private Long platformCount;
/** 今日预约车辆数(按 WINDOW_NAME 关联楼层) */
private Long todayReservedVehicles;
/** 当前作业车辆数(FLOW_STATUS IN 5,6,7,8,9,10 */
private Long operatingVehicles;
}
@@ -0,0 +1,59 @@
package com.mhd.bi.domain.biPlatformRealData.repository.po;
import lombok.Data;
import java.io.Serializable;
/**
* 月台管理列表真实数据来自 TEST_NGWL_YMS.QMS_WINDOW_INFO
* 对应 YMS qms_window_info 月台/鹤位窗口表
*/
@Data
public class RealPlatformInfoPO implements Serializable {
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 机构代码(org_no */
private String orgNo;
/** 机构名称(dept_name */
private String deptName;
/** 鹤位号/月台号(window_number */
private String windowNumber;
/** 鹤位名称/月台名称(window_name */
private String windowName;
/** 优先级别(priority_set */
private String prioritySet;
/** 鹤位状态/月台状态(running_status */
private String runningStatus;
/** uuid */
private String uuid;
/** 鹤位屏名字集合/绑定月台屏(berr_names */
private String berrNames;
/** 最新业务状态(new_flow_status */
private String newFlowStatus;
/** 月台图片(guide_images */
private String guideImages;
/** 月台楼层(platform_floor */
private String platformFloor;
/** 作业状态 0-空闲 1-占用(job_status */
private Integer jobStatus;
/** 创建人(create_by */
private String createBy;
/** 创建时间(create_time */
private String createTime;
}
@@ -0,0 +1,18 @@
package com.mhd.bi.domain.biPlatformRealData.repository.po;
import lombok.Data;
import java.io.Serializable;
/**
* 月台实时概览真实数据来自 TEST_NGWL_YMS.QMS_WINDOW_INFO
*/
@Data
public class RealPlatformOverviewPO implements Serializable {
private static final long serialVersionUID = 1L;
/** 月台总数 */
private Long totalPlatforms;
/** 当前作业中(月台作业状态=占用) */
private Long operatingPlatforms;
}
@@ -0,0 +1,30 @@
package com.mhd.bi.domain.biPlatformRealData.repository.po;
import lombok.Data;
import java.io.Serializable;
/**
* 月台监测-作业车辆真实数据来自 TEST_NGWL_YMS.QMS_MAIN_BUSINESS
*/
@Data
public class RealPlatformVehiclePO implements Serializable {
private static final long serialVersionUID = 1L;
/** 车牌号(qms_main_business.CARNO */
private String plateNumber;
/** 流程状态(qms_main_business.FLOWSTATUS */
private String status;
/** 叫号月台(qms_queue_list.WINDOWNAME */
private String platformId;
/** 月台作业时长,分钟(EXITTIME - ENTRYTIME */
private Long platformDuration;
/** 预约申请时间(qms_main_business.CREATE_TIME */
private String appointmentTime;
/** 作业楼层(qms_window_info.PLATFORMFLOOR */
private String workFloor;
}
@@ -0,0 +1,18 @@
package com.mhd.bi.domain.biPlatformRealData.repository.po;
import lombok.Data;
import java.io.Serializable;
/**
* 任务负荷统计按小时来自 TEST_NGWL_YMS.QMS_MAIN_BUSINESS
*/
@Data
public class RealTaskLoadPO implements Serializable {
private static final long serialVersionUID = 1L;
/** 0-23 小时 */
private Integer hourOfDay;
/** 该小时段任务数 */
private Long taskCount;
}
@@ -0,0 +1,20 @@
package com.mhd.bi.domain.biPlatformRealData.repository.po;
import lombok.Data;
import java.io.Serializable;
/**
* 任务类型统计真实数据来自 NGWL_TEST_YMS.QMS_MAIN_BUSINESS 预约登记表
* 按本月预约车辆数TARGET_DATE 在当前月 BUSINESS_NAME 业务类型分组
*/
@Data
public class RealTaskTypeStatPO implements Serializable {
private static final long serialVersionUID = 1L;
/** 业务类型名称(qms_main_business.BUSINESS_NAME */
private String businessName;
/** 该业务类型本月预约车辆数 */
private Long count;
}
@@ -0,0 +1,30 @@
package com.mhd.bi.domain.biPlatformRealData.repository.po;
import lombok.Data;
import java.io.Serializable;
/**
* 作业车辆状态统计真实数据来自 TEST_NGWL_YMS.QMS_MAIN_BUSINESS
*/
@Data
public class RealVehicleStatusPO implements Serializable {
private static final long serialVersionUID = 1L;
/** 今日预约车辆 */
private Long todayReservedVehicles;
/** 当前未签到 */
private Long notCheckedIn;
/** 当前等待作业(FLOW_STATUS IN '1','2','3' 已预约/已签到/已叫号) */
private Long waiting;
/** 叫号状态合计:已签到 + 已叫号 + 已过号(FLOW_STATUS IN '2','3','4',预约日期为今天) */
private Long callStatusTotal;
/** 当前作业中 */
private Long operatingVehicles;
/** 作业完成 */
private Long completedVehicles;
}
@@ -0,0 +1,501 @@
package com.mhd.bi.domain.biPlatformRealData.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mhd.bi.domain.biPlatformRealData.repository.mapper.BiPlatformRealDataMapper;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformVehiclePO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformOverviewPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealVehicleStatusPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealTaskLoadPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealBusinessTypeStatPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformFloorStatPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformInfoPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealOnTimeStatPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealTaskTypeStatPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealMonthlyTaskDurationPO;
import com.mhd.bi.domain.biPlatformSurveillance.repository.mapper.BiPlatformSurveillanceReportMapper;
import com.mhd.bi.domain.biSnapshotSync.repository.mapper.BiSnapshotWriteMapper;
import com.mhd.bi.domain.biSnapshotSync.support.BiSnapshotWeeklyRandomDataBuilder;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.PlatformSurveillanceVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.PlatformVehicleItemVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.TaskLoadItemVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.TaskTypeStatisticsVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.TaskTypeCountItemVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
/**
* 月台监测-真实数据业务层封装 YMS 跨库查询
* 列名大小写字段类型需以实际库为准 YMS 库无数据/无权限相关方法应返回空/0不影响写死字段写入快照
*/
@Slf4j
@Service
public class BiPlatformRealDataService {
@Resource
private BiPlatformRealDataMapper biPlatformRealDataMapper;
@Resource
private BiSnapshotWriteMapper biSnapshotWriteMapper;
@Resource
private BiPlatformSurveillanceReportMapper biPlatformSurveillanceReportMapper;
@Resource
private ObjectMapper objectMapper;
private static final String REMARK_REALTIME = "realtime platform-surveillance";
/**
* 实时组装月台监测数据仅当真实业务数据YMS 库查出的字段发生变化时
* 才覆盖更新 BI_PLATFORM_SURVEILLANCE_SNAPSHOT 快照表最新一条后返回
* 写死字段变化不触发更新表中尚无记录时插入一条兜底
*/
public PlatformSurveillanceVO buildRealTimePlatformSurveillanceAndPersist() {
PlatformSurveillanceVO vo = buildRealTimePlatformSurveillance();
try {
String fullJson = objectMapper.writeValueAsString(vo);
String fingerprint = realDataFingerprint(vo);
String latestJson = biPlatformSurveillanceReportMapper.selectLatestPayloadJson();
if (StringUtils.isNotBlank(latestJson)) {
PlatformSurveillanceVO latestVo = objectMapper.readValue(latestJson.trim(), PlatformSurveillanceVO.class);
if (Objects.equals(fingerprint, realDataFingerprint(latestVo))) {
log.info("BI 月台监测真实业务数据未变化,跳过落库");
return vo;
}
}
int rows = biSnapshotWriteMapper.updateLatestPlatformSurveillanceSnapshot(fullJson, REMARK_REALTIME);
if (rows < 1) {
// 表中无最新记录可更新插入一条兜底
biSnapshotWriteMapper.insertPlatformSurveillanceSnapshot(fullJson, REMARK_REALTIME);
}
log.info("BI 月台监测实时数据已落库(覆盖最新, 数据变化), affectedRows={}", rows);
} catch (Exception e) {
log.error("BI 月台监测实时数据落库失败", e);
}
return vo;
}
/**
* 提取月台监测的真实业务数据指纹仅含 YMS 库查出的字段用于判断业务数据是否变化
* 写死/随机字段不纳入指纹故其变化不会触发更新
*/
private String realDataFingerprint(PlatformSurveillanceVO vo) throws Exception {
Map<String, Object> fp = new LinkedHashMap<>();
if (vo.getPlatformOverview() != null) {
fp.put("totalPlatforms", vo.getPlatformOverview().getTotalPlatforms());
fp.put("operatingPlatforms", vo.getPlatformOverview().getOperatingPlatforms());
fp.put("currentOccupancyRate", vo.getPlatformOverview().getCurrentOccupancyRate());
fp.put("todayTasks", vo.getPlatformOverview().getTodayTasks());
}
if (vo.getEfficiencyStatistics() != null) {
fp.put("platformOnTimeRate", vo.getEfficiencyStatistics().getPlatformOnTimeRate());
}
if (vo.getVehicleStatus() != null) {
fp.put("todayReservedVehicles", vo.getVehicleStatus().getTodayReservedVehicles());
fp.put("notCheckedIn", vo.getVehicleStatus().getNotCheckedIn());
fp.put("waiting", vo.getVehicleStatus().getWaiting());
fp.put("callStatusTotal", vo.getVehicleStatus().getCallStatusTotal());
fp.put("operatingVehicles", vo.getVehicleStatus().getOperatingVehicles());
fp.put("completedVehicles", vo.getVehicleStatus().getCompletedVehicles());
}
if (vo.getMonthlyTaskStatistics() != null) {
fp.put("taskTotal", vo.getMonthlyTaskStatistics().getTaskTotal());
fp.put("avgTaskDuration", vo.getMonthlyTaskStatistics().getAvgTaskDuration());
fp.put("taskCompletionRate", vo.getMonthlyTaskStatistics().getTaskCompletionRate());
}
if (vo.getVehicles() != null) {
List<Map<String, Object>> vehicles = new ArrayList<>();
for (PlatformVehicleItemVO v : vo.getVehicles()) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("appointmentTime", v.getAppointmentTime());
m.put("workFloor", v.getWorkFloor());
m.put("plateNumber", v.getPlateNumber());
m.put("status", v.getStatus());
m.put("platformId", v.getPlatformId());
m.put("platformDuration", v.getPlatformDuration());
vehicles.add(m);
}
fp.put("vehicles", vehicles);
}
if (vo.getTaskLoadStatistics() != null) {
List<Map<String, Object>> loads = new ArrayList<>();
for (TaskLoadItemVO item : vo.getTaskLoadStatistics()) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("time", item.getTime());
m.put("taskCount", item.getTaskCount());
loads.add(m);
}
fp.put("taskLoadStatistics", loads);
}
if (vo.getTaskTypeStatistics() != null) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("totalTasks", vo.getTaskTypeStatistics().getTotalTasks());
if (vo.getTaskTypeStatistics().getTaskTypes() != null) {
List<Map<String, Object>> types = new ArrayList<>();
for (TaskTypeCountItemVO it : vo.getTaskTypeStatistics().getTaskTypes()) {
Map<String, Object> tm = new LinkedHashMap<>();
tm.put("type", it.getType());
tm.put("count", it.getCount());
types.add(tm);
}
m.put("taskTypes", types);
}
fp.put("taskTypeStatistics", m);
}
// 月台告警统计按业务要求恒为 0纳入指纹以确保旧快照可能含非0写死值能被覆盖更新为 0
if (vo.getPlatformAlarmStatistics() != null) {
fp.put("todayAlarmTotal", vo.getPlatformAlarmStatistics().getTodayAlarmTotal());
fp.put("handled", vo.getPlatformAlarmStatistics().getHandled());
fp.put("unhandled", vo.getPlatformAlarmStatistics().getUnhandled());
}
return objectMapper.writeValueAsString(fp);
}
public List<RealPlatformVehiclePO> queryVehicles() {
try {
return biPlatformRealDataMapper.queryVehicles();
} catch (Exception e) {
log.error("【YMS】查询作业车辆列表失败: {}", e.getMessage(), e);
return java.util.Collections.emptyList();
}
}
public RealPlatformOverviewPO queryPlatformOverview() {
try {
RealPlatformOverviewPO po = biPlatformRealDataMapper.queryPlatformOverview();
if (po == null) {
po = new RealPlatformOverviewPO();
}
if (po.getTotalPlatforms() == null) po.setTotalPlatforms(0L);
if (po.getOperatingPlatforms() == null) po.setOperatingPlatforms(0L);
return po;
} catch (Exception e) {
log.error("【YMS】查询月台概览失败: {}", e.getMessage(), e);
RealPlatformOverviewPO po = new RealPlatformOverviewPO();
po.setTotalPlatforms(0L);
po.setOperatingPlatforms(0L);
return po;
}
}
public long countTodayTasks() {
try {
Long n = biPlatformRealDataMapper.countTodayTasks();
return n == null ? 0L : n;
} catch (Exception e) {
log.error("【YMS】统计今日作业任务失败: {}", e.getMessage(), e);
return 0L;
}
}
/**
* 今日作业准时率 = 今日准时车辆数 / 今日有入场时间的车辆数 × 100%四舍五入取整
* 准时实际进入时间 < 预约日期(TARGET_DATE) + 预约结束时间(BOOKING_END_TIME)
* 分子分母都只统计有入场时间ENTRY_TIME 不为空的车辆分母为 0 时返回 0
*/
public int calcTodayOnTimeRate() {
try {
RealOnTimeStatPO po = biPlatformRealDataMapper.queryTodayOnTimeStats();
if (po == null) return 0;
long total = po.getTotal() == null ? 0L : po.getTotal();
long onTime = po.getOnTimeCount() == null ? 0L : po.getOnTimeCount();
if (total <= 0) return 0;
// 四舍五入到整数百分比取整
return (int) Math.round(((double) onTime / (double) total) * 100.0);
} catch (Exception e) {
log.error("【YMS】计算今日作业准时率失败: {}", e.getMessage(), e);
return 0;
}
}
public RealVehicleStatusPO queryVehicleStatusToday() {
try {
RealVehicleStatusPO po = biPlatformRealDataMapper.queryVehicleStatusToday();
if (po == null) po = new RealVehicleStatusPO();
if (po.getTodayReservedVehicles() == null) po.setTodayReservedVehicles(0L);
if (po.getNotCheckedIn() == null) po.setNotCheckedIn(0L);
if (po.getWaiting() == null) po.setWaiting(0L);
if (po.getCallStatusTotal() == null) po.setCallStatusTotal(0L);
if (po.getOperatingVehicles() == null) po.setOperatingVehicles(0L);
if (po.getCompletedVehicles() == null) po.setCompletedVehicles(0L);
return po;
} catch (Exception e) {
log.error("【YMS】统计车辆状态失败: {}", e.getMessage(), e);
RealVehicleStatusPO po = new RealVehicleStatusPO();
po.setTodayReservedVehicles(0L);
po.setNotCheckedIn(0L);
po.setWaiting(0L);
po.setCallStatusTotal(0L);
po.setOperatingVehicles(0L);
po.setCompletedVehicles(0L);
return po;
}
}
public long countMonthTasks() {
try {
Long n = biPlatformRealDataMapper.countMonthTasks();
return n == null ? 0L : n;
} catch (Exception e) {
log.error("【YMS】统计本月任务量失败: {}", e.getMessage(), e);
return 0L;
}
}
/**
* 本月任务平均时长 / 完成率统计
* - avgDurationHours累计(EXIT_TIME - ENTRY_TIME)小时数 / 参与数任一为空的行不参与
* - taskCompletionRate已完成EXIT_TIME 不为空 预约日期在本月/ 本月预约总数量 ×100
* 任一查询失败均返回 null由调用方决定是否覆盖模板值
*/
public RealMonthlyTaskDurationPO queryMonthTaskStats() {
try {
return biPlatformRealDataMapper.queryMonthTaskStats();
} catch (Exception e) {
log.error("【YMS】统计本月任务平均时长/完成率失败: {}", e.getMessage(), e);
return null;
}
}
public List<RealTaskLoadPO> queryTaskLoadToday() {
try {
return biPlatformRealDataMapper.queryTaskLoadToday();
} catch (Exception e) {
log.error("【YMS】统计任务负荷失败: {}", e.getMessage(), e);
return java.util.Collections.emptyList();
}
}
/**
* 任务类型统计本月YMS QMS_MAIN_BUSINESS预约车辆按业务类型 BUSINESS_NAME 分组
* 返回 {totalTasks: 当月总预约车辆数, taskTypes: [{type: 业务类型名称, count: 该类型预约数}]}
* 按真实 BUSINESS_NAME 分组输出不固定兜底类别当月无数据或查询失败时返回空列表
*/
public TaskTypeStatisticsVO queryMonthTransportOrderByType() {
List<TaskTypeCountItemVO> items = new ArrayList<>();
int total = 0;
try {
List<RealTaskTypeStatPO> rows = biPlatformRealDataMapper.queryMonthTransportOrderByType();
if (rows != null) {
for (RealTaskTypeStatPO r : rows) {
if (r == null || r.getBusinessName() == null || r.getCount() == null) {
continue;
}
int c = r.getCount().intValue();
items.add(TaskTypeCountItemVO.builder().type(r.getBusinessName()).count(c).build());
total += c;
}
}
} catch (Exception e) {
log.error("【YMS】统计当月预约业务类型失败: {}", e.getMessage(), e);
// 查询失败返回空列表前端会显示空
items = new ArrayList<>();
total = 0;
}
return TaskTypeStatisticsVO.builder().totalTasks(total).taskTypes(items).build();
}
/**
* 今日预约-业务类型统计按业务类型分组统计今日预约数量
* 今日预约航空打板 3 返回 {businessName:"航空打板", count:3}
*/
public List<RealBusinessTypeStatPO> queryTodayBusinessTypeStats() {
try {
return biPlatformRealDataMapper.queryTodayBusinessTypeStats();
} catch (Exception e) {
log.error("【YMS】统计今日业务类型失败: {}", e.getMessage(), e);
return java.util.Collections.emptyList();
}
}
/**
* 月台监控-按楼层统计月台车辆返回 {floorNo, platformCount, todayReservedVehicles, operatingVehicles}
* 实时查 YMS 不落库
*/
public List<RealPlatformFloorStatPO> queryPlatformFloorStats() {
try {
return biPlatformRealDataMapper.queryPlatformFloorStats();
} catch (Exception e) {
log.error("【YMS】月台监控按楼层统计失败: {}", e.getMessage(), e);
return java.util.Collections.emptyList();
}
}
/**
* 月台管理列表实时查 YMS qms_window_info返回月台/鹤位窗口完整信息不落库
*/
public List<RealPlatformInfoPO> queryPlatformInfoList() {
try {
return biPlatformRealDataMapper.queryPlatformInfoList();
} catch (Exception e) {
log.error("【YMS】查询月台管理列表失败: {}", e.getMessage(), e);
return java.util.Collections.emptyList();
}
}
/**
* 实时组装月台监测数据原则有真实数据源用真实无真实数据源用写死模拟
* 有真实数据源的字段vehicles / platformOverview / vehicleStatus / taskLoad / taskTotal
* 无条件用 YMS 真实查询覆盖真实为空即为空不用模板兜底
* 无真实数据源的字段效率统计趋势告警任务类型等保留模板写死值
* 每次调用实时查库不经过快照表
*/
public PlatformSurveillanceVO buildRealTimePlatformSurveillance() {
// 固定种子生成写死模板仅用于没有真实数据源的字段
Random r = new Random(20260825L);
PlatformSurveillanceVO template = BiSnapshotWeeklyRandomDataBuilder.platformSurveillance(r);
// 作业车辆列表真实数据源无条件覆盖真实为空则返回空列表不用模板模拟
List<RealPlatformVehiclePO> realVehicles = queryVehicles();
List<PlatformVehicleItemVO> vehicleVos = new ArrayList<>();
for (RealPlatformVehiclePO rv : realVehicles) {
PlatformVehicleItemVO v = new PlatformVehicleItemVO();
v.setAppointmentTime(rv.getAppointmentTime());
v.setWorkFloor(rv.getWorkFloor());
v.setPlateNumber(rv.getPlateNumber());
v.setStatus(translateFlowStatus(rv.getStatus()));
v.setPlatformId(rv.getPlatformId());
v.setPlatformDuration(rv.getPlatformDuration() == null ? 0 : rv.getPlatformDuration().intValue());
vehicleVos.add(v);
}
template.setVehicles(vehicleVos);
// 月台实时概览真实数据源无条件覆盖
// 总月台 / 占用月台 来源YMS 月台管理列表 QMS_WINDOW_INFOJOB_STATUS=1 表示占用
// 月台占用率 = 占用 / 全部月台
// 今日作业任务 来源QMS_MAIN_BUSINESS 按预约时间 TARGET_DATE = 今天 的全部数量
// 作业准时率 = 今日实际进场时间在预约日期当天的车辆数 / 今日预约车辆总数 × 100%
if (template.getPlatformOverview() != null) {
List<RealPlatformInfoPO> platformList = queryPlatformInfoList();
int total = platformList == null ? 0 : platformList.size();
int occ = 0;
if (platformList != null) {
for (RealPlatformInfoPO p : platformList) {
if (p != null && p.getJobStatus() != null && p.getJobStatus() == 1) {
occ++;
}
}
}
double rate = total > 0 ? Math.round(((double) occ / total) * 100.0 * 100.0) / 100.0 : 0d;
int todayTasks = (int) countTodayTasks();
template.getPlatformOverview().setTotalPlatforms(total);
template.getPlatformOverview().setOperatingPlatforms(occ);
template.getPlatformOverview().setCurrentOccupancyRate(rate);
template.getPlatformOverview().setTodayTasks(todayTasks);
// 作业准时率实际进入时间 < 预约日期+预约结束时间 的车辆 / 今日预约总数 × 100% 取整
if (template.getEfficiencyStatistics() != null) {
template.getEfficiencyStatistics().setPlatformOnTimeRate(calcTodayOnTimeRate());
}
}
// 作业车辆状态统计真实数据源无条件覆盖含等待作业 waiting = 今日预约且 已预约/已签到/已叫号
if (template.getVehicleStatus() != null) {
RealVehicleStatusPO vs = queryVehicleStatusToday();
template.getVehicleStatus().setTodayReservedVehicles(vs.getTodayReservedVehicles().intValue());
template.getVehicleStatus().setNotCheckedIn(vs.getNotCheckedIn().intValue());
template.getVehicleStatus().setWaiting(vs.getWaiting().intValue());
// 叫号状态合计已签到 + 已叫号 + 已过号一个字段表示三个状态的总数量
template.getVehicleStatus().setCallStatusTotal(vs.getCallStatusTotal().intValue());
template.getVehicleStatus().setOperatingVehicles(vs.getOperatingVehicles().intValue());
template.getVehicleStatus().setCompletedVehicles(vs.getCompletedVehicles().intValue());
}
// 本月任务统计taskTotal / avgTaskDuration / taskCompletionRate 均有真实数据源无条件覆盖YoY 保留模板写死值
if (template.getMonthlyTaskStatistics() != null) {
template.getMonthlyTaskStatistics().setTaskTotal((int) countMonthTasks());
RealMonthlyTaskDurationPO monthStats = queryMonthTaskStats();
if (monthStats != null) {
if (monthStats.getAvgDurationHours() != null) {
// 保留两位小数
double v = monthStats.getAvgDurationHours();
template.getMonthlyTaskStatistics().setAvgTaskDuration(Math.round(v * 100.0) / 100.0);
}
Long total = monthStats.getTotalCount();
Long completed = monthStats.getCompletedCount();
if (total != null && total > 0 && completed != null) {
int rate = (int) Math.round(((double) completed.longValue() / total.longValue()) * 100.0);
template.getMonthlyTaskStatistics().setTaskCompletionRate(rate);
} else {
template.getMonthlyTaskStatistics().setTaskCompletionRate(0);
}
}
}
// 任务负荷有真实数据源真实为空则清空不用模板模拟有数据则按真实小时覆盖
List<RealTaskLoadPO> loads = queryTaskLoadToday();
if (loads.isEmpty()) {
template.setTaskLoadStatistics(new ArrayList<>());
} else if (template.getTaskLoadStatistics() != null) {
Map<Integer, Long> hourMap = new HashMap<>();
for (RealTaskLoadPO l : loads) {
hourMap.put(l.getHourOfDay(), l.getTaskCount());
}
for (TaskLoadItemVO item : template.getTaskLoadStatistics()) {
Integer hour = parseHourFromLabel(item.getTime());
if (hour != null && hourMap.containsKey(hour)) {
item.setTaskCount(hourMap.get(hour).intValue());
}
}
}
// 任务类型统计本月 YMS QMS_MAIN_BUSINESS 按业务类型 BUSINESS_NAME 分组真实业务数据
template.setTaskTypeStatistics(queryMonthTransportOrderByType());
return template;
}
private static Integer parseHourFromLabel(String label) {
if (label == null) return null;
try {
String s = label.replace("", "").trim();
return Integer.parseInt(s);
} catch (Exception e) {
return null;
}
}
/**
* FLOW_STATUS 数字转中文1已预约 2已签到 3已叫号 4已过号 5已进场 6已称重 7已装车 8二次称重 9已结算 10已还卡 11已出场 12已取消
*/
private static String translateFlowStatus(String flowStatus) {
if (flowStatus == null) return null;
switch (flowStatus.trim()) {
case "1": return "已预约";
case "2": return "已签到";
case "3": return "已叫号";
case "4": return "已过号";
case "5": return "已进场";
case "6": return "已称重";
case "7": return "已装车";
case "8": return "二次称重";
case "9": return "已结算";
case "10": return "已还卡";
case "11": return "已出场";
case "12": return "已取消";
default: return flowStatus;
}
}
}
@@ -85,9 +85,11 @@ public final class BiReportSnapshotMapperSupport {
.entryOvertimeRate(0).overtimeCount(0).platformOnTimeRate(0)
.avgPlatformDuration(0d).yardOnTimeRate(0).avgYardDuration(0d).build())
.platformOverview(PlatformOverviewVO.builder()
.totalPlatforms(0).currentOccupancyRate(0).operatingPlatforms(0).todayTasks(0).build())
.totalPlatforms(0).currentOccupancyRate(0d).operatingPlatforms(0).todayTasks(0).build())
.vehicleStatus(VehicleStatusVO.builder()
.todayReservedVehicles(0).notCheckedIn(0).operatingVehicles(0).completedVehicles(0).build())
.todayReservedVehicles(0).notCheckedIn(0).waiting(0)
.callStatusTotal(0)
.operatingVehicles(0).completedVehicles(0).build())
.avgOperationDurationTrend(Collections.emptyList())
.monthlyTaskStatistics(MonthlyTaskStatisticsVO.builder()
.taskTotal(0).taskTotalYoY(0).avgTaskDuration(0d).avgDurationYoY(0)
@@ -13,6 +13,8 @@ public interface BiSnapshotWriteMapper {
int insertPlatformSurveillanceSnapshot(@Param("payloadJson") String payloadJson, @Param("remark") String remark);
int updateLatestPlatformSurveillanceSnapshot(@Param("payloadJson") String payloadJson, @Param("remark") String remark);
int insertOverallOperationSnapshot(@Param("payloadJson") String payloadJson, @Param("remark") String remark);
int insertWarehouseOperationZoneSnapshot(@Param("payloadJson") String payloadJson, @Param("remark") String remark);
@@ -13,10 +13,20 @@ import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.PlatformSurveillance
import com.mhd.bi.interfaces.facadeApi.biReport.vo.hkMacaoZone.HkMacaoServiceZoneVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.transportZone.TransportOperationZoneVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.warehouseZone.WarehouseOperationZoneVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.PlatformVehicleItemVO;
import com.mhd.bi.domain.biPlatformRealData.service.BiPlatformRealDataService;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformVehiclePO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformInfoPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealVehicleStatusPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealTaskLoadPO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Random;
/**
@@ -34,6 +44,7 @@ public class BiReportSnapshotSyncService {
private final BiSnapshotWriteMapper biSnapshotWriteMapper;
private final ObjectMapper objectMapper;
private final BiPlatformRealDataService biPlatformRealDataService;
/**
* 依次同步各快照表单表失败不影响其它表只记日志
@@ -137,9 +148,126 @@ public class BiReportSnapshotSyncService {
return BiSnapshotWeeklyRandomDataBuilder.warehouseTransport(new Random());
}
/** TODO 业务落地:改为查询真实数据。临时实现见 {@link BiSnapshotWeeklyRandomDataBuilder#platformSurveillance(Random)}。 */
/** TODO 业务落地:部分字段改为真实数据,其余仍写死。 */
protected PlatformSurveillanceVO buildPlatformSurveillanceSnapshot() {
return BiSnapshotWeeklyRandomDataBuilder.platformSurveillance(new Random());
// 固定种子保证写死字段每次生成值一致真实字段随后实时覆盖
Random r = new Random(20260825L);
// 写死数据复用原 builder
PlatformSurveillanceVO template = BiSnapshotWeeklyRandomDataBuilder.platformSurveillance(r);
// ====== 真实数据作业车辆列表 ======
List<RealPlatformVehiclePO> realVehicles = biPlatformRealDataService.queryVehicles();
List<PlatformVehicleItemVO> vehicleVos = new ArrayList<>();
for (RealPlatformVehiclePO rv : realVehicles) {
PlatformVehicleItemVO v = new PlatformVehicleItemVO();
v.setAppointmentTime(rv.getAppointmentTime());
v.setWorkFloor(rv.getWorkFloor());
v.setPlateNumber(rv.getPlateNumber());
v.setStatus(rv.getStatus());
v.setPlatformId(rv.getPlatformId());
v.setPlatformDuration(rv.getPlatformDuration() == null ? 0 : rv.getPlatformDuration().intValue());
vehicleVos.add(v);
}
if (!vehicleVos.isEmpty()) {
template.setVehicles(vehicleVos);
}
// ====== 真实数据月台实时概览 ======
// 总月台 / 占用月台 来源YMS 月台管理列表 QMS_WINDOW_INFOJOB_STATUS=1 表示占用
// 月台占用率 = 占用 / 全部月台
// 今日作业任务 来源QMS_MAIN_BUSINESS 按预约时间 TARGET_DATE = 今天 的全部数量
if (template.getPlatformOverview() != null) {
List<RealPlatformInfoPO> platformList = biPlatformRealDataService.queryPlatformInfoList();
int total = platformList == null ? 0 : platformList.size();
int occ = 0;
if (platformList != null) {
for (RealPlatformInfoPO p : platformList) {
if (p != null && p.getJobStatus() != null && p.getJobStatus() == 1) {
occ++;
}
}
}
double rate = total > 0 ? Math.round(((double) occ / total) * 100.0 * 100.0) / 100.0 : 0d;
int todayTasks = (int) biPlatformRealDataService.countTodayTasks();
template.getPlatformOverview().setTotalPlatforms(total);
template.getPlatformOverview().setOperatingPlatforms(occ);
template.getPlatformOverview().setCurrentOccupancyRate(rate);
template.getPlatformOverview().setTodayTasks(todayTasks);
// 作业准时率 = 实际进入时间 < 预约日期+预约结束时间 的车辆 / 今日预约总数 × 100%取整
if (template.getEfficiencyStatistics() != null) {
template.getEfficiencyStatistics().setPlatformOnTimeRate(biPlatformRealDataService.calcTodayOnTimeRate());
}
}
// ====== 真实数据作业车辆状态统计 ======
RealVehicleStatusPO vs = biPlatformRealDataService.queryVehicleStatusToday();
if (template.getVehicleStatus() != null) {
template.getVehicleStatus().setTodayReservedVehicles(vs.getTodayReservedVehicles().intValue());
template.getVehicleStatus().setNotCheckedIn(vs.getNotCheckedIn().intValue());
template.getVehicleStatus().setWaiting(vs.getWaiting().intValue());
// 叫号状态合计已签到 + 已叫号 + 已过号一个字段表示三个状态的总数量
template.getVehicleStatus().setCallStatusTotal(vs.getCallStatusTotal() == null ? 0 : vs.getCallStatusTotal().intValue());
template.getVehicleStatus().setOperatingVehicles(vs.getOperatingVehicles().intValue());
template.getVehicleStatus().setCompletedVehicles(vs.getCompletedVehicles().intValue());
}
// ====== 真实数据本月任务统计 taskTotal / avgTaskDuration / taskCompletionRate ======
long monthTasks = biPlatformRealDataService.countMonthTasks();
if (template.getMonthlyTaskStatistics() != null) {
template.getMonthlyTaskStatistics().setTaskTotal((int) monthTasks);
com.mhd.bi.domain.biPlatformRealData.repository.po.RealMonthlyTaskDurationPO monthStats =
biPlatformRealDataService.queryMonthTaskStats();
if (monthStats != null) {
if (monthStats.getAvgDurationHours() != null) {
double v = monthStats.getAvgDurationHours();
template.getMonthlyTaskStatistics().setAvgTaskDuration(Math.round(v * 100.0) / 100.0);
}
Long total = monthStats.getTotalCount();
Long completed = monthStats.getCompletedCount();
if (total != null && total > 0 && completed != null) {
int rate = (int) Math.round(((double) completed.longValue() / total.longValue()) * 100.0);
template.getMonthlyTaskStatistics().setTaskCompletionRate(rate);
} else {
template.getMonthlyTaskStatistics().setTaskCompletionRate(0);
}
}
}
// ====== 真实数据任务负荷今日 24 小时 ======
List<RealTaskLoadPO> loads = biPlatformRealDataService.queryTaskLoadToday();
if (!loads.isEmpty() && template.getTaskLoadStatistics() != null) {
Map<Integer, Long> hourMap = new HashMap<>();
for (RealTaskLoadPO l : loads) {
hourMap.put(l.getHourOfDay(), l.getTaskCount());
}
for (com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.TaskLoadItemVO item : template.getTaskLoadStatistics()) {
Integer hour = parseHourFromLabel(item.getTime());
if (hour != null) {
Long n = hourMap.get(hour);
if (n != null) item.setTaskCount(n.intValue());
}
}
}
// ====== 真实数据任务类型统计本月 YMS QMS_MAIN_BUSINESS 按业务类型 BUSINESS_NAME 分组 ======
template.setTaskTypeStatistics(biPlatformRealDataService.queryMonthTransportOrderByType());
return template;
}
private static Integer parseHourFromLabel(String label) {
if (label == null) return null;
// "15时" -> 15
try {
String s = label.replace("", "").trim();
return Integer.parseInt(s);
} catch (Exception e) {
return null;
}
}
/**
@@ -127,6 +127,8 @@ public final class BiSnapshotWeeklyRandomDataBuilder {
for (String[] row : Baseline.P_PLATES) {
int dur = jitterInt(Integer.parseInt(row[3]), r);
vehicles.add(PlatformVehicleItemVO.builder()
.appointmentTime(Baseline.P_APPOINTMENT_TIME)
.workFloor(Baseline.P_WORK_FLOOR)
.plateNumber(row[0])
.status(row[1])
.platformId(row[2])
@@ -145,7 +147,7 @@ public final class BiSnapshotWeeklyRandomDataBuilder {
PlatformOverviewVO overview = PlatformOverviewVO.builder()
.totalPlatforms(Math.max(1, jitterInt(Baseline.P_TOT_PL, r)))
.currentOccupancyRate(jitterPercentInt(Baseline.P_OCC, r))
.currentOccupancyRate((double) jitterPercentInt(Baseline.P_OCC, r))
.operatingPlatforms(Math.max(0, jitterInt(Baseline.P_OP, r)))
.todayTasks(Math.max(0, jitterInt(Baseline.P_TASKS, r)))
.build();
@@ -153,10 +155,13 @@ public final class BiSnapshotWeeklyRandomDataBuilder {
VehicleStatusVO vs = VehicleStatusVO.builder()
.todayReservedVehicles(Math.max(0, jitterInt(Baseline.P_RESV, r)))
.notCheckedIn(Math.max(0, jitterInt(Baseline.P_NC, r)))
.waiting(Math.max(0, jitterInt(Baseline.P_WAIT, r)))
.callStatusTotal(Math.max(0, jitterInt(Baseline.P_CALL_STATUS_TOTAL, r)))
.operatingVehicles(Math.max(0, jitterInt(Baseline.P_OPV, r)))
.completedVehicles(Math.max(0, jitterInt(Baseline.P_DONE, r)))
.build();
List<AvgOperationDurationTrendItemVO> avgTrend = new ArrayList<>();
for (int i = 0; i < Baseline.P_MO_LABELS.length; i++) {
avgTrend.add(AvgOperationDurationTrendItemVO.builder()
@@ -183,13 +188,8 @@ public final class BiSnapshotWeeklyRandomDataBuilder {
.build());
}
// 月台告警按业务要求全部置 0趋势/统计/分布均不生成写死数据
List<PlatformAlarmTrendItemVO> alarmTrend = new ArrayList<>();
for (int i = 0; i < Baseline.P_AL_D.length; i++) {
alarmTrend.add(PlatformAlarmTrendItemVO.builder()
.date(Baseline.P_AL_D[i])
.alarmCount(Math.max(0, jitterInt(Baseline.P_AL_C[i], r)))
.build());
}
List<TaskTypeCountItemVO> typeCounts = new ArrayList<>();
for (int i = 0; i < Baseline.P_TT_TYPES.length; i++) {
@@ -199,18 +199,11 @@ public final class BiSnapshotWeeklyRandomDataBuilder {
.build());
}
int todayAl = Math.max(0, jitterInt(Baseline.P_AL_TOT, r));
int handled = Math.max(0, jitterInt(Baseline.P_AL_H, r));
handled = Math.min(handled, todayAl);
int unhandled = Math.max(0, todayAl - handled);
int todayAl = 0;
int handled = 0;
int unhandled = 0;
List<PlatformAlarmDistItemVO> dist = new ArrayList<>();
for (int i = 0; i < Baseline.P_DIST_T.length; i++) {
dist.add(PlatformAlarmDistItemVO.builder()
.type(Baseline.P_DIST_T[i])
.count(Math.max(0, jitterInt(Baseline.P_DIST_C[i], r)))
.build());
}
return PlatformSurveillanceVO.builder()
.vehicles(vehicles)
@@ -394,6 +387,8 @@ public final class BiSnapshotWeeklyRandomDataBuilder {
static final String[] W_CUST_NAMES = {"华东冷链", "华南汽配", "西南快消", "华北家电", "跨境达"};
static final int[] W_CUST_AMT = {198, 172, 205, 189, 221};
static final String P_APPOINTMENT_TIME = "2026-08-03 09:30:00";
static final String P_WORK_FLOOR = "一楼";
static final String[][] P_PLATES = {
{"粤A12345", "待入场", "#12", "88"},
{"闽D99887", "作业中", "#07", "142"},
@@ -411,6 +406,8 @@ public final class BiSnapshotWeeklyRandomDataBuilder {
static final int P_TASKS = 418;
static final int P_RESV = 2_850;
static final int P_NC = 920;
static final int P_WAIT = 680;
static final int P_CALL_STATUS_TOTAL = 680;
static final int P_OPV = 1_180;
static final int P_DONE = 1_420;
static final String[] P_MO_LABELS = {"5月", "6月", "7月"};
@@ -3,6 +3,10 @@ package com.mhd.bi.interfaces.facadeApi.biReport;
import com.mhd.bi.domain.biSnapshotSync.service.BiReportSnapshotSyncService;
import com.mhd.bi.domain.biComprehensive.service.BiComprehensiveReportService;
import com.mhd.bi.domain.biPlatformSurveillance.service.BiPlatformSurveillanceReportService;
import com.mhd.bi.domain.biPlatformRealData.service.BiPlatformRealDataService;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealBusinessTypeStatPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformFloorStatPO;
import com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformInfoPO;
import com.mhd.bi.domain.biOverallOperation.service.BiOverallOperationReportService;
import com.mhd.bi.domain.biHkMacaoServiceZone.service.BiHkMacaoServiceZoneReportService;
import com.mhd.bi.domain.biTransportOperationZone.service.BiTransportOperationZoneReportService;
@@ -11,12 +15,17 @@ import com.mhd.bi.domain.biWarehouseTransport.service.BiWarehouseTransportReport
import com.mhd.bi.interfaces.facadeApi.biReport.dto.BiApiResult;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.ComprehensiveSituationVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.WarehouseTransportSituationVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.gps.NanqiGpsLocationVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.overall.OverallOperationSituationVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.PlatformSurveillanceVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.hkMacaoZone.HkMacaoServiceZoneVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.transportZone.TransportOperationZoneVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.warehouseZone.WarehouseOperationZoneVO;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.feign.ThirdPartyServiceFeign;
import com.mhd.common.core.web.controller.BaseController;
import com.mhd.common.core.web.domain.AjaxResult;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@@ -29,6 +38,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* BI 报表接口
*/
@@ -48,6 +59,9 @@ public class BiReportApi extends BaseController {
@Autowired
private BiPlatformSurveillanceReportService biPlatformSurveillanceReportService;
@Autowired
private BiPlatformRealDataService biPlatformRealDataService;
@Autowired
private BiOverallOperationReportService biOverallOperationReportService;
@@ -63,6 +77,12 @@ public class BiReportApi extends BaseController {
@Autowired
private BiReportSnapshotSyncService biReportSnapshotSyncService;
@Autowired
private ThirdPartyServiceFeign thirdPartyServiceFeign;
@Autowired
private ObjectMapper objectMapper;
@ApiOperation(value = "手动触发快照同步", notes = "立即写入各 BI 快照表(综合、仓储运输、月台监测、总体运营、仓储运营专区、运输运营专区、港澳服务专区);须带 X-BI-Access-Token")
@PostMapping("/snapshotSync/run")
@@ -92,14 +112,67 @@ public class BiReportApi extends BaseController {
}
/**
* 月台监测指标查询按照 del_flag=1 create_time 最新一条
* 月台监测指标查询实时查 YMS 真实字段 + 写死字段并落库一条到 BI_PLATFORM_SURVEILLANCE_SNAPSHOT
*/
@ApiOperation(value = "月台监测指标查询", notes = "返回 DEL_FLAG=1 且 CREATE_TIME 最新的一条快照")
@ApiOperation(value = "月台监测指标查询", notes = "每次调用实时查询 YMS 库组装并写入快照表;部分字段为真实业务数据,部分为写死数据")
@GetMapping("/platformSurveillance")
public BiApiResult<PlatformSurveillanceVO> platformSurveillance() {
PlatformSurveillanceVO data = biPlatformSurveillanceReportService.loadLatestPlatformSurveillance();
PlatformSurveillanceVO data = biPlatformRealDataService.buildRealTimePlatformSurveillanceAndPersist();
return BiApiResult.ok(data);
}
/**
* 今日预约-业务类型统计实时查 YMS 不落库
*/
@ApiOperation(value = "今日预约业务类型统计", notes = "按业务类型分组统计今日预约数量,实时查询 YMS 库,不落库;例:航空打板 3 条")
@GetMapping("/businessTypeStats")
public BiApiResult<List<RealBusinessTypeStatPO>> businessTypeStats() {
List<RealBusinessTypeStatPO> data = biPlatformRealDataService.queryTodayBusinessTypeStats();
return BiApiResult.ok(data);
}
/**
* 月台监控-按楼层统计月台车辆实时查 YMS 不落库
*/
@ApiOperation(value = "月台车辆统计(按楼层)", notes = "按楼层统计月台数量、今日预约车辆、当前作业车辆,实时查询 YMS 库,不落库")
@GetMapping("/platformFloorStats")
public BiApiResult<List<RealPlatformFloorStatPO>> platformFloorStats() {
List<RealPlatformFloorStatPO> data = biPlatformRealDataService.queryPlatformFloorStats();
return BiApiResult.ok(data);
}
/**
* 月台管理列表实时查 YMS qms_window_info不落库
*/
@ApiOperation(value = "月台管理列表", notes = "实时查询 YMS 库 qms_window_info,返回月台/鹤位窗口列表(机构、月台号、月台名称、楼层、绑定屏、UUID、状态等),不落库")
@GetMapping("/platformInfoList")
public BiApiResult<List<RealPlatformInfoPO>> platformInfoList() {
List<RealPlatformInfoPO> data = biPlatformRealDataService.queryPlatformInfoList();
return BiApiResult.ok(data);
}
/**
* 南岐GPS根据车牌号查询车辆实时定位
* 内部经 ThirdPartyServiceFeign 转发到 mhd_thrid_party /nanqiGps/queryByPlate逻辑仍在 mhd_thrid_party
*/
@ApiOperation(value = "根据车牌号查询车辆实时定位(南岐GPS)", notes = "按车牌号查询南岐GPS车辆实时定位,实时转发到三方服务")
@GetMapping("/nanqiGps/queryByPlate")
public BiApiResult<NanqiGpsLocationVO> nanqiQueryByPlate(
@ApiParam(value = "车牌号")
@RequestParam(value = "carPlate") String carPlate) {
if (carPlate == null || carPlate.trim().isEmpty()) {
throw new ServiceException("车牌号不能为空");
}
AjaxResult result = thirdPartyServiceFeign.nanqiQueryByPlate(carPlate);
Object codeObj = result == null ? null : result.get("code");
if (codeObj == null || !"200".equals(String.valueOf(codeObj))) {
String msg = result == null ? "南岐GPS查询失败" : String.valueOf(result.get("msg"));
throw new ServiceException(msg);
}
Object data = result.get("data");
NanqiGpsLocationVO vo = objectMapper.convertValue(data, NanqiGpsLocationVO.class);
return BiApiResult.ok(vo);
}
//园区物流大屏接口----------------------------------------------------------------------
/**
* 总体运营态势
@@ -0,0 +1,248 @@
package com.mhd.bi.interfaces.facadeApi.biReport.vo.gps;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 南岐GPS 车辆定位信息 VO mhd_thrid_party.NanqiGpsLocationVO 同构 BI 开放接口返回
*
* @author mhd
*/
@Data
@ApiModel("南岐GPS 车辆定位信息")
public class NanqiGpsLocationVO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("应答结果:1成功 0失败")
private Integer rspCode;
@ApiModelProperty("应答描述")
private String rspDesc;
@ApiModelProperty("车辆id")
private String carId;
@ApiModelProperty("车牌号")
private String carPlate;
@ApiModelProperty("车辆名")
private String carName;
@ApiModelProperty("车队id")
private String teamId;
@ApiModelProperty("车队名称")
private String teamName;
@ApiModelProperty("终端号")
private String tmnNo;
@ApiModelProperty("消息序列号")
private String tmnKey;
@ApiModelProperty("卡号")
private String simCard;
@ApiModelProperty("定位时间")
private String time;
@ApiModelProperty("经度(WGS84")
private BigDecimal lng;
@ApiModelProperty("纬度(WGS84")
private BigDecimal lat;
@ApiModelProperty("百度经度")
private BigDecimal blng;
@ApiModelProperty("百度纬度")
private BigDecimal blat;
@ApiModelProperty("谷歌/高德经度")
private BigDecimal glng;
@ApiModelProperty("谷歌/高德纬度")
private BigDecimal glat;
@ApiModelProperty("海拔(米)")
private BigDecimal height;
@ApiModelProperty("速度(千米/小时)")
private BigDecimal speed;
@ApiModelProperty("方向 0~360")
private String drct;
@ApiModelProperty("昨日平台总里程(千米)")
private String prevDayTotalMile;
@ApiModelProperty("平台总里程(千米)")
private String mile;
@ApiModelProperty("今日里程(千米)")
private String preMile;
@ApiModelProperty("终端里程(千米)")
private String tmnMile;
@ApiModelProperty("定位信号:0无 弱<=3 中<=6 强>6")
private String satl;
@ApiModelProperty("通讯信号:0无 弱<=10 中<=20 强>20")
private String sgn;
@ApiModelProperty("地理描述")
private String addr;
@ApiModelProperty("车辆定位状态")
private String state;
@ApiModelProperty("车辆状态文字")
private String stateCn;
@ApiModelProperty("驾驶员")
private String drvName;
@ApiModelProperty("驾驶员电话")
private String drvPhone;
@ApiModelProperty("车牌颜色")
private String plateColor;
@ApiModelProperty("车辆类型")
private String carType;
@ApiModelProperty("地图图标")
private String icon;
@ApiModelProperty("地图图标完整链接")
private String iconLink;
@ApiModelProperty("是否上传自定义图片:true取上传图片 false取大图")
private String uploadFlag;
@ApiModelProperty("大图片")
private String bigIcon;
@ApiModelProperty("大图片完整链接")
private String bigIconLink;
@ApiModelProperty("实时照片")
private String photoIcon;
@ApiModelProperty("中文方向")
private String drctCn;
@ApiModelProperty("今日行驶时长(秒)")
private String todayRun;
@ApiModelProperty("行停时长")
private String runStopTime;
@ApiModelProperty("行停时长(秒),排序时使用")
private String runStopTimeSecond;
@ApiModelProperty("ACC时长")
private String accTime;
@ApiModelProperty("ACC总时长")
private String totalAccTime;
@ApiModelProperty("离线时长")
private String offLineTime;
@ApiModelProperty("信号线(返回集合,每记录含name/value)")
private String sgnStts;
@ApiModelProperty("提醒信息(返回集合,每记录含name/value)")
private String reminds;
@ApiModelProperty("油量(返回集合,每记录含name/value)")
private String st1;
@ApiModelProperty("载重(返回集合,每记录含name/value)")
private String st2;
@ApiModelProperty("温度(返回集合,每记录含name/value)")
private String st3;
@ApiModelProperty("湿度(返回集合,每记录含name/value)")
private String st4;
@ApiModelProperty("水位(返回集合,每记录含name/value)")
private String st5;
@ApiModelProperty("服务到期状态:1已到期 0未到期")
private String expState;
@ApiModelProperty("服务期限")
private String expTime;
@ApiModelProperty("油量")
private String oil;
@ApiModelProperty("定位附加项(JSON")
private String protocols;
@ApiModelProperty("扩展字段(JSON")
private String exts;
@ApiModelProperty("模拟量1")
private String moni1;
@ApiModelProperty("模拟量2")
private String moni2;
@ApiModelProperty("模拟量3")
private String moni3;
@ApiModelProperty("模拟量4")
private String moni4;
@ApiModelProperty("视频通道(JSON")
private String videos;
@ApiModelProperty("未处理报警类型名称(逗号分隔)")
private String alarms;
@ApiModelProperty("未处理报警类型ID(逗号分隔)")
private String alarmTypeIds;
@ApiModelProperty("终端型号")
private String tmnType;
@ApiModelProperty("终端到期时间")
private String tmnExpirTime;
@ApiModelProperty("视频设备报警id集合")
private String videoAlarmTypes;
@ApiModelProperty("驾驶员登签姓名(卡号)")
private String driverSign;
@ApiModelProperty("驾驶员登签电话号码")
private String driverSignPhone;
@ApiModelProperty("驾驶员登签时间")
private String driverSignTime;
@ApiModelProperty("驾驶员登签时长")
private String drvSignTimeLong;
@ApiModelProperty("车辆基本状态(16进制位掩码)")
private String carStts;
@ApiModelProperty("报警状态(16进制位掩码)")
private String alarmStts;
@ApiModelProperty("协议版本")
private String prtcVer;
@ApiModelProperty("接入端口")
private String tmnPort;
}
@@ -1,5 +1,6 @@
package com.mhd.bi.interfaces.facadeApi.biReport.vo.hkMacaoZone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -17,6 +18,7 @@ import java.util.List;
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel("BI-港澳服务专区")
public class HkMacaoServiceZoneVO {
@@ -1,5 +1,6 @@
package com.mhd.bi.interfaces.facadeApi.biReport.vo.hkMacaoZone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
@@ -11,6 +12,7 @@ import lombok.NoArgsConstructor;
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
@ApiModel("BI-港澳服务专区-地图点位")
public class HkMapPointVO {
@@ -1,5 +1,6 @@
package com.mhd.bi.interfaces.facadeApi.biReport.vo.hkMacaoZone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -38,4 +39,24 @@ public class HkVehicleDetailsVO {
@JsonProperty("update_time")
@ApiModelProperty("更新时间")
private String updateTime;
@ApiModelProperty("状态")
private String status;
@ApiModelProperty("运输方向")
private String direction;
@ApiModelProperty("货物类型")
private String cargo;
@ApiModelProperty("预计到达时间")
private String eta;
@JsonProperty("transportion_number")
@ApiModelProperty("运单号")
private String transportionNumber;
@JsonProperty("cargo_source")
@ApiModelProperty("货源")
private String cargoSource;
}
@@ -18,7 +18,7 @@ public class PlatformOverviewVO {
private Integer totalPlatforms;
@ApiModelProperty("当前占用率,单位:%")
private Integer currentOccupancyRate;
private Double currentOccupancyRate;
@ApiModelProperty("当前作业中,单位:个")
private Integer operatingPlatforms;
@@ -14,6 +14,12 @@ import lombok.NoArgsConstructor;
@ApiModel("月台监测-作业车辆")
public class PlatformVehicleItemVO {
@ApiModelProperty("预约申请时间")
private String appointmentTime;
@ApiModelProperty("作业楼层")
private String workFloor;
@ApiModelProperty("车牌号码")
private String plateNumber;
@@ -20,6 +20,12 @@ public class VehicleStatusVO {
@ApiModelProperty("当前未签到,单位:辆")
private Integer notCheckedIn;
@ApiModelProperty("当前等待作业(已预约/已签到/已叫号),单位:辆")
private Integer waiting;
@ApiModelProperty("已签到+已叫号+已过号(FLOW_STATUS IN 2/3/4),单位:辆")
private Integer callStatusTotal;
@ApiModelProperty("当前作业中,单位:辆")
private Integer operatingVehicles;
@@ -0,0 +1,210 @@
<?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.mhd.bi.domain.biPlatformRealData.repository.mapper.BiPlatformRealDataMapper">
<!-- 作业车辆状态列表(vehicles):仅查询预约日期是今天(TARGET_DATE)的车辆
plateNumber <- qms_main_business.CAR_NO
status <- qms_main_business.FLOW_STATUS
platformId <- qms_main_business.WINDOW_NAME
platformDuration <- qms_main_business.EXIT_TIME - ENTRY_TIME
appointmentTime <- qms_main_business.CREATE_TIME
workFloor <- qms_window_info.PLATFORM_FLOOR WINDOW_NAME
-->
<select id="queryVehicles" resultType="com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformVehiclePO">
SELECT
mb.CAR_NO AS plateNumber,
mb.FLOW_STATUS AS status,
mb.WINDOW_NAME AS platformId,
CASE
WHEN mb.EXIT_TIME IS NOT NULL AND mb.ENTRY_TIME IS NOT NULL
THEN CAST((mb.EXIT_TIME - mb.ENTRY_TIME) * 24 * 60 AS BIGINT)
ELSE 0
END AS platformDuration,
TO_CHAR(mb.CREATE_TIME, 'YYYY-MM-DD HH24:MI:SS') AS appointmentTime,
wi.PLATFORM_FLOOR AS workFloor
FROM NGWL_TEST_YMS.QMS_MAIN_BUSINESS mb
LEFT JOIN NGWL_TEST_YMS.QMS_WINDOW_INFO wi
ON wi.WINDOW_NAME = mb.WINDOW_NAME
WHERE mb.TARGET_DATE IS NOT NULL
AND TRUNC(mb.TARGET_DATE) = TRUNC(SYSDATE)
ORDER BY mb.CREATE_TIME DESC
</select>
<!-- 月台概览:totalPlatforms(总条数)、operatingPlatforms(作业状态=占用,JOB_STATUS: 0空闲 1占用) -->
<select id="queryPlatformOverview" resultType="com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformOverviewPO">
SELECT
COUNT(1) AS totalPlatforms,
SUM(CASE WHEN JOB_STATUS = 1 THEN 1 ELSE 0 END) AS operatingPlatforms
FROM NGWL_TEST_YMS.QMS_WINDOW_INFO
</select>
<!-- 今日作业任务:按预约时间 TARGET_DATE(今日)统计主业务记录数 -->
<select id="countTodayTasks" resultType="java.lang.Long">
SELECT COUNT(1)
FROM NGWL_TEST_YMS.QMS_MAIN_BUSINESS
WHERE TARGET_DATE IS NOT NULL
AND TRUNC(TARGET_DATE) = TRUNC(SYSDATE)
</select>
<!-- 今日作业准时率统计:
total 今日有入场时间的预约车辆数(ENTRY_TIME 不为空 且 TARGET_DATE = 今天)
onTimeCount 今日准时车辆数(实际进入时间 < 预约日期 + BOOKING_END_TIME ENTRY_TIME < TRUNC(TARGET_DATE) +
「准时率 = 今日准时车辆数 / 今日有入场时间的车辆数 × 100%(四舍五入取整);分子分母都只统计有入场时间的车辆」
BOOKING_END_TIME 存纯时分(如 18:30),故用 TO_DATE 解析后取其时分间隔加到 TARGET_DATE 上
-->
<select id="queryTodayOnTimeStats" resultType="com.mhd.bi.domain.biPlatformRealData.repository.po.RealOnTimeStatPO">
SELECT
SUM(CASE WHEN ENTRY_TIME IS NOT NULL
AND TARGET_DATE IS NOT NULL
AND TRUNC(TARGET_DATE) = TRUNC(SYSDATE) THEN 1 ELSE 0 END) AS total,
SUM(CASE WHEN ENTRY_TIME IS NOT NULL
AND TRUNC(TARGET_DATE) = TRUNC(SYSDATE)
AND ENTRY_TIME &lt; TRUNC(TARGET_DATE)
+ (TO_DATE(BOOKING_END_TIME, 'HH24:MI') - TRUNC(TO_DATE(BOOKING_END_TIME, 'HH24:MI')))
THEN 1 ELSE 0 END) AS onTimeCount
FROM NGWL_TEST_YMS.QMS_MAIN_BUSINESS
</select>
<!-- 车辆状态统计:今日的统计(按创建时间 CREATE_TIME / 流程状态)
todayReservedVehicles 改为按预约日期 TARGET_DATE(其它 3 项保持 CREATE_TIME
waiting 等待作业:FLOW_STATUS IN ('1','2','3') 已预约/已签到/已叫号 且 预约日期 = 今天
callStatusTotal 叫号状态合计:已签到 + 已叫号 + 已过号 = FLOW_STATUS IN ('2','3','4') 且 预约日期 = 今天
FLOW_STATUS: 1已预约 2已签到 3已叫号 4已过号 5已进场 6已称重 7已装车 8二次称重 9已结算 10已还卡 11已出场 12已取消 -->
<select id="queryVehicleStatusToday" resultType="com.mhd.bi.domain.biPlatformRealData.repository.po.RealVehicleStatusPO">
SELECT
SUM(CASE WHEN TRUNC(TARGET_DATE) = TRUNC(SYSDATE) THEN 1 ELSE 0 END) AS todayReservedVehicles,
SUM(CASE WHEN FLOW_STATUS = '1' AND TRUNC(CREATE_TIME) = TRUNC(SYSDATE) THEN 1 ELSE 0 END) AS notCheckedIn,
SUM(CASE WHEN FLOW_STATUS IN ('1','2','3') AND TRUNC(TARGET_DATE) = TRUNC(SYSDATE) THEN 1 ELSE 0 END) AS waiting,
SUM(CASE WHEN FLOW_STATUS IN ('2','3','4') AND TRUNC(TARGET_DATE) = TRUNC(SYSDATE) THEN 1 ELSE 0 END) AS callStatusTotal,
SUM(CASE WHEN FLOW_STATUS IN ('5','6','7','8','9','10') AND TRUNC(CREATE_TIME) = TRUNC(SYSDATE) THEN 1 ELSE 0 END) AS operatingVehicles,
SUM(CASE WHEN FLOW_STATUS = '11' AND TRUNC(CREATE_TIME) = TRUNC(SYSDATE) THEN 1 ELSE 0 END) AS completedVehicles
FROM NGWL_TEST_YMS.QMS_MAIN_BUSINESS
</select>
<!-- 本月任务量:按预约日期 TARGET_DATE(Y预约日期)统计本月预约总数量 -->
<select id="countMonthTasks" resultType="java.lang.Long">
SELECT COUNT(1)
FROM NGWL_TEST_YMS.QMS_MAIN_BUSINESS
WHERE TARGET_DATE IS NOT NULL
AND TO_CHAR(TARGET_DATE, 'YYYY-MM') = TO_CHAR(SYSDATE, 'YYYY-MM')
</select>
<!-- 本月任务平均作业时长 / 完成率统计:
avgDurationHours 平均时长(小时)= AVG((EXIT_TIME - ENTRY_TIME) * 24)
仅 ENTRY_TIME 与 EXIT_TIME 都不为空时参与;
durationCount 参与平均时长统计的有效条数;
completedCount 本月(TARGET_DATE)已出场(EXIT_TIME IS NOT NULL)的数量;
totalCount 本月(TARGET_DATE)预约总数量。
-->
<select id="queryMonthTaskStats" resultType="com.mhd.bi.domain.biPlatformRealData.repository.po.RealMonthlyTaskDurationPO">
SELECT
AVG(CASE WHEN ENTRY_TIME IS NOT NULL AND EXIT_TIME IS NOT NULL
THEN (EXIT_TIME - ENTRY_TIME) * 24
END) AS avgDurationHours,
SUM(CASE WHEN ENTRY_TIME IS NOT NULL AND EXIT_TIME IS NOT NULL
AND TO_CHAR(ENTRY_TIME, 'YYYY-MM') = TO_CHAR(SYSDATE, 'YYYY-MM')
THEN 1 ELSE 0 END) AS durationCount,
SUM(CASE WHEN EXIT_TIME IS NOT NULL
AND TARGET_DATE IS NOT NULL
AND TO_CHAR(TARGET_DATE, 'YYYY-MM') = TO_CHAR(SYSDATE, 'YYYY-MM')
THEN 1 ELSE 0 END) AS completedCount,
SUM(CASE WHEN TARGET_DATE IS NOT NULL
AND TO_CHAR(TARGET_DATE, 'YYYY-MM') = TO_CHAR(SYSDATE, 'YYYY-MM')
THEN 1 ELSE 0 END) AS totalCount
FROM NGWL_TEST_YMS.QMS_MAIN_BUSINESS
</select>
<!-- 今日预约-业务类型统计:按 BUSINESS_NAME(业务类型名称)分组统计今日预约数量,按预约日期 TARGET_DATE 过滤 -->
<select id="queryTodayBusinessTypeStats" resultType="com.mhd.bi.domain.biPlatformRealData.repository.po.RealBusinessTypeStatPO">
SELECT
BUSINESS_NAME AS businessName,
COUNT(1) AS count
FROM NGWL_TEST_YMS.QMS_MAIN_BUSINESS
WHERE BUSINESS_NAME IS NOT NULL
AND TRUNC(TARGET_DATE) = TRUNC(SYSDATE)
GROUP BY BUSINESS_NAME
ORDER BY COUNT(1) DESC
</select>
<!-- 月台监控-按楼层统计:楼层从叫号月台 WINDOW_NAME 解析(如 S1-01 / N1-02 -> F1),不依赖字母前缀,只取 - 前面那段的数字
platformCount 来自 QMS_WINDOW_INFOtodayReservedVehicles/operatingVehicles 来自 QMS_MAIN_BUSINESS(按 TARGET_DATE=今天) -->
<select id="queryPlatformFloorStats" resultType="com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformFloorStatPO">
SELECT
'F' || SUBSTR(W.WINDOW_NAME, INSTR(W.WINDOW_NAME,'-')-1, 1) AS floorNo,
COUNT(DISTINCT W.WINDOW_NAME) AS platformCount,
COUNT(DISTINCT CASE
WHEN TRUNC(mb.TARGET_DATE) = TRUNC(SYSDATE) THEN mb.CAR_NO
END) AS todayReservedVehicles,
COUNT(DISTINCT CASE
WHEN TRUNC(mb.TARGET_DATE) = TRUNC(SYSDATE)
AND mb.FLOW_STATUS IN ('5','6','7','8','9','10')
THEN mb.CAR_NO
END) AS operatingVehicles
FROM NGWL_TEST_YMS.QMS_WINDOW_INFO W
LEFT JOIN NGWL_TEST_YMS.QMS_MAIN_BUSINESS mb
ON mb.WINDOW_NAME = W.WINDOW_NAME
WHERE W.WINDOW_NAME LIKE '%-%'
GROUP BY SUBSTR(W.WINDOW_NAME, INSTR(W.WINDOW_NAME,'-')-1, 1)
ORDER BY 1 DESC
</select>
<!-- 任务类型统计(来自 NGWL_TEST_YMS.QMS_MAIN_BUSINESS 预约登记表):
按本月预约车辆数(TARGET_DATE 在当前月)按 BUSINESS_NAME 业务类型分组统计 -->
<select id="queryMonthTransportOrderByType" resultType="com.mhd.bi.domain.biPlatformRealData.repository.po.RealTaskTypeStatPO">
SELECT
BUSINESS_NAME AS businessName,
COUNT(1) AS count
FROM NGWL_TEST_YMS.QMS_MAIN_BUSINESS
WHERE BUSINESS_NAME IS NOT NULL
AND TARGET_DATE IS NOT NULL
AND TO_CHAR(TARGET_DATE, 'YYYY-MM') = TO_CHAR(SYSDATE, 'YYYY-MM')
GROUP BY BUSINESS_NAME
ORDER BY COUNT(1) DESC
</select>
<!-- 任务负荷(今日 24 小时时段):按 EXTRACT(HOUR FROM ENTRY_TIME) 统计 -->
<select id="queryTaskLoadToday" resultType="com.mhd.bi.domain.biPlatformRealData.repository.po.RealTaskLoadPO">
SELECT
EXTRACT(HOUR FROM ENTRY_TIME) AS hourOfDay,
COUNT(1) AS taskCount
FROM NGWL_TEST_YMS.QMS_MAIN_BUSINESS
WHERE ENTRY_TIME IS NOT NULL
AND TRUNC(ENTRY_TIME) = TRUNC(SYSDATE)
GROUP BY EXTRACT(HOUR FROM ENTRY_TIME)
ORDER BY EXTRACT(HOUR FROM ENTRY_TIME)
</select>
<!-- 月台管理列表:查询 YMS qms_window_info 月台/鹤位窗口
机构名称 deptName <- sys_dept.DEPT_NAMEd.dept_id = a.ORG_NO
鹤位屏名称 berrNames <- qms_window_berr(WINDOW_ID/BERR_ID) join qms_berr_config(ID/BERR_NAME)WM_CONCAT
其余列来自 qms_window_info 本身 -->
<select id="queryPlatformInfoList" resultType="com.mhd.bi.domain.biPlatformRealData.repository.po.RealPlatformInfoPO">
SELECT
a.ID AS id,
a.ORG_NO AS orgNo,
d.DEPT_NAME AS deptName,
a.WINDOW_NUMBER AS windowNumber,
a.WINDOW_NAME AS windowName,
a.PRIORITY_SET AS prioritySet,
a.RUNNING_STATUS AS runningStatus,
a.CREATE_BY AS createBy,
TO_CHAR(a.CREATE_TIME, 'YYYY-MM-DD HH24:MI:SS') AS createTime,
a.UUID AS uuid,
a.GUIDE_IMAGES AS guideImages,
a.PLATFORM_FLOOR AS platformFloor,
a.JOB_STATUS AS jobStatus,
(
SELECT WM_CONCAT(qbc.BERR_NAME)
FROM NGWL_TEST_YMS.QMS_WINDOW_BERR qwb
LEFT JOIN NGWL_TEST_YMS.QMS_BERR_CONFIG qbc ON qbc.ID = qwb.BERR_ID
WHERE qwb.WINDOW_ID = a.ID
) AS berrNames
FROM NGWL_TEST_YMS.QMS_WINDOW_INFO a
LEFT JOIN NGWL_TEST_YMS.SYS_DEPT d ON d.DEPT_ID = a.ORG_NO
ORDER BY a.PLATFORM_FLOOR, a.WINDOW_NUMBER
</select>
</mapper>
@@ -18,6 +18,15 @@
values (#{payloadJson}, SYSDATE, SYSDATE, 1, #{remark})
</insert>
<update id="updateLatestPlatformSurveillanceSnapshot">
update NGWL_TEST_BI.BI_PLATFORM_SURVEILLANCE_SNAPSHOT
set PAYLOAD_JSON = #{payloadJson},
UPDATE_TIME = SYSDATE,
REMARK = #{remark}
where DEL_FLAG = 1
and ID = (select max(t.ID) from NGWL_TEST_BI.BI_PLATFORM_SURVEILLANCE_SNAPSHOT t where t.DEL_FLAG = 1)
</update>
<insert id="insertOverallOperationSnapshot">
insert into NGWL_TEST_BI.BI_OVERALL_OPERATION_SNAPSHOT (PAYLOAD_JSON, CREATE_TIME, UPDATE_TIME, DEL_FLAG, REMARK)
values (#{payloadJson}, SYSDATE, SYSDATE, 1, #{remark})
@@ -66,6 +66,9 @@ public class ServiceNameConstants
//YMS系统
public static final String YMS_SERVICE = "mhd-yms-service";
//YMS系统
public static final String XXL_JOB_SERVICE = "xxl-job-service";
}
@@ -32,8 +32,8 @@ public class TmsAddressMultiDTO {
@ApiModelProperty(value = "装卸货联系人电话")
private String contactPhone;
@ApiModelProperty(value = "装卸货日期(年月日)")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern="yyyy-MM-dd")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date layDate;
@ApiModelProperty(value = "装卸货时间(上午、下午、24小时)")
private String layTime;
@@ -88,5 +88,10 @@ public class SettlementCustomersPO extends BaseVOEntity{
private String settlementObject;
}
@ApiModelProperty(name = "散租推送计费单据/流水任务id")
private Integer pushBillingRecordJobId;
@ApiModelProperty(name = "整租推送计费单据/流水任务id")
private Integer pushContractManageToBmsJobId;
@ApiModelProperty(name = "生成应收账单任务id")
private Integer pushBillManageJobId;
}
@@ -0,0 +1,58 @@
package com.mhd.common.core.domain.po;
import com.mhd.common.core.annotation.Excel;
import com.mhd.common.core.web.domain.BaseVOEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "结算对象参数对象", description = "结算对象参数响应对象")
public class SettlementCustomersParametersPO extends BaseVOEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("id")
private Long id;
@ApiModelProperty("结算对象id")
private Long settlementCustomersId;
@ApiModelProperty("一级组织表ID")
@Excel(name = "一级组织表ID")
private Long topOrganizationId;
@ApiModelProperty("组织表ID")
@Excel(name = "组织表ID")
private Long organizationId;
@ApiModelProperty("组织名称")
@Excel(name = "组织名称")
private String organizationName;
@ApiModelProperty("结算对象编码")
@Excel(name = "结算对象编码")
private String settlementCustomersCode;
@ApiModelProperty("结算主体id")
@Excel(name = "结算主体id")
private Long settlementEntityId;
@ApiModelProperty("结算主体")
@Excel(name = "结算主体")
private String settlementEntity;
@ApiModelProperty("合同编号")
@Excel(name = "合同编号")
private String contractNumber;
@ApiModelProperty("合同管理id")
private Long contractManageId;
@ApiModelProperty("参数内容")
@Excel(name = "参数内容")
private String content;
@ApiModelProperty("参数名称")
@Excel(name = "参数名称")
private String parametersName;
}
@@ -271,4 +271,8 @@ public class UserShipperPo {
@ApiModelProperty("货主code")
private String roleCodeShipper;
@ApiModelProperty(name = "是否校验信用")
private String isCheckCredit;
@ApiModelProperty(name = "组织代码")
private String orgCode;
}
@@ -33,4 +33,6 @@ public class WarehousePO implements Serializable {
@Excel(name = "仓库名称")
private String warehouseName;
@Excel(name = "是否启用: 1-否 2-是")
private Integer isEnable;
}
@@ -46,6 +46,9 @@ public class MdmMerchantRecordDTO implements Serializable {
@ApiModelProperty("电子邮件")
private String desc16;
@ApiModelProperty("nc编码")
private String desc17;
@ApiModelProperty("身份证号")
private String desc23;
@@ -95,21 +95,12 @@ public final class MdmMerchantSyncFilter {
public static SkipReason resolveSkipReason(MdmMerchantRecordDTO record, String orgNcCode,
Long syncOrganizationId, Long topOrganizationId) {
if (record == null || StringUtils.isEmpty(record.getCode())) {
if (StringUtils.isEmpty(trim(record.getDesc17()))) {
return SkipReason.EMPTY_CODE;
}
if (!isCustomer(record)) {
return SkipReason.NOT_CUSTOMER;
}
if (StringUtils.isNotEmpty(orgNcCode) && !orgNcCode.equals(trim(record.getCode()))) {
return SkipReason.ORG_MISMATCH;
}
if (StringUtils.isEmpty(trim(record.getDesc1()))) {
return SkipReason.MISSING_NAME;
}
if (isDisabled(record)) {
return SkipReason.DISABLED;
}
return null;
}
@@ -16,7 +16,8 @@ public enum RoleEnum {
STORE_ADMIN("店铺管理员", "store_admin"),
OWNER_CARGO("货主", "ownerCargo"),
SUPPLIER("供应商", "supplier"),
CUSTOMER("客户", "customer");
CUSTOMER("客户", "customer"),
TENANT("租户", "tenant");
private String name;
private String code;
@@ -26,7 +26,8 @@ import java.io.InputStream;
import java.util.List;
import java.util.Map;
@FeignClient(value = "mhd-third-party-service", configuration = FeignAutoConfiguration.class)
// 目标地址由 nacos 配置项 feign.url.mhd-third-party-service 指定未配置时按服务名走服务发现
@FeignClient(value = "mhd-third-party-service",url = "http://10.102.192.31:8012", configuration = FeignAutoConfiguration.class)
public interface ThirdPartyServiceFeign {
//查询当前组织所有三方接口信息
@@ -334,4 +335,12 @@ public interface ThirdPartyServiceFeign {
@PostMapping("/mdmMasterData/queryMerchant")
R<com.mhd.common.core.domain.thirdparty.MdmMerchantQueryResultDTO> queryMdmMerchant(
@RequestBody com.mhd.common.core.domain.thirdparty.MdmMerchantQueryDTO queryDTO);
/**
* 南岐GPS根据车牌号查询车辆实时定位
* @param carPlate 车牌号
* @return AjaxResultdata 为车辆定位信息code=200 成功
*/
@GetMapping("/nanqiGps/queryByPlate")
AjaxResult nanqiQueryByPlate(@RequestParam("carPlate") String carPlate);
}
@@ -0,0 +1,112 @@
package com.mhd.common.core.jackson;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import java.io.IOException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 宽松日期反序列化兼容 yyyy-MM-dd纯日期等常见格式
*
* 背景库存查询等接口日期只保留年月日后前端可能把 "2026-07-06" 这类纯日期回传
* 而实体/DTO @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 是严格格式反序列化直接报
* InvalidFormatException本反序列化器解析顺序
* 1) 字段 @JsonFormat 指定的模式严格全匹配保持原行为
* 2) 兜底常见格式yyyy-MM-dd HH:mm:ss yyyy-MM-dd HH:mm yyyy-MM-dd
* 3) 纯数字按毫秒时间戳
* 4) 交给 Jackson 默认解析ISO-8601
* 仅放宽接受范围不影响任何既有格式的解析结果由各服务 DateCompatibilityConfig 显式注册生效
*
* @author rcx
* @date 2026-09-05
*/
public class FlexibleDateDeserializer extends JsonDeserializer<Date> implements ContextualDeserializer {
/** 兜底格式按长度降序排列,避免长文本被短格式部分解析 */
private static final String[] FALLBACK_PATTERNS = {
"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM-dd"
};
/** 字段 @JsonFormat 指定的模式,可为空 */
private final String pattern;
public FlexibleDateDeserializer() {
this(null);
}
public FlexibleDateDeserializer(String pattern) {
this.pattern = pattern;
}
@Override
public Date deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
String value = parser.getText();
if (value == null || value.trim().isEmpty()) {
return null;
}
value = value.trim();
// 纯数字按毫秒时间戳10位秒级时间戳也兼容
if (value.matches("\\d{10,}")) {
return new Date(Long.parseLong(value));
}
// 1) 字段 @JsonFormat 指定的模式优先
Date parsed = tryParse(value, pattern);
// 2) 兜底常见格式
if (parsed == null) {
for (String fallback : FALLBACK_PATTERNS) {
parsed = tryParse(value, fallback);
if (parsed != null) {
break;
}
}
}
// 3) 交给 Jackson 默认解析ISO-8601
if (parsed == null) {
try {
parsed = ctxt.parseDate(value);
} catch (IllegalArgumentException ignore) {
// 走不到默认解析时统一在下方抛出友好异常
}
}
if (parsed == null) {
throw ctxt.weirdStringException(value, Date.class,
"支持格式:yyyy-MM-dd HH:mm:ss / yyyy-MM-dd HH:mm / yyyy-MM-dd");
}
return parsed;
}
/**
* 严格全匹配解析解析失败或文本未完整消费如按 yyyy-MM-dd 解析 "2026-07-06 10:00:00"
* 都视为不匹配返回 null交由下一个格式尝试
*/
private Date tryParse(String value, String pattern) {
if (pattern == null || pattern.isEmpty()) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
sdf.setLenient(false);
ParsePosition pos = new ParsePosition(0);
Date date = sdf.parse(value, pos);
return (date != null && pos.getIndex() == value.length()) ? date : null;
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
if (property != null) {
JsonFormat jsonFormat = property.getAnnotation(JsonFormat.class);
if (jsonFormat != null && jsonFormat.pattern() != null && !jsonFormat.pattern().isEmpty()) {
return new FlexibleDateDeserializer(jsonFormat.pattern());
}
}
return this;
}
}
@@ -88,7 +88,8 @@ public class GlobalExceptionHandler
{
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生未知异常.", requestURI, e);
return AjaxResult.error(e.getMessage());
String msg = StringUtils.isEmpty(e.getMessage()) ? "系统繁忙,请稍后重试" : e.getMessage();
return AjaxResult.error(msg);
}
/**
@@ -99,7 +100,8 @@ public class GlobalExceptionHandler
{
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生系统异常.", requestURI, e);
return AjaxResult.error(e.getMessage());
String msg = StringUtils.isEmpty(e.getMessage()) ? "系统繁忙,请稍后重试" : e.getMessage();
return AjaxResult.error(msg);
}
/**
@@ -34,6 +34,8 @@ public class CaptchaConfig
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
// 验证码文本字符长度 默认为5
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
// 验证码文本字符源 默认为abcde2345678gfynmnpqr 改为纯数字
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
@@ -191,6 +191,7 @@ public class AuthFilter implements GlobalFilter, Ordered
/**
* 获取请求token
* 优先从 Authorization 请求头获取其次从 URL 参数 token 获取SSO场景
*/
private String getToken(ServerHttpRequest request)
{
@@ -200,6 +201,11 @@ public class AuthFilter implements GlobalFilter, Ordered
{
token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
}
// 兜底从URL参数中获取tokenSSO单点登录场景前端尚未存入localStorage时
if (StringUtils.isEmpty(token))
{
token = request.getQueryParams().getFirst("token");
}
return token;
}
+6 -13
View File
@@ -13,22 +13,15 @@ spring:
cloud:
nacos:
discovery:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
# server-addr: 10.102.192.31:6848
server-addr: 10.33.0.129:6010
#线上正式环境
# server-addr: 127.0.0.1:8848
# server-addr: 10.102.192.31:6848
server-addr: 127.0.0.1:8848
# server-addr: 10.102.192.30:6848
# server-addr: 10.33.0.129:6010
username: nacos
password: manhuoda@2023
config:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
server-addr: 10.33.0.129:6010
#线上正式环境
# server-addr: 127.0.0.1:8848
# server-addr: 10.102.192.31:6848
server-addr: 127.0.0.1:8848
# server-addr: 10.33.0.129:6010
# server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
group: DEFAULT_GROUP # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置
+10
View File
@@ -111,6 +111,16 @@
<version>2.24</version>
</dependency>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
<!-- JPush推送 -->
<!-- jpush极光推送导入start -->
<!-- <dependency>-->
@@ -40,6 +40,14 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import com.mhd.basic.interfaces.dto.shipperLeaseDetailsApi.WarehouseLeaseExportVO;
import com.mhd.common.core.utils.poi.ExcelUtil;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.math.BigDecimal;
import java.time.LocalDate;
@@ -270,14 +278,15 @@ public class LeaseApplicationService {
* 货主租赁明细
* 定时任务每天凌晨1点执行计算前一天的货主租赁明细
*/
@Scheduled(cron = "0 0 1 * * ?")
// @Scheduled(cron = "0 0 1 * * ?")
public void shipperLeaseDetails() {
log.info("开始执行货主租赁明细定时任务");
// 计算前一天的日期将时间设置为当天的0点0分0秒只保留日期部分
final Date yesterday = DateUtil.beginOfDay(DateUtil.offsetDay(new Date(), -1));
LeaseDO leaseDO = new LeaseDO();
leaseDO.setTime(yesterday);
leaseDO.setTime(yesterday); // 设置查询时间
leaseDO.setStatus(1); // 只查询启用状态的租赁停用的不参与出租率计算
//查询有效期内的租赁
List<LeasePO> leasePOS = queryList(leaseDO);
List<LeasePO> entireUnit = leasePOS.stream()
@@ -494,6 +503,103 @@ public class LeaseApplicationService {
return warehouseOccupancyRatesList;
}
/**
* 导出仓库出租率及客户租赁明细 sheet明细行带仓库当日汇总列
* 参数与 /warehouseOccupancyRate/list 一致
*/
public void exportOccupancyRate(HttpServletResponse response, ShipperLeaseDetailsDO shipperLeaseDetailsDO) throws IOException {
// 注意本方法不调用 warehouseOccupancyRate()因为该方法在不传 warehouseId
// totalArea 会算成全系统所有仓库库区面积之和 6168导致导出面积/日租率错误
// 这里自行按 (业务日期 + 仓库) 维度计算保证多仓库导出时每个仓库的面积/日租率正确
// ===== 1. 查全部明细用副本 DO避免影响外部=====
ShipperLeaseDetailsDO detailDO = new ShipperLeaseDetailsDO();
BeanUtils.copyProperties(shipperLeaseDetailsDO, detailDO);
List<ShipperLeaseDetailsPO> detailList = shipperLeaseDetailsService.queryList(detailDO);
if (detailList == null) {
detailList = new ArrayList<>();
}
// ===== 2. 预算每个仓库的总面积启用库区的 storageRegion 累加 warehouseId -> totalArea 映射 =====
Set<Long> warehouseIds = detailList.stream()
.map(ShipperLeaseDetailsPO::getWarehouseId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Map<Long, BigDecimal> warehouseTotalAreaMap = new HashMap<>();
for (Long wid : warehouseIds) {
StorageSectionDO storageSectionDO = new StorageSectionDO();
storageSectionDO.setWarehouseId(wid);
storageSectionDO.setOpeningUp(1);
List<StorageSectionPO> sections = storageSectionApplicationService.queryList(storageSectionDO);
BigDecimal area = BigDecimal.ZERO;
for (StorageSectionPO s : sections) {
area = area.add(s.getStorageRegion() == null ? BigDecimal.ZERO : s.getStorageRegion());
}
warehouseTotalAreaMap.put(wid, area);
}
// ===== 3. (业务日期 + 仓库ID) 聚合算每个仓库当天的整租/散租面积 =====
// summaryMap: key -> [整租面积, 散租面积]
SimpleDateFormat keySdf = new SimpleDateFormat("yyyy-MM-dd");
Map<String, BigDecimal[]> summaryMap = new HashMap<>();
for (ShipperLeaseDetailsPO d : detailList) {
String key = (d.getBusinessDate() == null ? "" : keySdf.format(d.getBusinessDate()))
+ "_" + d.getWarehouseId();
BigDecimal[] arr = summaryMap.computeIfAbsent(key, k -> new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO});
BigDecimal leaseArea = d.getLeaseArea() == null ? BigDecimal.ZERO : d.getLeaseArea();
if ("整租".equals(d.getLeaseType())) {
arr[0] = arr[0].add(leaseArea);
} else {
arr[1] = arr[1].add(leaseArea);
}
}
// ===== 4. 明细为主每行拼上对应仓库当天的汇总总面积/日租率按仓库单独算=====
List<WarehouseLeaseExportVO> exportList = new ArrayList<>();
for (ShipperLeaseDetailsPO d : detailList) {
WarehouseLeaseExportVO vo = new WarehouseLeaseExportVO();
// 明细列
vo.setBusinessDate(d.getBusinessDate());
vo.setOrganizationName(d.getOrganizationName());
vo.setWarehouseName(d.getWarehouseName());
vo.setCargoOwnerName(d.getCargoOwnerName());
vo.setLeaseType(d.getLeaseType());
vo.setLeaseArea(d.getLeaseArea());
// 汇总列
String key = (d.getBusinessDate() == null ? "" : keySdf.format(d.getBusinessDate()))
+ "_" + d.getWarehouseId();
BigDecimal[] arr = summaryMap.get(key);
BigDecimal entireLeaseArea = (arr != null) ? arr[0] : BigDecimal.ZERO;
BigDecimal fractionalLeaseArea = (arr != null) ? arr[1] : BigDecimal.ZERO;
vo.setEntireLeaseArea(entireLeaseArea);
vo.setFractionalLeaseArea(fractionalLeaseArea);
// 该仓库的总面积按仓库单独算不再用全局总和
BigDecimal widTotalArea = warehouseTotalAreaMap.getOrDefault(d.getWarehouseId(), BigDecimal.ZERO);
vo.setTotalArea(widTotalArea);
// 日租率 = (整租+散租) / 总面积 × 100保留2位小数直接输出百分比值 10.00
BigDecimal leaseSum = entireLeaseArea.add(fractionalLeaseArea);
BigDecimal dailyRate = widTotalArea.compareTo(BigDecimal.ZERO) == 0
? BigDecimal.ZERO
: leaseSum.multiply(new BigDecimal("100")).divide(widTotalArea, 2, BigDecimal.ROUND_HALF_UP);
vo.setDailyRentalRate(dailyRate);
exportList.add(vo);
}
// ===== 5. 按业务日期降序仓库名升序排序null 排最后=====
exportList.sort(Comparator
.comparing(WarehouseLeaseExportVO::getBusinessDate, Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing(WarehouseLeaseExportVO::getWarehouseName, Comparator.nullsLast(Comparator.naturalOrder())));
// ===== 6. ExcelUtil 导出项目通用做法 sheet=====
String fileName = URLEncoder.encode("仓库出租率导出", "UTF-8").replaceAll("\\+", "%20");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
ExcelUtil<WarehouseLeaseExportVO> util = new ExcelUtil<>(WarehouseLeaseExportVO.class);
util.exportExcel(response, exportList, "仓库出租率");
}
/**
* 定时任务整租推送到bms
@@ -537,7 +643,7 @@ public class LeaseApplicationService {
/**
* 定时任务散租推送到bms
*/
@Scheduled(cron = "0 0 0 * * ?")
// @Scheduled(cron = "0 0 0 * * ?")
public void ScatteredRentalSynchronization() {
LeaseDO leaseDO = new LeaseDO();
leaseDO.setTime(new Date());
@@ -581,6 +687,25 @@ public class LeaseApplicationService {
}
}
/**
* 启用/停用租赁
* @param leaseIds 租赁ID列表
* @param status 目标状态1=启用0=停用
*/
public Boolean updateStatus(List<Long> leaseIds, Integer status) {
LoginUser loginUser = SecurityUtils.getLoginUser();
Long updateBy = loginUser != null ? loginUser.getUserid() : null;
String updateByName = loginUser != null ? loginUser.getUsername() : null;
if (leaseIds == null || leaseIds.isEmpty()) {
throw new ServiceException("租赁ID不能为空");
}
if (status == null || (status != 0 && status != 1)) {
throw new ServiceException("状态值无效:1=启用,0=停用");
}
log.info("启用/停用租赁--结束,leaseIds={},状态={},更新人id={},更新人名称={}",leaseIds,status==0?"停用":"启用",updateBy,updateByName);
return leaseDomainService.updateStatus(leaseIds, status, updateBy, updateByName);
}
// /**
// * @description 设置数据字典键值
// * @author ZhouGY
@@ -461,7 +461,8 @@ public class MessageManageApplicationService
//获取当前登录人
LoginUser loginUser = SecurityUtils.getLoginUser();
if(null == loginUser){
throw new ServiceException("获取登录人失败");
//未登录(游客)返回空消息中心结构保证小程序界面正常展示而不报错
return buildEmptyAppNoticeList();
}
noticeMessageLoggingDo.setUserId(loginUser.getUserid());
//获取每种类型的最新一条
@@ -522,6 +523,27 @@ public class MessageManageApplicationService
return result;
}
/**
* 未登录(游客)时返回空的消息中心结构避免前端页面因无登录上下文而报错
* @return NoticeMessageLoggingAppListPo
*/
private NoticeMessageLoggingAppListPo buildEmptyAppNoticeList() {
NoticeMessageLoggingAppListPo result = new NoticeMessageLoggingAppListPo();
NoticeMessageLoggingAppListPo.CommonNotice serviceNotice = new NoticeMessageLoggingAppListPo.CommonNotice();
serviceNotice.setUnreadNum("0");
NoticeMessageLoggingAppListPo.CommonNotice activityNotice = new NoticeMessageLoggingAppListPo.CommonNotice();
activityNotice.setUnreadNum("0");
NoticeMessageLoggingAppListPo.CommonNotice logisticsNotice = new NoticeMessageLoggingAppListPo.CommonNotice();
logisticsNotice.setUnreadNum("0");
NoticeMessageLoggingAppListPo.CommonNotice systemNotice = new NoticeMessageLoggingAppListPo.CommonNotice();
systemNotice.setUnreadNum("0");
result.setServiceNotice(serviceNotice);
result.setActivityNotice(activityNotice);
result.setLogisticsNotice(logisticsNotice);
result.setSystemNotice(systemNotice);
return result;
}
/**
* APP根据类型获取消息通知
* @param noticeMessageLoggingDo
@@ -4,6 +4,7 @@ import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -11,16 +12,26 @@ import com.mhd.basic.domain.contractManage.entity.ContractManage;
import com.mhd.basic.domain.contractManage.repository.mapper.ContractManageMapper;
import com.mhd.basic.domain.contractManage.repository.po.ContractManagePO;
import com.mhd.basic.domain.contractManage.repository.todo.ContractManageDO;
import com.mhd.basic.domain.contractManage.repository.util.HttpWebServiceUtil;
import com.mhd.basic.domain.contractManage.repository.util.XxlJobOpenApiUtil;
import com.mhd.basic.domain.contractManage.service.ContractManageDomainService;
import com.mhd.basic.domain.contractManageDetail.entity.ContractManageDetail;
import com.mhd.basic.domain.contractManageDetail.repository.mapper.ContractManageDetailMapper;
import com.mhd.basic.domain.contractManageDetail.repository.po.ContractManageDetailPO;
import com.mhd.basic.domain.contractManageDetail.repository.todo.ContractManageDetailDO;
import com.mhd.basic.domain.contractManageDetail.service.ContractManageDetailDomainService;
import com.mhd.basic.domain.contractManageParameters.entity.ContractManageParameters;
import com.mhd.basic.domain.contractManageParameters.repository.facade.IContractManageParametersService;
import com.mhd.basic.domain.contractManageParameters.repository.mapper.ContractManageParametersMapper;
import com.mhd.basic.domain.contractManageParameters.repository.po.ContractManageParametersPO;
import com.mhd.basic.domain.contractManageParameters.repository.todo.ContractManageParametersDO;
import com.mhd.basic.domain.contractManageParameters.service.ContractManageParametersDomainService;
import com.mhd.basic.domain.expenseAccount.repository.po.ExpenseAccountPO;
import com.mhd.basic.domain.expenseAccount.service.ExpenseAccountDomainService;
import com.mhd.basic.interfaces.dto.contractManage.*;
import com.mhd.basic.interfaces.assember.contractManageParameters.ContractManageParametersAssembler;
import com.mhd.basic.interfaces.dto.contractManageDetail.ContractManageDetailDTO;
import com.mhd.basic.interfaces.dto.contractManageParameters.ContractManageParametersDTO;
import com.mhd.common.core.domain.po.*;
import com.mhd.common.core.enums.DictCode;
import com.mhd.common.core.exception.ServiceException;
@@ -32,18 +43,23 @@ import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.security.utils.SecurityUtils;
import com.mhd.system.api.BmsServiceFeign;
import com.mhd.system.api.SystemServiceFeign;
import com.mhd.system.api.domain.BusinessDocumentFeign;
import com.mhd.system.api.domain.MaterialInventoryPO;
import com.mhd.system.api.domain.SysDictData;
import com.mhd.system.api.model.LoginUser;
import com.mhd.system.service.ISysDictTypeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -75,6 +91,20 @@ public class ContractManageApplicationService {
@Autowired
private SystemServiceFeign systemServiceFeign;
@Autowired
private ContractManageParametersDomainService contractManageParametersDomainService;
@Autowired
private ContractManageParametersAssembler contractManageParametersAssembler;
@Autowired
private ContractManageParametersMapper contractManageParametersMapper;
@Autowired
private IContractManageParametersService contractManageParametersService;
@Resource
private XxlJobOpenApiUtil apiUtil;
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
private static final String token = "Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjozNTYzLCJ0b3BPcmdhbml6YXRpb25JZCI6MjgyNywidXNlcl9rZXkiOiI0N2MzY2U4My0wMmFjLTQ0NTQtOTdiYS1lYmQwMDc2MzNiNDMiLCJ1c2VybmFtZSI6ImNhbmdtYSJ9.tnZyywwburfBo3Kizdhfk5eYdXbrrZ9976Z0W7GrS6UqSpKwfI2RwdRwfYx7DbD7Ri1Fdj_eOVxBkjvdFF226Q";
/**
* 分页查询合同管理列表
@@ -126,7 +156,21 @@ public class ContractManageApplicationService {
contractManageDO.setTopOrganizationId(2827L);
}
}
return contractManageDomainService.queryList(contractManageDO);
List<ContractManagePO> list = contractManageDomainService.queryList(contractManageDO);
if (!list.isEmpty()) {
List<Long> contractManageIds = list.stream()
.map(ContractManagePO::getContractManageId)
.collect(Collectors.toList());
List<ContractManageParametersPO> allParams = contractManageParametersDomainService.queryListByManageIds(contractManageIds);
Map<Long, List<ContractManageParametersPO>> paramsMap = allParams.stream()
.collect(Collectors.groupingBy(ContractManageParametersPO::getContractManageId));
for (ContractManagePO po : list) {
po.setContractManageParametersList(paramsMap.getOrDefault(po.getContractManageId(), new ArrayList<>()));
}
}
return list;
}
// public BigDecimal getAmount(List<SubjectAndPriceReturn> subjectAndPriceReturnList) {
@@ -268,12 +312,25 @@ public class ContractManageApplicationService {
Long organizationId = contractManageDTO.getOrganizationId();
String sunjectCode = contractManageDTO.getSubjectCode();
Long topOrganizationId = contractManageDTO.getTopOrganizationId();
List<ContractManage> UserContractManages = contractManageMapper.selectList(new LambdaQueryWrapper<ContractManage>()
.eq(ContractManage::getSettlementCustomersId, settlementCustomersId)
.eq(ContractManage::getDelFlag, 1)
.eq(ContractManage::getOrganizationId, organizationId)
.eq(ContractManage::getTopOrganizationId, topOrganizationId)
.eq(ContractManage::getCommonContractFlag, 2));
ContractManageDO contractManageDO = new ContractManageDO();
contractManageDO.setOrganizationId(organizationId);
contractManageDO.setSettlementCustomersId(settlementCustomersId);
contractManageDO.setTopOrganizationId(topOrganizationId);
contractManageDO.setCommonContractFlag(2);
contractManageDO.setDelFlag(1);
contractManageDO.setFirstSubjectCode(sunjectCode);
List<ContractManagePO> contractManagePOS = contractManageMapper.queryList(contractManageDO);
if (contractManagePOS != null && contractManagePOS.size() > 1) {
throw new RuntimeException("同一费用科目存在多条合同,请检查");
}
List<ContractManage> UserContractManages = new ArrayList<>();
if (contractManagePOS != null) {
for (ContractManagePO po : contractManagePOS) {
ContractManage contractManage = new ContractManage();
BeanUtils.copyProperties(po, contractManage);
UserContractManages.add(contractManage);
}
}
if (UserContractManages != null && UserContractManages.size() > 0) {
//用户合同计费策略
calucateSubjectAndPriceStrategy(UserContractManages, organizationId, topOrganizationId, sunjectCode, result);
@@ -595,7 +652,9 @@ public class ContractManageApplicationService {
通用合同同一时间段同一合同类型只能存在一个
特殊合同同一结算主体同一时间段同一合同类型只能存在一个
*/
checkContract(contractManageDO);
//20260702取消同一时间段不能有相同合同校验
//checkContract(contractManageDO);
checkUniqueActiveContract(contractManageDO);
handleData(contractManageDO);
handleDict(contractManageDO);
contractManageDO.setContractNumber(OrderSequence.getOrderCode("HT"));
@@ -603,10 +662,43 @@ public class ContractManageApplicationService {
contractManageDO.setOrganizationId(loginUser.getUserPo().getOrganizationId());
contractManageDO.setOrganizationName(loginUser.getUserPo().getOrganizationName());
boolean flag = contractManageDomainService.insert(contractManageDO);
handleDetils(contractManageDO);
handleDetils(contractManageDO, true);
handleParameters(contractManageDO);
return flag;
}
/**
* 新增合同管理
*/
@Transactional
public ContractManageDO insertFeign(ContractManageDO contractManageDO) {
//获取当前登录人信息
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNull(loginUser)) {
throw new DigitalLogisticsException(UserError.TIMEOUT);
}
validateContractType(contractManageDO.getContractType());
/*
通用合同同一时间段同一合同类型只能存在一个
特殊合同同一结算主体同一时间段同一合同类型只能存在一个
*/
//20260702取消同一时间段不能有相同合同校验
//checkContract(contractManageDO);
checkUniqueActiveContract(contractManageDO);
handleData(contractManageDO);
handleDict(contractManageDO);
contractManageDO.setContractNumber(OrderSequence.getOrderCode("HT"));
contractManageDO.setTopOrganizationId(loginUser.getUserPo().getTopOrganizationId());
contractManageDO.setOrganizationId(loginUser.getUserPo().getOrganizationId());
contractManageDO.setOrganizationName(loginUser.getUserPo().getOrganizationName());
boolean flag = contractManageDomainService.insert(contractManageDO);
if (!flag) {
throw new ServiceException("新增合同管理失败,请检查数据");
}
handleDetils(contractManageDO, true);
return contractManageDO;
}
/**
* 处理数据字典
*/
@@ -734,10 +826,30 @@ public class ContractManageApplicationService {
}
}
private void checkUniqueActiveContract(ContractManageDO contractManageDO) {
if (contractManageDO.getContractState() != null && contractManageDO.getContractState() != 2) {
return;
}
if (contractManageDO.getSettlementCustomersId() == null
|| StringUtils.isEmpty(contractManageDO.getWarehouseTempLayerType())
|| StringUtils.isEmpty(contractManageDO.getContractRentType())) {
return;
}
long count = contractManageDomainService.countByUniqueKey(
contractManageDO.getSettlementCustomersId(),
contractManageDO.getWarehouseTempLayerType(),
contractManageDO.getContractRentType(),
contractManageDO.getContractManageId()
);
if (count > 0) {
throw new ServiceException("同一结算客户、同一温层、同一租赁类型只能存在一个使用中的合同");
}
}
/**
* 处理合同详情
*/
private void handleDetils(ContractManageDO contractManageDO) {
private void handleDetils(ContractManageDO contractManageDO, boolean isInsert) {
//获取当前登录人信息
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNull(loginUser)) {
@@ -745,6 +857,10 @@ public class ContractManageApplicationService {
}
//根据合同编码查询保存合同信息
ContractManagePO contractManagePO = contractManageDomainService.getInfoByCode1(contractManageDO.getOriginalContractNumber());
//修改时不管前端是否传明细都需要先删除该合同原有的明细避免明细为空时老明细仍在
if (!isInsert) {
contractManageDetailMapper.delete(new LambdaQueryWrapper<ContractManageDetail>().eq(ContractManageDetail::getContractManageId, contractManageDO.getContractManageId()));
}
//保存合同详情科目
List<ContractManageDetailDTO> contractManageDetailDTOList = contractManageDO.getContractManageDetailDTOList();
if(null != contractManageDetailDTOList && contractManageDetailDTOList.size()>0){
@@ -813,10 +929,13 @@ public class ContractManageApplicationService {
}
}
if(null != contractManagePO){
contractManageDetailDO.setContractManageId(contractManagePO.getContractManageId());
if (isInsert) {
// 新增/复制时使用新插入的合同ID
contractManageDetailDO.setContractManageId(contractManageDO.getContractManageId());
} else {
// 修改时使用当前正在修改的合同ID不能用 getInfoByCode1 查到的避免多条合同 originalContractNumber 相同导致明细错绑
contractManageDetailDO.setContractManageId(contractManageDO.getContractManageId());
}
//contractManageDetailDO.setContractManageId(contractManageDO.getContractManageId());
contractManageDetailDO.setTopOrganizationId(loginUser.getUserPo().getTopOrganizationId());
contractManageDetailDO.setOrganizationId(loginUser.getUserPo().getOrganizationId());
contractManageDetailDO.setOrganizationName(loginUser.getUserPo().getOrganizationName());
@@ -825,15 +944,122 @@ public class ContractManageApplicationService {
}
}
private void handleParameters(ContractManageDO contractManageDO) {
List<ContractManageParametersPO> existingList = contractManageParametersDomainService.queryListByManageId(contractManageDO.getContractManageId());
if (!existingList.isEmpty()) {
Long[] ids = existingList.stream().map(ContractManageParametersPO::getId).toArray(Long[]::new);
contractManageParametersDomainService.delete(ids);
}
if (StringUtils.isNotEmpty(contractManageDO.getParametersJson())) {
ContractManageParametersDTO dto = new ContractManageParametersDTO();
dto.setContractManageId(contractManageDO.getContractManageId());
dto.setContractNumber(contractManageDO.getContractNumber());
dto.setContractName(contractManageDO.getContractName());
dto.setParametersJson(contractManageDO.getParametersJson());
dto.setOrganizationId(contractManageDO.getOrganizationId());
dto.setOrganizationName(contractManageDO.getOrganizationName());
dto.setTopOrganizationId(contractManageDO.getTopOrganizationId());
ContractManageParametersDO parametersDO = contractManageParametersAssembler.toDO(dto);
contractManageParametersDomainService.insert(parametersDO);
if(StringUtils.isNotEmpty(contractManageDO.getSettlementCustomersCode())){
AjaxResult ajaxResult = bmsServiceFeign.getCustomersInfoByCode(contractManageDO.getSettlementCustomersCode());
if (!"200".equals(String.valueOf(ajaxResult.get("code")))){
throw new ServiceException("获取结算客户信息失败");
}
SettlementCustomersPO settlementCustomersPO = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), SettlementCustomersPO.class);
if(null == settlementCustomersPO){
throw new ServiceException("结算客户信息未找到");
}
Long settlementEntityId = settlementCustomersPO.getSettlementEntityId();
if(null != settlementEntityId){
Integer pushContractManageToBmsJobId = settlementCustomersPO.getPushContractManageToBmsJobId();
if (null != pushContractManageToBmsJobId) {
stopXxlJob(pushContractManageToBmsJobId);
}
Integer jobId = addXxlJob(settlementEntityId.toString());
settlementCustomersPO.setPushContractManageToBmsJobId(jobId);
AjaxResult updateResult = bmsServiceFeign.updatePushContractManageJobId(settlementCustomersPO.getSettlementCustomersId(), jobId);
if (!"200".equals(String.valueOf(updateResult.get("code")))) {
throw new ServiceException("更新结算对象定时任务ID失败");
}
}
}
}
}
/**
* 创建夜间23点定时任务
* @param shipperId 结算对象id作为任务参数
* @return xxlJobId 保存到业务表后续用于删除/暂停
*/
public Integer addXxlJob(String shipperId) {
XxlJobOpenApiUtil.JobInfoAddReq req = new XxlJobOpenApiUtil.JobInfoAddReq();
req.setJobGroup(5);
//生成唯一业务流水号拼接至JobDesc保证本次新建任务的JobDesc唯一据此查询jobId不会命中历史任务
String xxlJobBizNo = generateXxlJobBizNo();
req.setJobDesc("整租推送计费单据/流水任务,结算对象id:" + shipperId + ",业务流水号:" + xxlJobBizNo);
req.setAuthor("system");
req.setAlarmEmail("");
req.setScheduleType("CRON");
// 每天晚上23点执行
req.setScheduleConf("0 0 1 * * ?");
req.setGlueType("BEAN");
req.setExecutorHandler("pushContractManageToBms");
req.setExecutorParam(shipperId);
req.setGlueRemark("");
req.setGlueSource("");
req.setExecutorRouteStrategy("FIRST");
req.setChildJobId(null);
req.setMisfireStrategy("DO_NOTHING");
req.setExecutorBlockStrategy("SERIAL_EXECUTION");
req.setExecutorTimeout(0);
req.setExecutorFailRetryCount(0);
boolean addOk = apiUtil.addJob(req);
if (!addOk) {
throw new RuntimeException("创建夜间定时任务失败");
}
Integer xxlJobId = apiUtil.queryJobIdByDescAndParam(req.getJobDesc(), shipperId,"5");
if (xxlJobId == null) {
throw new RuntimeException("定时任务创建成功,但查询jobId失败");
}
return xxlJobId;
}
public void stopXxlJob(Integer shipperId) {
//1.实例化工具类建议交给Spring管理
XxlJobOpenApiUtil apiUtil = new XxlJobOpenApiUtil(adminAddresses,token);
//3.调用创建任务接口 返回任务ID
apiUtil.pauseJob(shipperId);
}
private static final DateTimeFormatter JOB_BIZ_NO_FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
private static final Random RANDOM = new Random();
/**
* 生成xxl-job任务业务流水号JOB + 当天yyMMddHHmmssSSS + 6位随机数字保证每次创建的JobDesc唯一
* 示例JOB260905102030123123456
* @return 业务流水号字符串
*/
private static String generateXxlJobBizNo() {
String dateTimeStr = LocalDateTime.now().format(JOB_BIZ_NO_FORMATTER);
int randomNum = RANDOM.nextInt(1_000_000);
String randomStr = String.format("%06d", randomNum);
return "JOB" + dateTimeStr + randomStr;
}
/**
* 修改合同管理
*/
@Transactional
public Boolean update(ContractManageDO contractManageDO) {
validateContractType(contractManageDO.getContractType());
checkContract(contractManageDO);
//checkContract(contractManageDO);
checkUniqueActiveContract(contractManageDO);
handleData(contractManageDO);
handleDetils(contractManageDO);
handleDetils(contractManageDO, false);
handleParameters(contractManageDO);
handleDict(contractManageDO);
return contractManageDomainService.update(contractManageDO);
}
@@ -859,6 +1085,8 @@ public class ContractManageApplicationService {
ContractManagePO result = contractManageDomainService.getInfo(contractManageId);
List<ContractManageDetailPO> contractManageDetailPOList = contractManageDetailDomainService.queryListByManageId(result.getContractManageId());
result.setContractManageDetailPOList(contractManageDetailPOList);
List<ContractManageParametersPO> paramsList = contractManageParametersDomainService.queryListByManageId(result.getContractManageId());
result.setContractManageParametersList(paramsList);
return result;
}
@@ -935,6 +1163,79 @@ public class ContractManageApplicationService {
return resultContract;
}
public ContractManagePO getInfoByCustomerAndSecondSubjectCode(String settlementCustomersCode,Integer contractType, Long topOrganizationId, Long organizationId,String firstSubjectCode) {
/*
首先根据合同类型仓储运输其他以及结算客户查询合同信息
如果传了结算主体则根据结算主体以及当前时间查询有效的特殊合同如果特殊合同没有则查询通用合同
*/
//获取当前登录人信息
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNull(loginUser) && topOrganizationId == null) {
throw new DigitalLogisticsException(UserError.TIMEOUT);
}
if(contractType==null){
throw new ServiceException("合同类型不能为空");
}
ContractManagePO resultContract = new ContractManagePO();
//查询当前日期在有效期内的合同
ContractManageDO queryParam = new ContractManageDO();
queryParam.setNowDateString(DateUtil.format(new Date(),"yyyy-MM-dd"));
queryParam.setFirstSubjectCode(firstSubjectCode);
queryParam.setOrganizationId(organizationId);
queryParam.setTopOrganizationId(topOrganizationId);
List<ContractManagePO> contractManagePOList = contractManageDomainService.queryList(queryParam);
List<ContractManagePO> contractManagePOs = contractManagePOList.stream()
.filter(item -> item.getSettlementCustomersCode().equals(settlementCustomersCode)
&& Objects.equals(item.getContractType(), contractType))
.collect(Collectors.toList());
if (contractManagePOs != null && contractManagePOs.size() > 1) {
resultContract.setIsMany("1");
return resultContract;
}
if(contractManagePOList != null && contractManagePOList.size()>0){
if(StringUtils.isNotEmpty(settlementCustomersCode)){
//根据结算对象,及合同的类型 查询对应合同信息
ContractManagePO contractManagePO = contractManagePOList.stream()
.filter(item -> item.getSettlementCustomersCode().equals(settlementCustomersCode) && Objects.equals(item.getContractType(), contractType)).findFirst().orElse(null);
if(null == contractManagePO){
resultContract = findGeneralContract(contractManagePOList, contractType);
}else {
resultContract = contractManagePO;
}
}else {
resultContract = findGeneralContract(contractManagePOList, contractType);
}
if(null == resultContract){
throw new ServiceException("找不到匹配的合同,请重试");
}
//得到合同后查询合同明细
List<ContractManageDetailPO> contractManageDetailPOList = contractManageDetailDomainService.queryListByManageId(resultContract.getContractManageId());
List<ContractManageDetailPO> contractManageDetailSaveList = new ArrayList<>();
if(contractManageDetailPOList != null && contractManageDetailPOList.size()>0){
//将临时合同中没有但是通用合同中有的数据过滤出使用 ObjectUtil.equal 避免 firstSubjectCode/secondSubjectCode null NPE
contractManageDetailSaveList = contractManageDetailPOList.stream().filter(item -> contractManageDetailPOList.stream().noneMatch(item1 -> ObjectUtil.equal(item1.getFirstSubjectCode(), item.getFirstSubjectCode()) && ObjectUtil.equal(item1.getSecondSubjectCode(), item.getSecondSubjectCode()) && item1.getSubjectType()==1)).collect(Collectors.toList());
//首先根据结算科目类型将临时合同过滤出
List<ContractManageDetailPO> tempContractManageDetailPOList = contractManageDetailPOList.stream().filter(item -> item.getSubjectType()==2).collect(Collectors.toList());
//遍历两个集合将相同费用科目code的数据进行比较如果结算科目类型是临时且合同有效期有效则使用该条数据将另一条移除
for (ContractManageDetailPO manageDetailPO : tempContractManageDetailPOList) {
for (ContractManageDetailPO contractManageDetailPO : contractManageDetailPOList) {
if(ObjectUtil.equal(contractManageDetailPO.getFirstSubjectCode(), manageDetailPO.getFirstSubjectCode()) && ObjectUtil.equal(contractManageDetailPO.getSecondSubjectCode(), manageDetailPO.getSecondSubjectCode())){
//判断如果是临时合同在有效期内,则将该条数据保存到集合contractManageDetailSaveList
DateTime start = DateUtil.parseDate(DateUtil.format(manageDetailPO.getSubjectEffectiveDate(),"yyyy-MM-dd"));
DateTime end = DateUtil.parseDateTime(DateUtil.format(manageDetailPO.getSubjectEffectiveDate(),"yyyy-MM-dd"));
DateTime now = DateUtil.beginOfDay(DateUtil.date());
if (now.isAfterOrEquals(start) && now.isBefore(end)) {
contractManageDetailSaveList.add(manageDetailPO);
}
}
}
}
}
resultContract.setContractManageDetailPOList(contractManageDetailSaveList);
}
return resultContract;
}
/**
* 根据结算主体获取合同信息
* @param settlementCustomersCode 结算主体code
@@ -1030,4 +1331,343 @@ public class ContractManageApplicationService {
public ContractManagePO getGeneralContract() {
return contractManageDomainService.getGeneralContract();
}
/**
* 合同导出合同头字段 + 明细拍平成一行一条明细
*/
public List<ContractManageExportVO> buildExportList(ContractManageDO contractManageDO) {
List<ContractManagePO> contractList = this.queryList(contractManageDO);
List<ContractManageExportVO> exportList = new ArrayList<>();
if (contractList == null || contractList.isEmpty()) {
return exportList;
}
List<Long> contractManageIds = contractList.stream()
.map(ContractManagePO::getContractManageId)
.collect(Collectors.toList());
Map<Long, List<ContractManageDetailPO>> detailMap = contractManageDetailDomainService
.queryListByManageIds(contractManageIds).stream()
.collect(Collectors.groupingBy(ContractManageDetailPO::getContractManageId));
for (ContractManagePO contract : contractList) {
List<ContractManageDetailPO> details = detailMap.get(contract.getContractManageId());
if (details != null && !details.isEmpty()) {
for (ContractManageDetailPO detail : details) {
ContractManageExportVO vo = new ContractManageExportVO();
// 合同头字段整体复制
BeanUtils.copyProperties(contract, vo);
// 明细字段显式赋值合同头/明细存在同名字段避免互相覆盖
vo.setSubjectType(detail.getSubjectType());
vo.setFirstSubjectCode(detail.getFirstSubjectCode());
vo.setFirstSubjectName(detail.getFirstSubjectName());
vo.setSecondSubjectCode(detail.getSecondSubjectCode());
vo.setSecondSubjectName(detail.getSecondSubjectName());
vo.setAccountingStrategy(detail.getAccountingStrategy());
vo.setBillingAttributes(detail.getBillingAttributes());
vo.setSubjectEffectiveDate(detail.getSubjectEffectiveDate());
vo.setSubjectExpirationDate(detail.getSubjectExpirationDate());
vo.setDocumentType(detail.getDocumentType());
vo.setServiceItemsName(detail.getServiceItemsName());
exportList.add(vo);
}
} else {
// 无明细的合同也保留一行头字段
ContractManageExportVO vo = new ContractManageExportVO();
BeanUtils.copyProperties(contract, vo);
exportList.add(vo);
}
}
return exportList;
}
/*
* 获取结算对象
* */
public SettlementCustomersPO getSettlementCustomers(Long shipperId) {
try {
Long topOrganizationId = null;
AjaxResult ajaxResult = bmsServiceFeign.getCustomersInfoBySettlementEntityId(shipperId, topOrganizationId);
if (ajaxResult == null || !"200".equals(String.valueOf(ajaxResult.get("code"))) || ajaxResult.get("data") == null) {
log.warn("按 settlementEntityId 查询结算对象未成功:shipperId={}, code={}", shipperId, ajaxResult != null ? ajaxResult.get("code") : null);
return null;
}
return JSON.parseObject(JSON.toJSONString(ajaxResult.get("data")), SettlementCustomersPO.class);
} catch (Exception e) {
log.warn("按 settlementEntityId 查询结算对象异常,shipperId={}", shipperId, e);
return null;
}
}
/*
* 根据结算对象id获取结算对象参数列表
* */
public List<SettlementCustomersParametersPO> getSettlementCustomersParameters(Long settlementCustomersId) {
try {
AjaxResult ajaxResult = bmsServiceFeign.getListBySettlementCustomersId(settlementCustomersId);
if (ajaxResult == null || !"200".equals(String.valueOf(ajaxResult.get("code"))) || ajaxResult.get("data") == null) {
log.warn("按 settlementCustomersId 查询结算对象参数未成功:settlementCustomersId={}, code={}", settlementCustomersId, ajaxResult != null ? ajaxResult.get("code") : null);
return null;
}
return JSON.parseArray(JSON.toJSONString(ajaxResult.get("data")), SettlementCustomersParametersPO.class);
} catch (Exception e) {
log.warn("按 settlementCustomersId 查询结算对象参数异常,settlementCustomersId={}", settlementCustomersId, e);
return null;
}
}
public void pushContractManageToBms(String shipperId) {
SettlementCustomersPO settlementCustomers = getSettlementCustomers(Long.valueOf(shipperId));
if (settlementCustomers == null) {
log.warn("pushContractManageToBms 未找到结算对象,shipperId={}", shipperId);
return;
}
Long settlementCustomersId = settlementCustomers.getSettlementCustomersId();
List<SettlementCustomersParametersPO> parametersList = getSettlementCustomersParameters(settlementCustomersId);
if (parametersList == null || parametersList.isEmpty()) {
log.warn("pushContractManageToBms 未找到结算对象参数,settlementCustomersId={}", settlementCustomersId);
return;
}
for (SettlementCustomersParametersPO param : parametersList) {
String parametersName = param.getParametersName();
String content = param.getContent();
if (StringUtils.isEmpty(content)) {
log.warn("结算对象参数 content 为空,parametersName={}, settlementCustomersId={}", parametersName, settlementCustomersId);
continue;
}
Map<String, Object> contentMap = JSON.parseObject(content, new TypeReference<Map<String, Object>>() {});
Integer sfzdcz = Integer.valueOf(contentMap.get("sfzdcz").toString());
if (sfzdcz != 1) {
log.info("结算对象参数 sfzdcz 不为1,跳过推送,parametersName={}, sfzdcz={}", parametersName, sfzdcz);
continue;
}
String warehouseTempLayerType;
String serviceItemsName;
Boolean isGc = false;
if ("冻仓计费配置".equals(parametersName)) {
warehouseTempLayerType = "DC";
serviceItemsName = "冻仓仓租费用";
} else if ("干仓计费配置".equals(parametersName)) {
warehouseTempLayerType = "GC";
serviceItemsName = "干仓仓租费用";
isGc=true;
} else {
log.warn("未知的结算对象参数类型,parametersName={}", parametersName);
continue;
}
List<ContractManage> contractManages = contractManageMapper.selectList(new LambdaQueryWrapper<ContractManage>()
.eq(ContractManage::getContractRentType, "NORMAL")
.eq(ContractManage::getContractState, 2)
.eq(ContractManage::getDelFlag, 1)
.eq(ContractManage::getSettlementCustomersId, settlementCustomersId)
.eq(ContractManage::getWarehouseTempLayerType, warehouseTempLayerType));
if (contractManages == null || contractManages.isEmpty()) {
log.warn("未找到正式合同,warehouseTempLayerType={}, settlementCustomersId={}", warehouseTempLayerType, settlementCustomersId);
continue;
}
for (ContractManage contractManage : contractManages) {
Long contractManageId = contractManage.getContractManageId();
ContractManageParameters contractManageParameters = contractManageParametersService.getOne(new LambdaQueryWrapper<ContractManageParameters>()
.eq(ContractManageParameters::getContractManageId, contractManageId), false);
if (contractManageParameters == null) {
continue;
}
String parametersJson = contractManageParameters.getParametersJson();
Map<String, Object> parametersMap = JSON.parseObject(parametersJson, new TypeReference<Map<String, Object>>() {});
BigDecimal hyj = (BigDecimal) parametersMap.get("hyj");
buildBusinessDocument(hyj, settlementCustomers, contractManage, "0D01", "租金(固定租)", warehouseTempLayerType, serviceItemsName);
}
}
}
private void buildBusinessDocument(BigDecimal fee, SettlementCustomersPO settlementCustomers, ContractManage contractManage, String code, String name, String warehouseType, String serviceItemsName) {
Long settlementCustomersId = settlementCustomers.getSettlementCustomersId();
Long settlementEntityId = settlementCustomers.getSettlementEntityId();
String settlementEntity = settlementCustomers.getSettlementEntity();
String settlementCustomersCode = settlementCustomers.getSettlementCustomersCode();
BusinessDocumentFeign businessDocumentFeign = new BusinessDocumentFeign();
businessDocumentFeign.setBillAmount(fee);
businessDocumentFeign.setOrganizationId(contractManage.getOrganizationId());
businessDocumentFeign.setOrganizationName(contractManage.getOrganizationName());
businessDocumentFeign.setTopOrganizationId(contractManage.getTopOrganizationId());
businessDocumentFeign.setBelongModuleCode("wms");
businessDocumentFeign.setBelongModule("WMS");
businessDocumentFeign.setDataSources(1);
businessDocumentFeign.setSettlementEntity(settlementEntity);
businessDocumentFeign.setSettlementCustomersId(settlementCustomersId);
businessDocumentFeign.setSettlementCustomersCode(settlementCustomersCode);
businessDocumentFeign.setDocumentTypeId(4l);
businessDocumentFeign.setDocumentTypeCode("CM_ZL");
businessDocumentFeign.setDocumentType("仓库租赁单");
businessDocumentFeign.setFirstSubjectCode(code);
businessDocumentFeign.setFirstSubjectName(name);
businessDocumentFeign.setBillingTime(new Date());
businessDocumentFeign.setServiceItemsCode("GC_CZ");
businessDocumentFeign.setServiceItemsName(serviceItemsName);
businessDocumentFeign.setSettlementWay(1);
businessDocumentFeign.setOriginalBusinessNum(contractManage.getContractNumber());
businessDocumentFeign.setWarehouseType(warehouseType);
String contractName = contractManage.getContractName();
String contractNumber = contractManage.getContractNumber();
Long contractManageId = contractManage.getContractManageId();
businessDocumentFeign.setContractName(contractName);
businessDocumentFeign.setContractNumber(contractNumber);
businessDocumentFeign.setContractManageId(contractManageId);
businessDocumentFeign.setBusinessFlow(OrderSequence.getOrderCode("LS"));
businessDocumentFeign.setIsPush(1);
AjaxResult ajaxResult = bmsServiceFeign.feignSaveBusinessDocument(businessDocumentFeign);
if (ajaxResult == null || !"200".equals(String.valueOf(ajaxResult.get("code")))) {
log.error("保存业务单据失败: {}", ajaxResult != null ? ajaxResult.get("msg") : "feign调用异常");
}
}
private static final String WEBSERVICE_URL = "http://10.33.0.116:8080/sys/webservice/ngLegalByFindWebserviceService";
public List<com.alibaba.fastjson.JSONObject> getContractNosByCompanyName(String companyName, int pageNum, int pageSize) {
List<com.alibaba.fastjson.JSONObject> contractList = new ArrayList<>();
try {
log.info("=== 开始查询合同列表 ===");
log.info("查询公司: {}, 页码: {}, 每页数量: {}", companyName, pageNum, pageSize);
String httpRequest = buildXmlRequest(companyName, pageNum, pageSize);
log.info("XML请求: {}", httpRequest);
log.info("XML请求生成完成,长度: {} 字符", httpRequest.length());
log.info("正在调用WebService...");
String httpResponse = HttpWebServiceUtil.callWebService(httpRequest, WEBSERVICE_URL);
String jsonData = extractJsonFromResponse(httpResponse);
log.info("正在解析JSON..."+jsonData);
if (jsonData == null || jsonData.trim().isEmpty()) {
log.warn("未提取到JSON数据,返回空列表");
return contractList;
}
log.info("提取到JSON数据,长度: {} 字符", jsonData.length());
List<com.alibaba.fastjson.JSONObject> result = parseContractListFromJson(jsonData);
contractList.addAll(result);
log.info("=== 查询完成 ===");
log.info("找到 {} 个合同", contractList.size());
} catch (Exception e) {
log.error("查询合同列表失败", e);
throw new RuntimeException("查询合同列表失败: " + e.getMessage(), e);
}
return contractList;
}
/**
* 构建XML请求 - 动态分页
*/
private String buildXmlRequest(String companyName, int pageNum, int pageSize) {
String jsonParam = "{\"fdName\":\"" + companyName + "\"}";
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"" +
" xmlns:web=\"http://webservice.legal.ng.kmss.landray.com/\">" +
"<soapenv:Body>" +
"<web:findNgLegal>" +
"<arg0 xmlns=\"\">" +
"<fdPageNo>" + pageNum + "</fdPageNo>" +
"<fdRowSize>" + pageSize + "</fdRowSize>" +
"<fdRelativePerson><![CDATA[" + jsonParam + "]]></fdRelativePerson>" +
"<fdContractNo></fdContractNo>" +
"<fdPersonNo>NA0301</fdPersonNo>" +
"<fdSponsor></fdSponsor>" +
"<docCreateTimeStar></docCreateTimeStar>" +
"<docCreateTimeEnd></docCreateTimeEnd>" +
"</arg0>" +
"</web:findNgLegal>" +
"</soapenv:Body>" +
"</soapenv:Envelope>";
}
/**
* 从SOAP响应中提取JSON
*/
private String extractJsonFromResponse(String soapResponse) {
if (soapResponse == null || soapResponse.isEmpty()) {
return null;
}
// 直接查找JSON部分
int jsonStart = soapResponse.indexOf("{\"returnState\":");
int jsonEnd = soapResponse.indexOf("}</return>");
if (jsonStart != -1 && jsonEnd != -1) {
// 找到JSON结束位置
jsonEnd = jsonEnd + 1; // 包含右大括号
String json = soapResponse.substring(jsonStart, jsonEnd);
log.info("直接提取JSON成功");
return json;
}
// 备用方法查找<return>标签
int start = soapResponse.indexOf("<return>");
int end = soapResponse.indexOf("</return>");
if (start != -1 && end != -1) {
start += "<return>".length();
String json = soapResponse.substring(start, end);
// 解码XML实体
json = json.replace("&lt;", "<")
.replace("&gt;", ">")
.replace("&amp;", "&")
.replace("&quot;", "\"")
.replace("&apos;", "'");
log.info("从<return>标签提取JSON成功");
return json.trim();
}
log.warn("无法从响应中提取JSON");
return null;
}
/**
* 解析JSON获取完整合同列表
*/
private List<com.alibaba.fastjson.JSONObject> parseContractListFromJson(String jsonData) {
List<com.alibaba.fastjson.JSONObject> contractList = new ArrayList<>();
try {
com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(jsonData);
String returnState = jsonObject.getString("returnState");
if (!"2".equals(returnState)) {
log.warn("返回状态异常: {}", returnState);
return contractList;
}
JSONArray dataArray = jsonObject.getJSONArray("data");
if (dataArray == null || dataArray.isEmpty()) {
log.info("查询成功,但未找到合同数据");
return contractList;
}
log.info("找到 {} 个合同", dataArray.size());
for (int i = 0; i < dataArray.size(); i++) {
com.alibaba.fastjson.JSONObject contract = dataArray.getJSONObject(i);
contractList.add(contract);
}
} catch (Exception e) {
log.error("JSON解析失败", e);
log.error("原始JSON: {}", jsonData);
}
return contractList;
}
}
@@ -0,0 +1,72 @@
package com.mhd.basic.application.service.contractManageParameters;
import com.mhd.basic.domain.contractManageParameters.repository.po.ContractManageParametersPO;
import com.mhd.basic.domain.contractManageParameters.repository.todo.ContractManageParametersDO;
import com.mhd.basic.domain.contractManageParameters.service.ContractManageParametersDomainService;
import com.mhd.common.security.utils.SecurityUtils;
import com.mhd.system.api.model.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 合约信息规则维护表ApplicationService
*
* @author gen
* @date 2024-06-07
*/
@Service
@Slf4j
public class ContractManageParametersApplicationService {
@Autowired
private ContractManageParametersDomainService contractManageParametersDomainService;
/**
* 分页查询合约信息规则维护表列表
*/
public List<ContractManageParametersPO> queryList(ContractManageParametersDO contractManageParametersDO) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null){
Long topOrganizationId = loginUser.getUserPo().getTopOrganizationId();
if (topOrganizationId != null && topOrganizationId != 1){
contractManageParametersDO.setTopOrganizationId(loginUser.getUserPo().getTopOrganizationId());
}
}
return contractManageParametersDomainService.queryList(contractManageParametersDO);
}
/**
* 新增合约信息规则维护表
*/
public Boolean insert(ContractManageParametersDO contractManageParametersDO) {
return contractManageParametersDomainService.insert(contractManageParametersDO);
}
/**
* 修改合约信息规则维护表
*/
public Boolean update(ContractManageParametersDO contractManageParametersDO) {
return contractManageParametersDomainService.update(contractManageParametersDO);
}
/**
* 批量删除合约信息规则维护表
*/
public boolean delete(Long[] ids) {
return contractManageParametersDomainService.delete(ids);
}
/**
* 获取合约信息规则维护表详细信息
*/
public ContractManageParametersPO getInfo(Long id)
{
return contractManageParametersDomainService.getInfo(id);
}
}
@@ -13,6 +13,7 @@ import com.mhd.basic.application.service.contractManage.ContractManageApplicatio
import com.mhd.basic.domain.expenseAccount.service.ExpenseAccountDomainService;
import com.mhd.basic.infrastructure.feign.vo.SysDictDataVo;
import com.mhd.basic.interfaces.dto.expenseAccount.ExpenseAccountDTO;
import com.mhd.basic.interfaces.dto.expenseAccount.ExpenseAccountExportVO;
import com.mhd.basic.interfaces.dto.expenseAccount.SearchExpenseAccountDTO;
import com.mhd.common.core.enums.DictCode;
import com.mhd.common.core.exception.ServiceException;
@@ -27,14 +28,11 @@ import com.mhd.system.api.SystemServiceFeign;
import com.mhd.system.api.model.LoginUser;
import com.mhd.common.core.domain.po.UserPo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -382,6 +380,55 @@ public class ExpenseAccountApplicationService {
return expenseAccountDomainService.getInfo(expenseAccountId);
}
/**
* 复制费用科目-获取原科目数据供前端回显
* <p>前端拿到数据后回显到新增弹窗用户填写新科目编码后通过 /edit 接口id 为空走新增提交保存
* 清空科目编码是为了避免直接复制出重复编码费用科目编码无唯一性校验</p>
*/
public ExpenseAccountPO copy(ExpenseAccountDTO expenseAccountDTO) {
if (expenseAccountDTO == null || expenseAccountDTO.getExpenseAccountId() == null) {
throw new ServiceException("原费用科目id不能为空");
}
// 获取原费用科目信息
ExpenseAccountPO original = expenseAccountDomainService.getInfo(expenseAccountDTO.getExpenseAccountId());
if (null == original) {
throw new ServiceException("原费用科目信息未找到");
}
// 清空主键前端提交时走新增
original.setExpenseAccountId(null);
// 清空科目编码强制用户输入新编码避免编码重复
original.setSubjectCode(null);
// 清空审计字段新增时由 ExpenseAccountAssembler 重新生成
original.setCreateBy(null);
original.setCreateByName(null);
original.setCreateTime(null);
original.setUpdateBy(null);
original.setUpdateByName(null);
original.setUpdateTime(null);
original.setDelFlag(null);
// 清空非表字段
original.setUnit(null);
original.setExpenseAccountPOList(null);
return original;
}
/**
* 构建费用科目导出数据不分页全量按列表页查询条件 + 数据权限过滤
*/
public List<ExpenseAccountExportVO> buildExportList(ExpenseAccountDO expenseAccountDO) {
List<ExpenseAccountExportVO> exportList = new ArrayList<>();
List<ExpenseAccountPO> list = this.queryList(expenseAccountDO);
if (list == null || list.isEmpty()) {
return exportList;
}
for (ExpenseAccountPO po : list) {
ExpenseAccountExportVO vo = new ExpenseAccountExportVO();
BeanUtils.copyProperties(po, vo);
exportList.add(vo);
}
return exportList;
}
/**
* 修改状态
* @param expenseAccountDTO
@@ -580,6 +627,46 @@ public class ExpenseAccountApplicationService {
return expenseAccountDomainService.getInfoByCode2(subjectCode,topOrganizationId);
}
/**
* 根据编码和组织ID查询
*/
public ExpenseAccountPO getInfoByOrgAndCode(String subjectCode, Long organizationId) {
if(!StringUtils.isNotEmpty(subjectCode)){
throw new ServiceException("费用科目编码不能为空");
}
if(organizationId == null){
throw new ServiceException("组织ID不能为空");
}
ExpenseAccountPO expenseAccountPO = expenseAccountDomainService.getInfoByOrgAndCode(subjectCode, organizationId);
// // 组装计费单位列表单位-单位英文
// List<String> unit = new ArrayList<>();
// if (expenseAccountPO != null) {
// unit.add(expenseAccountPO.getBillingUnit() + "-" + expenseAccountPO.getBillingUnitEn());
// unit.add(expenseAccountPO.getBillingUnit2() + "-" + expenseAccountPO.getBillingUnitEn2());
// expenseAccountPO.setUnit(unit);
// }
// 组装计费单位列表(数组)中文和英文都为null时过滤掉避免出现"null-null"
List<Map<String, String>> unit = new ArrayList<>();
if (expenseAccountPO != null) {
addUnitIfPresent(unit, expenseAccountPO.getBillingUnit(), expenseAccountPO.getBillingUnitEn());
addUnitIfPresent(unit, expenseAccountPO.getBillingUnit2(), expenseAccountPO.getBillingUnitEn2());
expenseAccountPO.setUnit(unit);
}
return expenseAccountPO;
}
/**
* 组装计费单位中文和英文都为null时不加入列表
*/
private void addUnitIfPresent(List<Map<String, String>> unit, String billingUnit, String billingUnitEn) {
if (billingUnit == null && billingUnitEn == null) {
return;
}
Map<String, String> unitMap = new HashMap<>();
unitMap.put("unit", billingUnit + "-" + billingUnitEn);
unit.add(unitMap);
}
public List<QueryExpenseAccountPO> selectExpenseAccount(SearchExpenseAccountDO searchExpenseAccountDO){
setDataPermissionForSearch(searchExpenseAccountDO);
return expenseAccountDomainService.selectExpenseAccount(searchExpenseAccountDO);
@@ -157,15 +157,18 @@ public class MaterialBaseInfoApplicationService {
* @param materialBaseInfoDO
*/
private void shipperParam(MaterialBaseInfoDO materialBaseInfoDO){
AjaxResult ajaxResult = userServiceFeign.getInfo(materialBaseInfoDO.getShipperId());
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
throw new ServiceException("获取货主信息失败");
}
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
// 如果原始shipperName不为空保留原始值导入或手动输入时应该保留完整名称
// 只有在原始shipperName为空时才使用查询到的userName
if (materialBaseInfoDO.getShipperName() == null || materialBaseInfoDO.getShipperName().trim().isEmpty()) {
materialBaseInfoDO.setShipperName(userPo.getUserName());
Long shipperId = materialBaseInfoDO.getShipperId();
if (shipperId != null && shipperId != 0l) {
AjaxResult ajaxResult = userServiceFeign.getInfo(materialBaseInfoDO.getShipperId());
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
throw new ServiceException("获取货主信息失败");
}
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
// 如果原始shipperName不为空保留原始值导入或手动输入时应该保留完整名称
// 只有在原始shipperName为空时才使用查询到的userName
if (materialBaseInfoDO.getShipperName() == null || materialBaseInfoDO.getShipperName().trim().isEmpty()) {
materialBaseInfoDO.setShipperName(userPo.getUserName());
}
}
}
@@ -182,4 +185,4 @@ public class MaterialBaseInfoApplicationService {
//return materialBaseInfoDomainService.getMaterialStockList(shipperName,materialName,machineCode,topOrganizationId,pageNum,pageSize);/**/
return null;
}
}
}
@@ -6,6 +6,7 @@ import com.alibaba.fastjson.JSON;
import com.mhd.basic.domain.storageLocation.repository.po.StorageLocationPO;
import com.mhd.basic.domain.storageLocation.repository.todo.StorageLocationDO;
import com.mhd.basic.domain.storageLocation.service.StorageLocationDomainService;
import com.mhd.basic.interfaces.dto.storageLocation.StorageLocationDTO;
import com.mhd.basic.domain.storageSection.repository.todo.StorageSectionDO;
import com.mhd.basic.infrastructure.feign.vo.SysDictDataVo;
import com.mhd.common.core.domain.po.UserPo;
@@ -207,6 +208,39 @@ public class StorageLocationApplicationService {
return storageLocationDomainService.getInfo(storageLocationId);
}
/**
* 复制库位-获取原库位数据供前端回显
* 前端拿到数据后跳转到新增库位页面用户修改编码后通过edit接口提交新增
*/
public StorageLocationPO copyStorageLocation(StorageLocationDTO storageLocationDTO) {
if (storageLocationDTO.getStorageLocationId() == null) {
throw new ServiceException("原库位id不能为空");
}
// 获取原库位信息
StorageLocationPO originalStorageLocation = storageLocationDomainService.getInfo(storageLocationDTO.getStorageLocationId());
if (null == originalStorageLocation) {
throw new ServiceException("原库位信息未找到");
}
// 清空唯一性字段库位id不清空会导致提交后走修改分支覆盖原库位
// 库位编码同组织同仓库唯一须由用户重新填写条码为物理唯一标识一并清空
originalStorageLocation.setStorageLocationId(null);
originalStorageLocation.setStorageLocationCode(null);
originalStorageLocation.setLocationBarCode(null);
// 状态重置为初始值新库位无库存()启用未作废
originalStorageLocation.setStatus(1);
originalStorageLocation.setOpeningUp(1);
originalStorageLocation.setNullify(1);
// 清空审计字段提交新增时由Assembler按当前登录人重新生成
originalStorageLocation.setCreateBy(null);
originalStorageLocation.setCreateByName(null);
originalStorageLocation.setCreateTime(null);
originalStorageLocation.setUpdateBy(null);
originalStorageLocation.setUpdateByName(null);
originalStorageLocation.setUpdateTime(null);
// 其余业务字段(仓库/库区/库位组分类/种类/混放策略限制长宽高坐标备注)保留回显
return originalStorageLocation;
}
public int getStorageLocationCount(StorageLocationDO storageLocationDO)
{
return storageLocationDomainService.getStorageLocationCount(storageLocationDO);
@@ -21,6 +21,7 @@ import com.mhd.system.service.ISysDictTypeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
/**
* 库区ApplicationService
@@ -42,11 +43,32 @@ public class StorageSectionApplicationService {
*/
public List<StorageSectionPO> queryList(StorageSectionDO storageSectionDO) {
//设置查询数据权限
applyQueryDataPermission(storageSectionDO);
return storageSectionDomainService.queryList(storageSectionDO);
}
/**
* 库区面积合计 /list 相同的数据权限和筛选条件SQL 直接 SUM(库区面积)
* 保证合计数与列表中各行库区面积之和一致
*/
public BigDecimal sumStorageRegion(StorageSectionDO storageSectionDO) {
// /list 共用同一数据权限保证合计与列表口径一致
applyQueryDataPermission(storageSectionDO);
return storageSectionDomainService.sumStorageRegion(storageSectionDO);
}
/**
* @description 设置查询数据权限queryList sumStorageRegion 共用
* @author ZhouGY
* @param storageSectionDO
*/
private void applyQueryDataPermission(StorageSectionDO storageSectionDO) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null && loginUser.getUserPo() != null) {
Long userOrganizationId = loginUser.getUserPo().getOrganizationId();
Long frontendOrganizationId = storageSectionDO.getOrganizationId(); // 前端传递的 organizationId
// 数据权限根据 organizationId 来设置查询权限
// 当前登录用户的 organizationId 2827 可查全部组织数据其他组织只能查自己
if (userOrganizationId != null && userOrganizationId == 2827L) {
@@ -91,7 +113,6 @@ public class StorageSectionApplicationService {
}
}
}
return storageSectionDomainService.queryList(storageSectionDO);
}
@@ -23,6 +23,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import com.mhd.common.core.utils.StringUtils;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -98,6 +99,13 @@ public class WarehouseApplicationService {
}
}
}
String orgIds = warehouseDO.getOrgIds();
if (StringUtils.isNotEmpty(orgIds)) {
String[] orgIdArray = orgIds.split(",");
List<Long> orgIdList = Arrays.stream(orgIdArray).map(Long::valueOf).collect(Collectors.toList());
warehouseDO.setOrgIdList(orgIdList);
warehouseDO.setOrganizationId(null);
}
return warehouseDomainService.queryList(warehouseDO);
}
@@ -314,4 +322,4 @@ public class WarehouseApplicationService {
return warehouseDomainService.getWarehouseChildren(warehouseId, storageLocationType);
}
}
}
@@ -126,6 +126,18 @@ public class ContractManage extends BaseVOEntity{
@Excel(name = "其他附件地址")
private String otherAttachmentsUrl;
@ApiModelProperty("合同正本附件原始文件名")
private String contractOriginalName;
@ApiModelProperty("廉政协议附件原始文件名")
private String integrityAgreementName;
@ApiModelProperty("安全协议附件原始文件名")
private String securityProtocolName;
@ApiModelProperty("其他附件原始文件名(多文件时与 otherAttachmentsUrl 同分隔符、同顺序)")
private String otherAttachmentsName;
@ApiModelProperty("我司签订人")
@Excel(name = "我司签订人")
private String ourSinged;
@@ -180,4 +192,30 @@ public class ContractManage extends BaseVOEntity{
@ApiModelProperty(name = "是否包含运输费用(1-包含,2-包含)")
private Integer transportationCosts;
@ApiModelProperty("合同租赁类型")
private String contractRentType;
@ApiModelProperty("合同租赁类型")
private String contractRentTypeName;
@ApiModelProperty("仓库温层类型")
private String warehouseTempLayerType;
@ApiModelProperty("仓库温层类型")
private String warehouseTempLayerTypeName;
@ApiModelProperty("续期提前天数")
private Integer renewalAdvanceDays;
@ApiModelProperty("标的物")
private String subjectMatter;
@ApiModelProperty("性质")
private String nature;
@ApiModelProperty("合同最初起始日")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "合同最初起始日", width = 30, dateFormat = "yyyy-MM-dd")
private Date initialStartDate;
}
@@ -23,7 +23,7 @@ public interface IContractManageService extends IService<ContractManage>
/**
* 新增合同管理
*/
public Boolean insert(ContractManageDO contractManageDO);
public Long insert(ContractManageDO contractManageDO);
/**
* 修改合同管理
@@ -37,10 +37,11 @@ public class ContractManageImpl extends ServiceImpl<ContractManageMapper, Contra
* 新增合同管理
*/
@Override
public Boolean insert(ContractManageDO contractManageDO) {
public Long insert(ContractManageDO contractManageDO) {
ContractManage contractManage = new ContractManage();
BeanUtils.copyProperties(contractManageDO,contractManage);
return this.save(contractManage);
this.save(contractManage);
return contractManage.getContractManageId();
}
/**
@@ -1,6 +1,7 @@
package com.mhd.basic.domain.contractManage.repository.po;
import com.mhd.basic.domain.contractManageDetail.repository.po.ContractManageDetailPO;
import com.mhd.basic.domain.contractManageParameters.repository.po.ContractManageParametersPO;
import com.mhd.basic.interfaces.dto.contractManageDetail.ContractManageDetailDTO;
import com.mhd.common.core.annotation.Excel;
import lombok.Data;
@@ -124,6 +125,18 @@ public class ContractManagePO extends BaseVOEntity{
@Excel(name = "其他附件地址")
private String otherAttachmentsUrl;
@ApiModelProperty("合同正本附件原始文件名")
private String contractOriginalName;
@ApiModelProperty("廉政协议附件原始文件名")
private String integrityAgreementName;
@ApiModelProperty("安全协议附件原始文件名")
private String securityProtocolName;
@ApiModelProperty("其他附件原始文件名(多文件时与 otherAttachmentsUrl 同分隔符、同顺序)")
private String otherAttachmentsName;
@ApiModelProperty("我司签订人")
@Excel(name = "我司签订人")
private String ourSinged;
@@ -184,4 +197,34 @@ public class ContractManagePO extends BaseVOEntity{
@ApiModelProperty(name = "是否包含运输费用(1-包含,2-包含)")
private Integer transportationCosts;
@ApiModelProperty("客户类型")
private String contractRentType;
@ApiModelProperty("客户类型编码")
private String contractRentTypeName;
@ApiModelProperty("仓库温层类型")
private String warehouseTempLayerType;
@ApiModelProperty("仓库温层类型编码")
private String warehouseTempLayerTypeName;
private String isMany;
@ApiModelProperty("合约信息规则维护列表")
private List<ContractManageParametersPO> contractManageParametersList;
@ApiModelProperty("续期提前天数")
private Integer renewalAdvanceDays;
@ApiModelProperty("标的物")
private String subjectMatter;
@ApiModelProperty("性质")
private String nature;
@ApiModelProperty("合同最初起始日")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "合同最初起始日", width = 30, dateFormat = "yyyy-MM-dd")
private Date initialStartDate;
}
@@ -121,6 +121,18 @@ public class ContractManageDO extends BaseVOEntity{
@Excel(name = "其他附件地址")
private String otherAttachmentsUrl;
@ApiModelProperty("合同正本附件原始文件名")
private String contractOriginalName;
@ApiModelProperty("廉政协议附件原始文件名")
private String integrityAgreementName;
@ApiModelProperty("安全协议附件原始文件名")
private String securityProtocolName;
@ApiModelProperty("其他附件原始文件名(多文件时与 otherAttachmentsUrl 同分隔符、同顺序)")
private String otherAttachmentsName;
@ApiModelProperty("我司签订人")
@Excel(name = "我司签订人")
private String ourSinged;
@@ -214,4 +226,34 @@ public class ContractManageDO extends BaseVOEntity{
@ApiModelProperty(name = "是否包含运输费用(1-包含,2-包含)")
private Integer transportationCosts;
@ApiModelProperty("客户类型")
private String contractRentType;
@ApiModelProperty("客户类型编码")
private String contractRentTypeName;
@ApiModelProperty("仓库温层类型")
private String warehouseTempLayerType;
@ApiModelProperty("仓库温层类型编码")
private String warehouseTempLayerTypeName;
@ApiModelProperty("一级费用科目code")
private String firstSubjectCode;
@ApiModelProperty("合约信息规则维护JSON")
private String parametersJson;
@ApiModelProperty("续期提前天数")
private Integer renewalAdvanceDays;
@ApiModelProperty("标的物")
private String subjectMatter;
@ApiModelProperty("性质")
private String nature;
@ApiModelProperty("合同最初起始日")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date initialStartDate;
}
@@ -0,0 +1,96 @@
package com.mhd.basic.domain.contractManage.repository.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.zip.GZIPInputStream;
@Slf4j
@Component
public class HttpWebServiceUtil {
/**
* 调用HTTP WebService
*/
public static String callWebService(String requestBody, String endpointUrl) {
try {
// 创建RestTemplate
RestTemplate restTemplate = new RestTemplate();
// 设置请求头
HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.TEXT_XML);
// headers.setAccept(Collections.singletonList(MediaType.TEXT_XML));
headers.setContentType(MediaType.parseMediaType("text/xml; charset=UTF-8")); // 核心修复
headers.setAccept(Collections.singletonList(MediaType.ALL));
headers.set("SOAPAction", "");
headers.set("User-Agent", "PostmanRuntime/7.26.10");
headers.set("Cache-Control", "no-cache");
headers.set("Accept-Encoding", "gzip, deflate");
headers.set("Connection", "keep-alive");
// 创建请求实体
HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
log.info("发送请求到: {}", endpointUrl);
// 发送请求
ResponseEntity<byte[]> response = restTemplate.exchange(
endpointUrl,
HttpMethod.POST,
entity,
byte[].class
);
log.info("响应状态: {}", response.getStatusCode());
// 处理响应
byte[] rawResponse = response.getBody();
if (rawResponse == null) {
return "";
}
// 检查是否gzip压缩
String contentEncoding = response.getHeaders().getFirst("Content-Encoding");
String responseBody;
if ("gzip".equalsIgnoreCase(contentEncoding)) {
responseBody = decompressGzip(rawResponse);
log.info("已解压gzip响应,长度: {} 字符", responseBody.length());
} else {
responseBody = new String(rawResponse, StandardCharsets.UTF_8);
log.info("响应长度: {} 字符", responseBody.length());
}
return responseBody;
} catch (Exception e) {
log.error("WebService调用失败", e);
throw new RuntimeException("WebService调用失败: " + e.getMessage(), e);
}
}
/**
* 解压缩GZIP内容
*/
private static String decompressGzip(byte[] compressedData) throws IOException {
try (GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(compressedData));
InputStreamReader reader = new InputStreamReader(gis, StandardCharsets.UTF_8)) {
StringBuilder sb = new StringBuilder();
char[] buffer = new char[1024];
int len;
while ((len = reader.read(buffer)) != -1) {
sb.append(buffer, 0, len);
}
return sb.toString();
}
}
}
@@ -0,0 +1,20 @@
package com.mhd.basic.domain.contractManage.repository.util;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class XxlJobBusinessConfig {
@Value("${xxl.job.admin.address}")
private String adminAddress;
@Value("${xxl.job.admin.cookie}")
private String adminCookie;
@Bean
public XxlJobOpenApiUtil xxlJobOpenApiUtil() {
return new XxlJobOpenApiUtil(adminAddress, adminCookie);
}
}
@@ -0,0 +1,218 @@
package com.mhd.basic.domain.contractManage.repository.util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.Map;
/**
* 调用XXLJOB后台页面接口
* 列表接口返回JSON不再返回HTML
*/
@Slf4j
public class XxlJobOpenApiUtil {
private final String adminUrl;
private final String cookie;
public XxlJobOpenApiUtil(String adminUrl, String cookie) {
this.adminUrl = StrUtil.removeSuffix(adminUrl, "/");
this.cookie = cookie;
}
/**
* 新增定时任务 POST /jobinfo/add
* @param addReq 请求实体与浏览器payload字段完全对齐
* @return true=新增成功false=失败
*/
public boolean addJob(JobInfoAddReq addReq) {
String url = adminUrl + "/jobinfo/add";
try {
Map<String, Object> formMap = BeanUtil.beanToMap(addReq);
HttpResponse response = HttpRequest.post(url)
.header("Cookie", cookie)
.form(formMap)
.execute();
int status = response.getStatus();
log.info("[XxlJob] addJob status:{}", status);
// 新增成功200重定向到列表页
return status == 200;
} catch (Exception e) {
log.error("[XxlJob] addJob异常", e);
return false;
}
}
/**
* 根据任务描述+执行器参数查询jobId
* 适配返回JSON格式的pageList接口
* @param jobDesc 任务描述
* @param executorParam 任务参数(业务shipperId)
* @return jobId查不到返回null
*/
public Integer queryJobIdByDescAndParam(String jobDesc, String executorParam,String jobGroup) {
StringBuilder querySb = new StringBuilder();
// start length必须
querySb.append("start=0&length=10");
// jobGroup为空就不拼接这个参数不要 jobGroup=""
// 你们业务固定jobGroup=3直接写死3不用传空
if(StrUtil.isNotBlank(jobGroup)){
querySb.append("&jobGroup=").append(jobGroup);
}
// jobDesc
if(StrUtil.isNotBlank(jobDesc)){
querySb.append("&jobDesc=").append(cn.hutool.core.net.URLEncodeUtil.encode(jobDesc));
}
// executorParam
if(StrUtil.isNotBlank(executorParam)){
querySb.append("&executorParam=").append(cn.hutool.core.net.URLEncodeUtil.encode(executorParam));
}
// executorHandler为空直接不携带
// triggerStatus=-1
querySb.append("&triggerStatus=-1");
String url = adminUrl + "/jobinfo/pageList?" + querySb;
log.info("[XxlJob] pageList请求url:{}",url);
try {
HttpResponse response = HttpRequest.get(url)
.header("Authorization", cookie)
.execute();
String jsonStr = response.body();
log.info("[XxlJob] pageList响应:{}",jsonStr);
if (StrUtil.isBlank(jsonStr)) {
log.warn("[XxlJob] pageList返回空响应");
return null;
}
JSONObject jsonObj = JSON.parseObject(jsonStr);
JSONArray jsonArray = jsonObj.getJSONArray("data");
if(jsonArray == null){
return null;
}
List<JobPageItem> dataList = jsonArray.toList(JobPageItem.class);
if (dataList == null || dataList.isEmpty()) {
return null;
}
for (JobPageItem item : dataList) {
if (StrUtil.equals(item.jobDesc, jobDesc) && StrUtil.equals(item.executorParam, executorParam)) {
return item.id;
}
}
return null;
} catch (Exception e) {
log.error("[XxlJob] queryJobId异常", e);
return null;
}
}
/**
* 暂停任务 POST /jobinfo/pause
* @param jobId xxl任务id
* @return true成功
*/
public boolean pauseJob(Integer jobId) {
if (jobId == null) {
return false;
}
String url = adminUrl + "/jobinfo/pause";
try {
HttpResponse response = HttpRequest.post(url)
.header("Cookie", cookie)
.form("id", jobId)
.execute();
return response.getStatus() == 200;
} catch (Exception e) {
log.error("[XxlJob] pauseJob jobId:{}异常", jobId, e);
return false;
}
}
/**
* 开启任务 POST /jobinfo/start
* @param jobId xxl任务id
* @return true成功
*/
public boolean startJob(Integer jobId) {
if (jobId == null) {
return false;
}
String url = adminUrl + "/jobinfo/start";
try {
HttpResponse response = HttpRequest.post(url)
.header("Cookie", cookie)
.form("id", jobId)
.execute();
return response.getStatus() == 200;
} catch (Exception e) {
log.error("[XxlJob] startJob jobId:{}异常", jobId, e);
return false;
}
}
/**
* 删除任务 POST /jobinfo/remove
* @param jobId xxl任务id
* @return true成功
*/
public boolean removeJob(Integer jobId) {
if (jobId == null) {
return false;
}
String url = adminUrl + "/jobinfo/remove";
try {
HttpResponse response = HttpRequest.post(url)
.header("Cookie", cookie)
.form("id", jobId)
.execute();
return response.getStatus() == 200;
} catch (Exception e) {
log.error("[XxlJob] removeJob jobId:{}异常", jobId, e);
return false;
}
}
/**
* pageList 返回data数组中每一项实体
*/
@Data
public static class JobPageItem {
private Integer id;
private String jobDesc;
private String executorParam;
}
/**
* add接口请求实体与浏览器F12抓包payload字段一一对应
*/
@Data
public static class JobInfoAddReq {
private Integer jobGroup;
private String jobDesc;
private String author;
private String alarmEmail;
private String scheduleType;
private String scheduleConf;
private String glueType;
private String executorHandler;
private String executorParam;
private String glueRemark;
private String glueSource;
private String executorRouteStrategy;
private Integer childJobId;
private String misfireStrategy;
private String executorBlockStrategy;
private Integer executorTimeout;
private Integer executorFailRetryCount;
}
}
@@ -23,10 +23,7 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -60,8 +57,9 @@ public class ContractManageDomainService {
* 新增合同管理
*/
public Boolean insert(ContractManageDO contractManageDO) {
return contractManageService.insert(contractManageDO);
Long contractManageId = contractManageService.insert(contractManageDO);
contractManageDO.setContractManageId(contractManageId);
return true;
}
/**
@@ -148,6 +146,7 @@ public class ContractManageDomainService {
LambdaQueryWrapper<ContractManage> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ContractManage::getOriginalContractNumber,contractNumber);
queryWrapper.eq(ContractManage::getDelFlag,1);
queryWrapper.last("LIMIT 1");
ContractManage contractManage = contractManageService.getOne(queryWrapper);
if(null != contractManage){
BeanUtils.copyProperties(contractManage,contractManagePO);
@@ -191,6 +190,22 @@ public class ContractManageDomainService {
}
/**
* 同结算客户+同温层+同租赁类型+使用中 的合同数量用于唯一性校验
*/
public long countByUniqueKey(Long settlementCustomersId, String warehouseTempLayerType, String contractRentType, Long excludeId) {
LambdaQueryWrapper<ContractManage> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(ContractManage::getSettlementCustomersId, settlementCustomersId);
wrapper.eq(ContractManage::getWarehouseTempLayerType, warehouseTempLayerType);
wrapper.eq(ContractManage::getContractRentType, contractRentType);
wrapper.eq(ContractManage::getContractState, 2);
wrapper.eq(ContractManage::getDelFlag, 1);
if (excludeId != null) {
wrapper.ne(ContractManage::getContractManageId, excludeId);
}
return contractManageService.count(wrapper);
}
public ContractManagePO getGeneralContract() {
ContractManagePO contractManagePO = new ContractManagePO();
LambdaQueryWrapper<ContractManage> queryWrapper = new LambdaQueryWrapper<>();
@@ -226,4 +241,6 @@ public class ContractManageDomainService {
}
return contractManagePO;
}
}
@@ -98,4 +98,10 @@ public class ContractManageDetail extends BaseVOEntity{
@ApiModelProperty("单据类型")
private String documentType;
@ApiModelProperty("费用类别编码")
private String serviceItemsCode;
@ApiModelProperty("费用类别名称")
private String serviceItemsName;
}
@@ -97,4 +97,10 @@ public class ContractManageDetailPO extends BaseVOEntity{
@ApiModelProperty("单据类型")
private String documentType;
@ApiModelProperty("费用类别编码")
private String serviceItemsCode;
@ApiModelProperty("费用类别名称")
private String serviceItemsName;
}
@@ -102,4 +102,10 @@ public class ContractManageDetailDO extends BaseVOEntity{
@ApiModelProperty("单据类型")
private String documentType;
@ApiModelProperty("费用类别编码")
private String serviceItemsCode;
@ApiModelProperty("费用类别名称")
private String serviceItemsName;
}

Some files were not shown because too many files have changed in this diff Show More