284 Commits

Author SHA1 Message Date
wuweihua 206e4e786b 新增ar_bill_detail_fee表的income_fee_id字段,更新UUID到新同步逻辑 2026-11-15 09:39:57 +08:00
wuweihua 0179a35942 更新UUID到新费用行和阴影同步Mapper的注释,新增关联表回写逻辑 2026-11-15 09:01:19 +08:00
wuweihua 4de755ca60 移除UUID阴影同步中的应付相关表与同步逻辑
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-15 00:15:58 +08:00
wuweihua 358e5a46b9 新增UUID到新同步服务的失败处理逻辑和批次结果返回 2026-11-14 19:52:38 +08:00
wuweihua ee36c8c902 新增UUID到新同步运行器的Redis配置持久化功能 2026-11-14 19:27:49 +08:00
wuweihua 7e699fb80e 调整UUID到新配置的线程数范围和注释说明 2026-11-14 19:00:26 +08:00
wuweihua 80d639d887 更新支付账单服务逻辑,调整源ID赋值方式;修改SQL映射中的源ID字段为费用ID;新增UUID到BIGINT迁移配置 2026-11-14 18:53:03 +08:00
wuweihua 87ae3e6674 回退 UUID 转 bigint 相关改动(已迁至 feature/uuid-to-bigint)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-14 08:08:49 +08:00
wuweihua 359c3c18e4 修改费用ID类型为Long,更新相关逻辑和SQL映射 2026-11-14 01:22:12 +08:00
wuweihua 4f2f2db20f 更新UUID到BIGINT的迁移脚本,优化备份和回滚说明 2026-11-14 00:40:16 +08:00
wuweihua 0094e4aaff Merge branch 'test' of https://git.lionquexpress.com/wuweihua/BMS into test
# Conflicts:
#	bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPayBillFee.java
#	bms-back/bms-system/src/main/resources/mapper/price/PrcPayBillFeeMapper.xml
2026-11-14 00:32:55 +08:00
wuweihua 8b7c346ec4 修改计费订单ID类型为Long,优化相关逻辑 2026-11-14 00:23:47 +08:00
liuminghui bde1d7d86e 应付计费邮编改造 2026-11-13 18:26:21 +08:00
wuweihua 87eab12d51 优化附加费计算规则,调整相关逻辑和注释 2026-11-13 15:25:10 +08:00
liuminghui 880b4751c5 Merge remote-tracking branch 'origin/test' into test 2026-11-13 11:57:40 +08:00
liuminghui 3a104d2d8c 应付配置的附加费配置完善 2026-11-13 11:57:19 +08:00
wuweihua a024b45940 重构打单套餐相关逻辑,更新服务接口,优化保存和查询功能 2026-11-13 11:27:58 +08:00
liuminghui 6675808dfc 应付配置增加附加费配置,应付账单新增核销、对账、凭证、审核功能 2026-11-12 18:20:32 +08:00
caojia 1ba431540d ✨ 支持应收账单异步作废 2026-11-12 17:33:21 +08:00
caojia 0d0613e810 ⚡ 移除应收账单确认时的明细校验 2026-11-12 17:08:56 +08:00
caojia 47b95b6bfd 💄 调整应收合计查询按钮显示 2026-11-12 17:08:56 +08:00
wuweihua e7fd7f9059 优化计费规则注释,新增三边规则处理逻辑 2026-11-12 17:00:04 +08:00
wuweihua 1ffaf424b1 Merge branch 'test' of https://git.lionquexpress.com/wuweihua/BMS into test 2026-11-12 16:53:45 +08:00
wuweihua 8ca5af1ff0 新增打单产品明细保存接口,优化附加费管理逻辑 2026-11-12 16:53:40 +08:00
caojia 621128530a ⚡ 优化应收合计查询并补充导出汇总 2026-11-12 15:58:25 +08:00
caojia fb9a4e1b29 ⚡ 优化应收账单预览排序 2026-11-12 15:00:58 +08:00
caojia 89aadf97db ✨ 扩展应收账单销售经理部门数据范围 2026-11-12 15:00:58 +08:00
wuweihua 90147ed4e3 新增附加费计费标识,优化附加费管理逻辑 2026-11-12 14:43:42 +08:00
wuweihua cf336f7a67 新增按国家去重区块标题接口,优化计费列表请求方式 2026-11-12 13:45:09 +08:00
wuweihua d2c75e0c51 修改计费逻辑 2026-11-12 11:07:13 +08:00
wuweihua 17ee9731e8 更新应用配置,新增工具迁移链接排除项 2026-11-12 09:56:37 +08:00
caojia 146d3469b6 ✨ 支持应收账单导出通过 OSS 签名链接下载 2026-11-12 09:27:10 +08:00
caojia 27715b3e13 ✨ 将应收账单预览导出改为异步处理 2026-11-11 17:56:14 +08:00
wuweihua b5299e4490 移除价卡导入按钮和相关组件 2026-11-11 17:48:02 +08:00
wuweihua 82164cb00c 修改计费重按钮为注释,更新重新计费按钮样式 2026-11-11 17:12:20 +08:00
caojia 34fa8e23c1 🐛 毛利分析增加查询条件校验 2026-11-11 17:00:49 +08:00
liuminghui efd92b5663 新增提单管理和提单计费页面 2026-11-11 16:36:40 +08:00
wuweihua 7869205afc 新增数据迁移任务到定时任务白名单;优化默认收货时间范围逻辑 2026-11-11 15:34:11 +08:00
wuweihua f82d9c667f Merge branch 'test' of https://git.lionquexpress.com/wuweihua/BMS into test 2026-11-11 14:50:58 +08:00
wuweihua 7e1041391a 新增打单产品渠道查询与替换功能 2026-11-11 14:50:34 +08:00
caojia 99cdfd86d3 ✨ 展示TMS同步新增用户明细 2026-11-11 14:44:41 +08:00
caojia 41a80f9794 ✨ 设置应收账单默认日期范围 2026-11-11 14:31:08 +08:00
caojia 8cb2d03062 🐛 修复应收账单二维码位置 2026-11-11 14:23:25 +08:00
wuweihua 4ceb0bc830 Merge branch 'test' of https://git.lionquexpress.com/wuweihua/BMS into test 2026-11-11 13:52:35 +08:00
wuweihua f7384c88f6 优化代码注释为简体中文 2026-11-11 13:52:28 +08:00
caojia beba9e9caa 🐛 校验账单价格后确认提成比例 2026-11-11 13:45:34 +08:00
wuweihua b7d0674fda 优化代码注释为简体中文 2026-11-11 13:35:53 +08:00
wuweihua 0545de88b4 新增订单计费失败原因的价格周期字段,并优化前端展示,支持查看价格周期详情。 2026-11-11 13:12:32 +08:00
wuweihua 2430e344a0 Merge branch 'test' of https://git.lionquexpress.com/wuweihua/BMS into test 2026-11-11 11:30:22 +08:00
wuweihua 5db27e00ba 修改计费失败原因 2026-11-11 11:30:17 +08:00
caojia a06962d1dd ⚡ 优化应收账单毛利查询 2026-11-11 11:27:54 +08:00
wuweihua 5f679b5a6e 修改订单列表重新计费 2026-11-11 10:49:45 +08:00
wuweihua 02763f092e 修改打单套餐功能 2026-11-11 10:12:11 +08:00
caojia b6718f9361 调整命名2 2026-11-11 09:54:09 +08:00
wuweihua a58de9bb7e 修改计费逻辑仅 billing_fail_status = 0 才写 prc_income_bill 2026-11-11 09:49:59 +08:00
wuweihua a211f06663 修改定时任务时间 2026-11-11 09:29:47 +08:00
caojia 41cefd5fd5 调整命名 2026-11-11 00:18:12 +08:00
wuweihua fca999c384 修改比较逻辑 2026-11-10 18:10:10 +08:00
caojia 2e5ab2bfc1 ✅ 跳过依赖本机价卡文件的测试 2026-11-10 18:04:19 +08:00
caojia 3e5ef25153 ✨ 完善应收账单毛利分析与提成展示 2026-11-10 17:37:17 +08:00
caojia 9004a1b921 🔥 删除毛利汇总说明文字 2026-11-10 17:37:17 +08:00
wuweihua cf6b90008d 修改规则 2026-11-10 17:30:11 +08:00
liuminghui fbc138f041 提单费用均摊处理 2026-11-10 17:24:52 +08:00
wuweihua 3c49175cea 增加规则配置 2026-11-10 17:15:38 +08:00
wuweihua f26e03efb1 Merge branch 'test' of https://git.lionquexpress.com/wuweihua/BMS into test 2026-11-10 16:21:16 +08:00
wuweihua 1a0483c7fe 增加一个渠道绑定 2026-11-10 16:21:07 +08:00
liuminghui da9efc422e 提单费用调整 2026-11-10 15:21:03 +08:00
wuweihua e6a9fcf0a2 修改类型 2026-11-10 14:38:38 +08:00
wuweihua de5784cbac 修改打单计费逻辑 2026-11-09 23:38:07 +08:00
wuweihua 16afa0d590 增加一个打单功能套餐 2026-11-09 23:00:48 +08:00
wuweihua 2632e5aa78 渠道管理增加应收关联 2026-11-09 17:27:21 +08:00
liuminghui ace1eb06c0 去除计费列表的多余按钮 2026-11-09 16:15:55 +08:00
liuminghui f31bb4c54d Merge remote-tracking branch 'origin/test' into test 2026-11-09 16:00:23 +08:00
liuminghui b8b943ef51 偏远地区邮编判断调整 2026-11-09 15:58:27 +08:00
caojia f2d27f3502 🔥 移除应收毛利分析冗余展示和筛选 2026-11-09 15:58:14 +08:00
liuminghui 9220696519 Merge branch 'test' into feauture-20261104
# Conflicts:
#	bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcOrderBillMapper.java
2026-11-09 15:37:55 +08:00
wuweihua 8633019788 增加计费日志显示 2026-11-09 14:12:21 +08:00
wuweihua 4148c447fc 修改删除逻辑 2026-11-09 13:39:14 +08:00
caojia 61099b2514 调整模板 2026-11-09 11:24:27 +08:00
caojia 9e3f8314f1 🐛 修正账单预览导出重量精度 2026-11-09 11:24:26 +08:00
caojia 7abb7fdb06 🐛 修正账单预览重量精度显示 2026-11-09 11:24:26 +08:00
caojia cd25055159 ✨ 新增应收账单毛利分析与提成管理 2026-11-09 11:24:26 +08:00
wuweihua 489f99dc7b 合并套餐 2026-11-09 11:09:51 +08:00
wuweihua af3fb0aa2f 修改去空格 2026-11-06 19:27:31 +08:00
liuminghui e4c16263ab Merge branch 'test' into feauture-20261104
# Conflicts:
#	bms-front/src/views/price/billing/components/BillDetail.vue
2026-11-06 17:30:48 +08:00
liuminghui 020aace3f9 新增提单费用和费用日志 2026-11-06 17:28:55 +08:00
wuweihua 709c315971 增加计费列表收货时间查询 2026-11-06 16:13:03 +08:00
liuminghui 6f342d424f 新增路线产品 2026-11-06 13:39:26 +08:00
wuweihua a2e986fa6a 回退代码去掉收货查询 2026-11-06 10:46:58 +08:00
wuweihua 7807534e5d 去掉监控的价格日志 2026-11-06 10:28:55 +08:00
wuweihua e415843b14 增加价格变更日志 2026-11-06 10:11:15 +08:00
liuminghui b4da248815 应付产品增加状态过滤 2026-11-06 09:27:49 +08:00
wuweihua 1090d838a6 增加版本号显示 2026-11-05 18:42:27 +08:00
wuweihua 6ced4f237f 增加查看计费历史记录 2026-11-05 18:33:14 +08:00
wuweihua 87c75922aa 增加查看价格套餐历史版本的变更 2026-11-05 18:28:57 +08:00
wuweihua 44df6b1a1b 优化计费速度 2026-11-05 16:58:30 +08:00
liuminghui 270b762443 Merge branch 'test' into feauture-20261104
# Conflicts:
#	bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcProfitReportServiceImpl.java
2026-11-05 16:38:53 +08:00
liuminghui 36433863af 调整订单同步查询条件 2026-11-05 16:34:33 +08:00
wuweihua 04ce44647a 修改订单数源产品显示 2026-11-05 16:12:35 +08:00
liuminghui fde53681d1 新建应付配置的附加费开关配置 2026-11-05 16:05:01 +08:00
wuweihua 93c081775d 优化订单数源的进度条 2026-11-05 15:58:20 +08:00
caojia 25801fe42f ✨ 按客户区域计算毛利并完善汇总展示 2026-11-05 15:43:06 +08:00
wuweihua 891fdea7d3 增加失败原因和优化进度条 2026-11-05 15:38:45 +08:00
caojia 1727386811 毛利分析的客户区域筛选。 2026-11-05 14:27:01 +08:00
wuweihua 218001e6ae 修改编辑bug 2026-11-05 13:15:51 +08:00
wuweihua 308526ecee 增加专属报价功能 2026-11-05 12:57:13 +08:00
liuminghui 116b3b74e4 应付配置文件导入保存该文件 2026-11-05 10:31:02 +08:00
wuweihua 557d43a0b8 增加进度条 2026-11-04 19:38:13 +08:00
caojia 942d5932ae ✨ 同步客户区域字段并统一字典标识 2026-11-04 18:29:47 +08:00
caojia 51a89b18e1 应付账单初始化 2026-11-04 18:01:02 +08:00
caojia 846a41c6df 🐛 保留毛利报表暂停功能校验 2026-11-04 16:04:38 +08:00
caojia 04be15deab 🐛 修复毛利报表查询参数编译错误 2026-11-04 16:02:56 +08:00
caojia 328702a618 🔥 移除毛利分析价格缺失统计 2026-11-04 15:56:11 +08:00
caojia 910a73ed28 💄 调整毛利分析筛选项位置 2026-11-04 15:47:22 +08:00
caojia 5cccbf510f ✨ 新增管理员代登录功能 2026-11-04 15:20:05 +08:00
caojia 93da04fe5e ✨ 应收账单导出时间按筛选类型切换 2026-11-04 14:26:01 +08:00
wuweihua 1ebc86ddcf 隐藏修改计费重
(cherry picked from commit cdfc90556d)
2026-11-04 13:43:40 +08:00
caojia 6b111088c8 🐛 按当天截止时间筛选账单订单
(cherry picked from commit 1f0d757e29)
2026-11-04 13:43:31 +08:00
caojia 8d4e3363ae ✨ 新增应收账单日期类型筛选
(cherry picked from commit 762cad2c0d)
2026-11-04 13:43:30 +08:00
caojia 7399174bd6 ✨ 支持客户账单状态多选并修正有效金额汇总 2026-11-04 11:57:09 +08:00
caojia 8208a7393f ✨ 应收账单状态筛选支持多选并默认排除作废 2026-11-04 11:19:23 +08:00
caojia 826d95d3c1 ✨ 新增应收账单生成预览结果导出 2026-11-04 10:23:33 +08:00
wuweihua 071a1d7f55 优化列表查询 2026-11-04 10:16:26 +08:00
caojia c6509fca51 ✨ 合并毛利分析客户筛选并调整订单号输入高度 2026-11-04 10:09:10 +08:00
wuweihua f0012ac563 计费重覆盖 2026-11-03 18:13:52 +08:00
wuweihua 98ae525403 增加提单功能 2026-11-03 17:50:35 +08:00
wuweihua c87f49a14b 增加提单功能 2026-11-03 17:30:12 +08:00
caojia 6b78e13e5c ✨ 限制应收账单仅拉取指定上游订单状态 2026-11-03 16:55:15 +08:00
caojia 86255c45f6 🔧 将前端默认请求超时调整为20秒 2026-11-03 16:46:43 +08:00
caojia 844b501686 💄 调整侧栏 Logo 显示宽度 2026-11-03 15:58:00 +08:00
caojia 229f1f9bad 💄 调整毛利分析筛选项顺序 2026-11-03 14:31:06 +08:00
caojia 42d12a3fa3 🔥 移除毛利分析数据范围过滤 2026-11-03 14:19:20 +08:00
caojia 3481cfd634 更换logo 2026-11-02 16:45:42 +08:00
wuweihua 7d3854bb4f 增加导入模版逻辑判断 2026-11-02 16:41:47 +08:00
wuweihua e93f0c0233 新增套餐基本信息编辑功能,包括更新套餐名称和备注,支持客户筛选和绑定客户显示。 2026-11-02 11:52:08 +08:00
liuminghui 1b1b934d87 供应商路由调整 2026-11-02 10:41:20 +08:00
wuweihua 1ba5822a86 修改报错 2026-11-02 10:05:57 +08:00
wuweihua 17e80b3a18 增加最计费重的计费逻辑 2026-11-02 09:13:33 +08:00
wuweihua 9d4dbdcbe6 增加产品价编辑 2026-11-02 09:00:38 +08:00
liuminghui d185995dc7 客户管理新增区域类型属性 2026-10-30 18:00:20 +08:00
wuweihua bc33e11437 增加对外代码搜索 2026-10-30 17:45:37 +08:00
wuweihua 8ed97fed4a 增加批量绑定 2026-10-30 11:07:51 +08:00
wuweihua 6b10a41b9d 拉取上游数据记录es里面 2026-10-29 18:17:47 +08:00
caojia 02c49e3efe ✨ 新增应收账单按角色和客户归属的行级数据权限 2026-10-29 16:42:28 +08:00
liuminghui b091d47f64 新增渠道管理 2026-10-29 16:30:15 +08:00
wuweihua c3456ca92a 新增按版本获取价格设置明细的接口,优化产品下拉选项查询,更新相关服务和前端调用逻辑。 2026-10-29 16:13:18 +08:00
liuminghui 59eb4b23cc 客户管理套餐去除生效和失效日期 2026-10-29 11:37:31 +08:00
liuminghui fc21b08318 区域管理国旗替换 2026-10-29 11:30:26 +08:00
caojia b72f3a7014 导包 2026-10-29 11:13:36 +08:00
caojia eafc8af89a ✨ 新增未关联业务员客户列表 2026-10-29 11:08:46 +08:00
liuminghui d02d3dd881 订单列表和计费列表调整使用客户下拉全查接口 2026-10-29 10:33:41 +08:00
wuweihua 3bb7267b0b 修改产品价和红线价功能 2026-10-28 22:44:13 +08:00
wuweihua 1d47d5781b Merge branch 'test' of http://git.lionquexpress.com/wuweihua/BMS into test 2026-10-28 22:22:48 +08:00
caojia 5f082d905d ✨ 完善客户业务员关联和同步 2026-10-28 22:19:47 +08:00
wuweihua a5e9511857 去掉套餐用户绑定功能逻辑 2026-10-28 22:14:09 +08:00
wuweihua 56340d0ea0 优化套餐新建版本的逻辑 2026-10-28 22:09:30 +08:00
wuweihua 786feec859 Merge branch 'test' of http://git.lionquexpress.com/wuweihua/BMS into test 2026-10-28 21:42:55 +08:00
wuweihua 1eb0e45513 增加建立新版本 2026-10-28 21:42:45 +08:00
caojia 1688cddac7 注释不必要的东西 2026-10-28 20:47:42 +08:00
caojia d7f49cef58 💄 优化账单核销文案和弹窗展示 2026-10-28 20:30:28 +08:00
caojia df7220d333 “收款入账”和“账单核销”分开处理 2026-10-28 20:13:34 +08:00
wuweihua 00a690abe9 Merge branch 'test' of https://git.lionquexpress.com/wuweihua/BMS into test 2026-10-28 18:10:14 +08:00
wuweihua 8ed7b3146b 修改套餐规则 2026-10-28 18:10:10 +08:00
liuminghui 1e4711326c 去除供应商类型多余代码 2026-10-28 17:14:42 +08:00
wuweihua 2bd417b84e Merge branch 'test' of https://git.lionquexpress.com/wuweihua/BMS into test 2026-10-28 15:25:23 +08:00
wuweihua 3652546ea4 修改计费逻辑名称 2026-10-28 15:24:59 +08:00
liuminghui 1a0dc9c982 数据接口查询去除权限注解 2026-10-28 15:24:03 +08:00
caojia 173e22a58e ✨ 拆分应收账单导出与下载权限 2026-10-28 14:58:09 +08:00
caojia acfdfd5cbf ✨ 客户列表增加账单入口和权限 2026-10-27 20:29:08 +08:00
caojia db787ec7f7 ✨ 客户账单弹窗增加汇总和导出 2026-10-27 17:21:12 +08:00
caojia b4e696b27c ✨ 应收账单列表增加筛选导出 2026-10-27 17:04:22 +08:00
caojia 4238c31d9d 增加反核销按钮 2026-10-27 16:47:22 +08:00
wuweihua b55f0010ed 新增订单状态字段并调整提货时间字段,更新相关导出和展示逻辑 2026-10-27 16:23:02 +08:00
caojia 4067bfc277 ✨ 客户余额页增加只读账单弹窗 2026-10-27 16:19:44 +08:00
caojia fe30345045 Revert "✨ 应收账单接入角色数据权限并同步在线缓存"
This reverts commit 4659c63ef9.
2026-10-27 15:32:26 +08:00
wuweihua 4d4065b9e9 更新计费失败状态,新增销售价和产品价未匹配的错误信息,调整相关代码逻辑以支持新的状态处理。 2026-10-27 15:24:16 +08:00
liuminghui 0ba975656b 客户和供应商新增合同时间 2026-10-27 13:50:54 +08:00
liuminghui 65d382d256 Merge remote-tracking branch 'origin/test' into test 2026-10-27 13:36:11 +08:00
wuweihua 7fcd3b6089 计费列表增加状态搜索 2026-10-27 13:28:14 +08:00
liuminghui 7e53b41a3c 新增供应商类型配置 2026-10-27 11:40:22 +08:00
caojia 4659c63ef9 ✨ 应收账单接入角色数据权限并同步在线缓存 2026-10-27 11:32:26 +08:00
wuweihua f3fa3e1396 修改前端同步报错 2026-10-27 10:30:15 +08:00
liuminghui be0b067516 乱码注释调整 2026-10-27 10:17:53 +08:00
wuweihua f80af4a2f6 修改订单列表重新计费 2026-10-27 01:08:44 +08:00
wuweihua 7924450b89 修改同步落库 2026-10-27 00:04:21 +08:00
wuweihua 2bae431e74 优化落库功能 2026-10-26 23:23:22 +08:00
wuweihua 8fba64e2d6 Merge branch 'test' of https://git.lionquexpress.com/wuweihua/BMS into test 2026-10-26 17:59:46 +08:00
wuweihua 7e175808bf 去掉退费校验 2026-10-26 17:59:35 +08:00
caojia 74762c8043 调整权限 2026-10-26 17:59:34 +08:00
wuweihua bdce5e3086 优化数据源导出 2026-10-26 16:59:01 +08:00
caojia 2ed0e0c77d 🐛 修复用户管理组织机构筛选 deptId 滞后 2026-10-26 16:57:10 +08:00
caojia b3374fa44c 更新文档 2026-10-26 16:22:14 +08:00
wuweihua 76cc5b5781 增加导出功能 2026-10-26 16:20:46 +08:00
wuweihua 7f4fc3df8c 优化比对 2026-10-26 16:03:12 +08:00
wuweihua 209d545d5b 修改操作文档 2026-10-26 15:21:52 +08:00
wuweihua 90a0194a99 新增操作文档 2026-10-26 14:21:29 +08:00
wuweihua ab6216922a 订单比对加上状态 2026-10-26 11:59:19 +08:00
wuweihua 4bee108661 去掉三边之和规则 2026-10-23 17:49:52 +08:00
wuweihua 2bb562372e 修改计费规则 2026-10-23 17:43:07 +08:00
wuweihua 55b5ed8951 改动在 OracleOrderBillMapper.toBillRequest,同步计费 / 计费任务走上游行时都会生效。本地「重新计费」仍用订单表已存的计费重,不会再回上游取 2026-10-23 17:38:22 +08:00
wuweihua 48d938c4f7 支持按提货时间重新计费 2026-10-23 17:36:03 +08:00
luojiaquan dac0c0f252 Merge branch 'master' of http://git.lionquexpress.com/wuweihua/BMS 2026-10-23 15:57:15 +08:00
luojiaquan de34cad95d 无用字段注释 2026-10-23 15:57:09 +08:00
wuweihua d46d1596e8 处理同步退费逻辑 2026-10-23 14:00:53 +08:00
wuweihua 84939a8875 订单增加状态搜索 2026-10-23 13:47:41 +08:00
wuweihua fcebf9282c 优化添加附加费 2026-10-23 11:02:24 +08:00
caojia fc94a15f76 ✨ 单号筛选改为多行输入并限制1000个 2026-10-23 10:06:59 +08:00
wuweihua 4ec28de073 增加订单复选搜索 2026-10-22 17:40:57 +08:00
wuweihua 23236ec141 导入提示报错 2026-10-22 15:57:08 +08:00
wuweihua d010783c97 Merge branch 'master' of https://git.lionquexpress.com/wuweihua/BMS 2026-10-22 14:46:57 +08:00
wuweihua f07386f4aa 增加模版 2026-10-22 14:46:52 +08:00
luojiaquan 6fb0ba3edc 客户管理附件oss上传 2026-10-22 11:50:32 +08:00
wuweihua c064d925ca 增加上传附件到oss 2026-10-22 10:45:50 +08:00
wuweihua 92000956fc 增加导出功能 2026-10-21 18:06:21 +08:00
caojia c04191c316 🐛 修复账单导出数值精度显示 2026-10-21 15:10:34 +08:00
wuweihua b8e2a8e31a 增加套餐产品红线价修改内容日志 2026-10-21 15:08:13 +08:00
wuweihua 1e8a449dda 优化套餐编辑逻辑 2026-10-21 14:51:44 +08:00
caojia 26a3285571 🐛 修复账单导出运单号格式和列宽 2026-10-21 14:18:27 +08:00
caojia 9e61f7f55c 调整模板比例为70% 2026-10-21 13:50:03 +08:00
wuweihua a4440d7932 修改订单数据源的产品检测 2026-10-21 11:42:08 +08:00
wuweihua 35f1048190 删除productCountryId 2026-10-21 11:36:25 +08:00
wuweihua 8f1cf5c755 修改比对规则 2026-10-21 11:01:59 +08:00
wuweihua 36837f94bf 失败记录日志 2026-10-21 10:45:04 +08:00
wuweihua dd2efef456 修改死锁 2026-10-21 10:34:45 +08:00
wuweihua d7f7ebd981 订单列表重新计费优化 2026-10-21 10:13:01 +08:00
wuweihua be3856a59c 自动脚本计费 2026-10-21 09:44:54 +08:00
caojia 501056bb17 🐛 修复账单截止日当天数据漏查 2026-10-21 09:23:59 +08:00
wuweihua c30c88bbe8 修改已出账单,状态没落库 2026-10-21 09:13:50 +08:00
caojia dba75c3a77 ✨ 汇总前新增明细纳入应收合计 2026-10-20 20:32:24 +08:00
caojia e41c7b072f ✨ 应收账单导出金额公式动态化 2026-10-20 20:09:39 +08:00
wuweihua 2d5a2c4bab 修改计费重去掉客户 2026-10-20 18:48:46 +08:00
wuweihua 66d95a0da9 更改产品获取数据 2026-10-20 18:43:33 +08:00
wuweihua 7655713319 修改生效时间 2026-10-20 18:05:18 +08:00
wuweihua eca8855b8d 修改对外代码查询 2026-10-20 16:20:57 +08:00
caojia acf4757144 🐛 修复账单预览翻页重置手动选择模式 2026-10-20 15:38:43 +08:00
caojia 7063dc7218 ✨ 优化生成应收账单订单表格 2026-10-20 15:29:36 +08:00
caojia 9166220579 ✨ 支持生成账单列表拖选复制单列文字 2026-10-20 15:25:15 +08:00
caojia b772c95813 ✨ 支持按单号批量排除账单订单 2026-10-20 15:11:27 +08:00
wuweihua 29e804dae2 修改前端同步逻辑 2026-10-20 14:03:37 +08:00
wuweihua 45969a4d29 订单数据源增加订单对比功能 2026-10-20 13:55:55 +08:00
luojiaquan 8093cb52e7 订单数据源数据速度优化 2026-10-20 10:14:38 +08:00
wuweihua 58d7ec90b0 提高订单源的查询速度 2026-10-19 17:44:19 +08:00
caojia 383ef55e00 ✨ 完善核销用户记录和毛利报表导出日志 2026-10-19 16:43:14 +08:00
luojiaquan a754e8dcc6 Merge branch 'master' of http://git.lionquexpress.com/wuweihua/BMS 2026-10-19 16:03:36 +08:00
luojiaquan 1ae97cd622 客户余额按钮加权限控制 2026-10-19 16:03:30 +08:00
caojia 1986a901d9 ✨ 补充应收账单用户ID记录及迁移脚本 2026-10-19 15:52:57 +08:00
wuweihua 5bb9000e8e 修改套餐报错 2026-10-19 15:34:04 +08:00
wuweihua df1a2fd731 修改订单搜索 2026-10-19 15:19:06 +08:00
luojiaquan b945c9f37b Merge branch 'master' of http://git.lionquexpress.com/wuweihua/BMS 2026-10-19 12:01:08 +08:00
luojiaquan 6b570f948c 修改客户管理权限控制,按user_id控制 2026-10-19 12:00:56 +08:00
wuweihua 374c8b8bbb 增加套餐绑定用户功能 2026-10-19 11:59:44 +08:00
wuweihua 69852907f3 修改列表 2026-10-19 10:03:13 +08:00
luojiaquan 92fc2f1ad0 修改TMS用户同步只增量同步用户数据 2026-10-19 09:59:01 +08:00
caojia a48b40c649 🚚 重命名应收账单明细导出记录表 2026-10-18 22:41:31 +08:00
caojia 3cf85af180 💄 调整应收账单导出列宽与公式显示 2026-10-18 22:13:40 +08:00
wuweihua a19d97d111 修改优化 2026-10-18 15:32:48 +08:00
wuweihua 60d4614695 重构产品价和红线价功能 2026-10-18 14:16:27 +08:00
wuweihua db6f5e882a 优化计费逻辑 2026-10-17 01:37:33 +08:00
wuweihua 52f714c760 回滚代码 2026-10-16 20:28:49 +08:00
wuweihua 9ff89e36ee 增加收货时间 2026-10-16 18:01:46 +08:00
wuweihua 6a07786e75 增加字段 2026-10-16 17:46:50 +08:00
wuweihua a15a96f881 Merge branch 'master' of https://git.lionquexpress.com/wuweihua/BMS 2026-10-16 17:46:43 +08:00
caojia 1d22bd91fd 💄 调整应收账单导出表格布局 2026-10-16 17:43:00 +08:00
wuweihua db396458c5 增加订单主表 2026-10-16 17:27:11 +08:00
wuweihua e227c6a80f Merge branch 'master' of https://git.lionquexpress.com/wuweihua/BMS 2026-10-16 17:27:09 +08:00
caojia eb67ccc3cb ✨ 毛利分析报表导出接入 OSS 存储 2026-10-16 17:09:34 +08:00
caojia 9e391888f5 ✨ 账号密码补全 2026-10-16 16:48:46 +08:00
caojia b0719d2ae9 ✨ 接入账单 OSS 存储并区分生产测试目录 2026-10-16 16:44:51 +08:00
wuweihua 15e005fd20 修改规则 2026-10-16 16:28:12 +08:00
wuweihua 9824e05919 增加规则判断 2026-10-16 14:05:50 +08:00
wuweihua b54cb1b018 增加规则配置 2026-10-16 13:40:03 +08:00
wuweihua b3f79ffc4c Merge branch 'master' of https://git.lionquexpress.com/wuweihua/BMS 2026-10-16 11:27:48 +08:00
wuweihua 2431a5caac 增加筛选 2026-10-16 11:27:44 +08:00
caojia 760e3807f3 ✨ 应收账单预览支持大批量单号查询 2026-10-16 11:05:02 +08:00
luojiaquan 132688b9cf 同步计费优化 2026-10-16 10:59:59 +08:00
wuweihua 2689138b6a 修改套餐价格 2026-10-16 10:43:45 +08:00
luojiaquan 622d2a4c40 Merge branch 'master' of http://git.lionquexpress.com/wuweihua/BMS 2026-10-16 09:22:19 +08:00
luojiaquan 02481b102c 优化订单列表,多单号查询,支持几万单号查询 2026-10-16 09:22:13 +08:00
caojia ca010a4242 🔧 调整JWT令牌有效期为24小时 2026-10-15 21:15:01 +08:00
caojia f92da4782d 💄 调整应收账单导出按钮文案 2026-10-15 20:51:18 +08:00
caojia 0a7f639138 sql 2026-10-15 18:49:16 +08:00
caojia 5126a5c163 🐛 修复应收账单序号格式并移除登录默认账号密码 2026-10-15 18:45:09 +08:00
caojia a22039defc 🐛 修复订单列表多单号查询URL过长 2026-10-15 18:00:44 +08:00
luojiaquan 085d01dc15 价格套餐缓存修改 2026-10-15 17:13:00 +08:00
834 changed files with 102000 additions and 7999 deletions
+38
View File
@@ -0,0 +1,38 @@
# 应收账单行级权限
规则独立于 `@DataScope` 和角色管理的 `dataScope`,现有菜单、按钮权限保持不变。
| roleKey | 数据范围 |
| --- | --- |
| ORA_6041 / ORA_6163 | 销售员、商务专员:本人负责客户 |
| ORA_6040 | 本部门人员负责客户,不含下级部门 |
| ORA_6042 / ORA_6043 | 财务经理、应收财务:全部账单 |
超级管理员沿用系统判断。仅参与当前入口功能授权的有效角色合并范围;未知角色、空权限对象默认无数据。财务本期不使用账单 `create_user_id`。应付财务不参与应收账单权限规则。
归属链为 `ar_bill.customer_id → ctr_customer.sales_user_id → sys_user.user_id / dept_id`。销售员和商务专员均通过客户的 `sales_user_id` 与当前登录用户 ID 匹配本人客户。客户转交后,历史账单跟随当前归属变化。全量角色可见未关联销售、销售已删除、客户已删除的历史账单;受限角色不放行无有效归属的数据。业务员仅停用但未删除时,其部门经理仍可查看。
核心实现位于 `bms-system/src/main/java/com/bms/ar/security` 和 `mapper/ar/ArBillScopeMapper.xml`。内部权限对象作为独立 Mapper 参数传递,不绑定 HTTP 查询对象;后台生成和导出任务继续使用独立的内部读取方法。
接入范围包括列表、汇总、列表导出、详情/费用、日志、生成预览及提交、生成任务、导出任务及下载、客户账单入口,以及客户/收款页面的待核销账单、核销记录、核销和反核销。应收筛选及生成客户选项分别使用 `/ar/bill/customer-options`、`/ar/bill/generate/customer-options`。
用户编辑、调部门、停用、分配角色,以及角色编辑、停用、删除和授权关系调整,会在事务提交后让受影响的登录会话失效;相关用户需要重新登录。不改变角色配置本身。
## 本地验证
在 `bms-back` 下执行(PowerShell):
```powershell
mvn -o -pl bms-admin -am -DskipTests compile
```
本次新增的行级权限测试用例及其辅助脚本已按要求删除。
在 `bms-front` 下执行 `npm run build:prod` 验证前端构建。
## 部署前核实
- 本次没有新增数据库字段、权限配置表或迁移 SQL。
- 目标环境 `ctr_customer.sales_user_id` 必须已经统一为系统用户 ID,不能仍是旧业务员工号。现有迁移文件位于 `sql/customer+supplier/20261028_customer_sales_user_migration.sql`,需要按原有流程确认执行状态,本次不自动执行。
- 使用真实销售 A/B、经理、财务和商务专员账号检查数据范围与功能授权,特别是生产角色实际拥有的接口权限。
- 上线前仍需在 MySQL 5.7 环境联调,并检查实际数据的执行计划。
@@ -28,6 +28,7 @@ public class BmsApplication
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
@@ -16,8 +16,8 @@ import com.bms.price.search.IBillSearchStore;
import com.bms.web.controller.price.BillingController;
/**
* Persist quote/bill API failures to Elasticsearch (validation, JSON parse, business, unexpected).
* Uses {@link EsBizLogSupport#saveApiFail} so service/controller can also call without duplicate docs.
* 把报价/计费接口失败写入 Elasticsearch(校验、JSON 解析、业务异常、未预期异常)。
* 通过 {@link EsBizLogSupport#saveApiFail} 写入,service/controller 也可调用且不会重复落文档。
*/
@Order(0)
@RestControllerAdvice(assignableTypes = { TmsPriceController.class, BillingController.class })
@@ -29,10 +29,10 @@ import com.bms.price.service.IPrcOrderBillService;
import com.bms.price.service.ITmsPriceQuoteService;
/**
* TMS open API: freight quote.
* TMS 开放接口:运费试算。
*
* POST /api/tms/price/quote
* Header X-Api-Code must equal bms.tms.api-code
* 请求头 X-Api-Code 必须等于 bms.tms.api-code
*
* @author bms
*/
@@ -59,9 +59,9 @@ public class TmsPriceController extends BaseController
private IBillSearchStore billSearchStore;
/**
* Quote by customer + product + country + weight (+ destPostcode when country has zones).
* Zone resolve: destPostcode -> prc_zone_detail/prc_zone -> product_country.zone_code.
* Match: customer package FIXED &gt; DISCOUNT &gt; product default.
* 按客户 + 产品 + 国家 + 重量试算(国家配置了分区时需传 destPostcode)。
* 分区解析:destPostcode -> prc_zone_detail/prc_zone -> product_country.zone_code。
* 匹配顺序:客户套餐 FIXED &gt; DISCOUNT &gt; 产品默认价。
*/
@PostMapping("/quote")
public AjaxResult quote(
@@ -83,9 +83,9 @@ public class TmsPriceController extends BaseController
}
/**
* Sync order and persist prc_order_bill / prc_income_bill_fee.
* Same price match as quote (bound set + active version by bizDate, else default).
* Same orderNo upserts.
* 同步订单并落库 prc_order_bill / prc_income_bill_fee。
* 价格匹配与试算一致(绑定套餐 + 按 bizDate 取生效版本,否则取默认价)。
* 相同 orderNo 执行 upsert。
*/
@PostMapping("/bill")
public AjaxResult bill(
@@ -106,8 +106,8 @@ public class TmsPriceController extends BaseController
}
/**
* Warehouse inbound: create billing task (PENDING/REBILL/REFUND) and publish MQ.
* Consumer queries Oracle by transferNo/orderNo then inserts prc_order_bill.
* 仓库入库:创建计费任务(PENDING/REBILL/REFUND)并发送 MQ。
* 消费端按 transferNo/orderNo 查询 Oracle,然后插入 prc_order_bill。
* POST /api/tms/price/billing-task
*/
@PostMapping("/billing-task")
@@ -121,7 +121,7 @@ public class TmsPriceController extends BaseController
}
/**
* Query billing task writeback status.
* 查询计费任务回写状态。
* GET /api/tms/price/billing-task/{taskId}
*/
@GetMapping("/billing-task/{taskId}")
@@ -135,7 +135,7 @@ public class TmsPriceController extends BaseController
}
/**
* Query order bill by orderNo after sync.
* 同步完成后按 orderNo 查询订单账单。
*/
@GetMapping("/bill/by-order/{orderNo}")
public AjaxResult getBillByOrder(
@@ -11,6 +11,7 @@ import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.bms.common.config.BmsConfig;
@@ -18,6 +19,8 @@ import com.bms.common.core.domain.AjaxResult;
import com.bms.common.utils.StringUtils;
import com.bms.common.utils.file.FileUploadUtils;
import com.bms.common.utils.file.FileUtils;
import com.bms.common.utils.file.MimeTypeUtils;
import com.bms.common.utils.file.OssStorage;
import com.bms.framework.config.ServerConfig;
/**
@@ -34,6 +37,9 @@ public class CommonController
@Autowired
private ServerConfig serverConfig;
@Autowired
private OssStorage ossStorage;
private static final String FILE_DELIMITER = ",";
/**
@@ -94,6 +100,56 @@ public class CommonController
}
}
/**
* 通用上传请求(OSS 存储,返回 oss:// 存储标识)。
* 客户附件、公司主体、收款凭证等业务附件走此接口;
* 下载统一经 /common/download/resource?resource=oss://... 鉴权转发。
*/
@PostMapping("/upload/oss")
public AjaxResult uploadFileOss(MultipartFile file,
@RequestParam(value = "module", required = false) String module) throws Exception
{
try
{
if (file == null || file.isEmpty())
{
return AjaxResult.error("上传文件不能为空");
}
String originalFilename = file.getOriginalFilename();
// 扩展名白名单与大小校验(默认 50MB,图片/文档/压缩包/视频/pdf)
FileUploadUtils.assertAllowed(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
String extension = "";
int dotIndex = originalFilename != null ? originalFilename.lastIndexOf('.') : -1;
if (dotIndex >= 0)
{
extension = originalFilename.substring(dotIndex + 1).toLowerCase();
}
// module 仅允许字母数字下划线中划线,防止对象 key 注入
String moduleKey = StringUtils.defaultIfBlank(module, "misc").replaceAll("[^a-zA-Z0-9_-]", "");
if (moduleKey.isEmpty())
{
moduleKey = "misc";
}
String datePath = new java.text.SimpleDateFormat("yyyy/MM/dd").format(new java.util.Date());
String objectKey = "attachment/" + moduleKey + "/" + datePath + "/"
+ java.util.UUID.randomUUID().toString().replace("-", "") + "." + extension;
String storageKey = ossStorage.upload(file.getInputStream(), file.getSize(), objectKey, file.getContentType());
String downloadUrl = "/common/download/resource?resource="
+ java.net.URLEncoder.encode(storageKey, java.nio.charset.StandardCharsets.UTF_8);
AjaxResult ajax = AjaxResult.success();
ajax.put("url", downloadUrl);
ajax.put("fileName", storageKey);
ajax.put("newFileName", originalFilename);
ajax.put("originalFilename", originalFilename);
return ajax;
}
catch (Exception e)
{
log.error("upload file to oss failed", e);
return AjaxResult.error(e.getMessage());
}
}
/**
* 通用上传请求(多个)
*/
@@ -132,7 +188,7 @@ public class CommonController
}
/**
* 本地资源通用下载
* 通用资源下载:本地 profile 路径或 oss://bucket/key(AR 账单风格)。
*/
@GetMapping("/download/resource")
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
@@ -140,15 +196,30 @@ public class CommonController
{
try
{
if (!FileUtils.checkAllowDownload(resource))
if (StringUtils.isEmpty(resource))
{
throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
throw new Exception("resource empty");
}
boolean ossFile = resource.startsWith("oss://");
if (!ossFile && !FileUtils.checkAllowDownload(resource))
{
throw new Exception(StringUtils.format("resource ({}) not allowed", resource));
}
if (ossFile)
{
// 扩展名校验仍适用于对象 key 后缀。
if (!FileUtils.checkAllowDownload(resource))
{
throw new Exception(StringUtils.format("resource ({}) not allowed", resource));
}
String downloadName = StringUtils.substringAfterLast(resource, "/");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, downloadName);
ossStorage.download(resource, response.getOutputStream());
return;
}
// 本地资源路径
String localPath = BmsConfig.getProfile();
// 数据库资源地址
String downloadPath = localPath + FileUtils.stripPrefix(resource);
// 下载名称
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, downloadName);
@@ -156,7 +227,7 @@ public class CommonController
}
catch (Exception e)
{
log.error("下载文件失败", e);
log.error("download resource failed", e);
}
}
}
@@ -5,6 +5,7 @@ import java.util.List;
import com.bms.customer.customerinfo.domain.BmsCustomerAttachment;
import com.bms.customer.customerinfo.domain.BmsCustomerCompany;
import com.bms.customer.customerinfo.domain.BmsCustomerContact;
import com.bms.customer.customerinfo.vo.UnlinkedSalesCustomerVO;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +23,7 @@ import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.enums.BusinessType;
import com.bms.customer.customerinfo.domain.BmsCustomer;
import com.bms.customer.customerinfo.domain.BmsCustomerOption;
import com.bms.customer.customerinfo.service.IBmsCustomerService;
import com.bms.common.utils.poi.ExcelUtil;
import com.bms.common.core.page.TableDataInfo;
@@ -51,6 +53,32 @@ public class BmsCustomerController extends BaseController
return getDataTable(list);
}
/** 查询未关联业务员的客户列表 */
@PreAuthorize("@ss.hasPermi('customersupplier:customerinfo:list')")
@GetMapping("/unlinked-sales-user/list")
public TableDataInfo unlinkedSalesUserList()
{
startPage();
BmsCustomer query = new BmsCustomer();
List<UnlinkedSalesCustomerVO> list = bmsCustomerService.selectUnlinkedSalesUserCustomerList(query);
return getDataTable(list);
}
/**
* 客户下拉选项。
* 只返回客户ID、客户编码、客户名称,供各页面下拉框使用。
* 查询参数 keywords 按客户名称、客户编码、对外代码模糊匹配,多行之间为或者关系。
* 分页参数与原下拉一致,避免一次查出全部客户。
*/
// @PreAuthorize("@ss.hasPermi('customersupplier:customerinfo:list')")
@GetMapping("/optionselect")
public TableDataInfo optionselect(BmsCustomer query)
{
startPage();
List<BmsCustomerOption> list = bmsCustomerService.selectCustomerOptions(query);
return getDataTable(list);
}
/**
* 导出客户信息列表
*/
@@ -1,7 +1,9 @@
package com.bms.web.controller.customer.customermoney;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
@@ -11,16 +13,22 @@ import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.bms.ar.domain.ArBalanceWriteoff;
import com.bms.ar.service.IArBalanceWriteoffService;
import com.bms.receivable.domain.ArBill;
import com.bms.receivable.domain.ArBalanceWriteoff;
import com.bms.receivable.domain.vo.ArBillListExportRow;
import com.bms.receivable.domain.vo.ArBillQuery;
import com.bms.receivable.domain.vo.ArBillSummary;
import com.bms.receivable.service.IArBalanceWriteoffService;
import com.bms.receivable.service.IArBillService;
import com.bms.common.annotation.Log;
import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.page.TableDataInfo;
import com.bms.common.enums.BusinessType;
import com.bms.common.utils.poi.ExcelUtil;
/**
* 客户余额核销应收账单 Controller(账单查看统一走应收管理-应收账单页面)
* 客户余额账单查询与核销 Controller
*
* @author bms
* @date 2026-09-16
@@ -32,6 +40,60 @@ public class CustomerBillController extends BaseController
@Autowired
private IArBalanceWriteoffService balanceWriteoffService;
@Autowired
private IArBillService billService;
/**
* 查询指定客户的应收账单(分页)。客户ID来自路径并覆盖查询对象中的同名参数。
*/
@PreAuthorize("@ss.hasPermi('customersupplier:customerinfo:bill')")
@GetMapping("/list/{customerId}")
public AjaxResult billList(@PathVariable("customerId") Long customerId, ArBillQuery query)
{
if (customerId == null || customerId <= 0L)
{
AjaxResult result = success();
result.put("rows", Collections.emptyList());
result.put("total", 0L);
result.put("summary", new ArBillSummary());
return result;
}
ArBillQuery billQuery = query == null ? new ArBillQuery() : query;
billQuery.setCustomerId(customerId);
startPage();
List<ArBill> list = billService.selectArBillList(billQuery);
TableDataInfo pageData = getDataTable(list);
AjaxResult result = success();
result.put("rows", pageData.getRows());
result.put("total", pageData.getTotal());
result.put("summary", billService.selectArBillSummary(billQuery));
return result;
}
/**
* 按当前筛选条件导出指定客户的全部应收账单,不受列表分页参数影响。
*/
@PreAuthorize("@ss.hasPermi('customersupplier:customerinfo:bill') and @ss.hasPermi('customersupplier:customerinfo:export')")
@Log(title = "客户账单", businessType = BusinessType.EXPORT)
@PostMapping("/export/{customerId}")
public void export(HttpServletResponse response, @PathVariable("customerId") Long customerId, ArBillQuery query)
{
List<ArBillListExportRow> rows = new ArrayList<>();
if (customerId != null && customerId > 0L)
{
ArBillQuery billQuery = query == null ? new ArBillQuery() : query;
// 客户ID固定取自路径,忽略请求参数中可能出现的 customerId。
billQuery.setCustomerId(customerId);
List<ArBill> bills = billService.selectArBillList(billQuery);
for (ArBill bill : bills)
{
rows.add(ArBillListExportRow.from(bill));
}
}
ExcelUtil<ArBillListExportRow> util = new ExcelUtil<>(ArBillListExportRow.class);
util.exportExcel(response, rows, "客户账单");
}
/**
* 查询客户可核销账单(已确认/部分核销,未核销额大于0)
*/
@@ -0,0 +1,73 @@
package com.bms.web.controller.data;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.bms.common.annotation.Log;
import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.page.TableDataInfo;
import com.bms.common.enums.BusinessType;
import com.bms.system.domain.BmsBizRule;
import com.bms.system.service.IBmsBizRuleService;
/**
* 规则配置
*/
@RestController
@RequestMapping("/data/bizRule")
public class BmsBizRuleController extends BaseController
{
@Autowired
private IBmsBizRuleService bizRuleService;
@PreAuthorize("@ss.hasPermi('data:bizRule:list')")
@GetMapping("/list")
public TableDataInfo list(BmsBizRule query)
{
startPage();
List<BmsBizRule> list = bizRuleService.selectList(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('data:bizRule:query')")
@GetMapping("/{ruleId}")
public AjaxResult getInfo(@PathVariable Long ruleId)
{
return success(bizRuleService.selectById(ruleId));
}
@PreAuthorize("@ss.hasPermi('data:bizRule:add')")
@Log(title = "biz rule", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody BmsBizRule row)
{
row.setCreateBy(getUsername());
return toAjax(bizRuleService.insert(row));
}
@PreAuthorize("@ss.hasPermi('data:bizRule:edit')")
@Log(title = "biz rule", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody BmsBizRule row)
{
row.setUpdateBy(getUsername());
return toAjax(bizRuleService.update(row));
}
@PreAuthorize("@ss.hasPermi('data:bizRule:remove')")
@Log(title = "biz rule", businessType = BusinessType.DELETE)
@DeleteMapping("/{ruleIds}")
public AjaxResult remove(@PathVariable Long[] ruleIds)
{
return toAjax(bizRuleService.deleteByIds(ruleIds));
}
}
@@ -0,0 +1,175 @@
package com.bms.web.controller.data;
import java.util.List;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.bms.common.annotation.Log;
import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.page.TableDataInfo;
import com.bms.common.enums.BusinessType;
import com.bms.common.enums.PaymentMesEnum;
import com.bms.price.domain.PayPostcodeGroup;
import com.bms.price.domain.PayPostcodeLine;
import com.bms.price.service.IPayPostcodeService;
/**
* 数据管理下的应付邮编配置。Excel 导入后按国家和附加费金额合并。
*/
@RestController
@RequestMapping("/data/payPostcode")
public class PayPostcodeController extends BaseController
{
@Autowired
private IPayPostcodeService payPostcodeService;
@PreAuthorize("@ss.hasPermi('data:payPostcode:list')")
@GetMapping("/list")
public TableDataInfo list(PayPostcodeGroup query)
{
startPage();
List<PayPostcodeGroup> list = payPostcodeService.selectCountryList(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:query')")
@GetMapping("/zones")
public AjaxResult zones(PayPostcodeGroup query)
{
return success(payPostcodeService.selectZoneList(query));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.INSERT)
@PostMapping("/zones")
public AjaxResult addZone(@RequestBody PayPostcodeGroup zone)
{
return toAjax(payPostcodeService.addZone(zone, getUsername()));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.UPDATE)
@PutMapping("/zones")
public AjaxResult editZone(@RequestBody PayPostcodeGroup zone)
{
return toAjax(payPostcodeService.updateZone(zone));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:remove')")
@Log(title = "应付邮编配置", businessType = BusinessType.DELETE)
@DeleteMapping("/zones")
public AjaxResult removeZone(PayPostcodeGroup zone)
{
return toAjax(payPostcodeService.deleteZone(zone));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.UPDATE)
@PutMapping("/country")
public AjaxResult editCountry(@RequestBody PayPostcodeGroup country)
{
return toAjax(payPostcodeService.updateCountry(country));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:remove')")
@Log(title = "应付邮编配置", businessType = BusinessType.DELETE)
@DeleteMapping("/country")
public AjaxResult removeCountry(PayPostcodeGroup country)
{
return toAjax(payPostcodeService.deleteCountry(country));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.INSERT)
@PostMapping("/lines")
public AjaxResult addLine(@RequestBody PayPostcodeLine line)
{
return toAjax(payPostcodeService.addLine(line));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.UPDATE)
@PutMapping("/lines")
public AjaxResult editLine(@RequestBody PayPostcodeLine line)
{
return toAjax(payPostcodeService.updateLine(line));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:remove')")
@Log(title = "应付邮编配置", businessType = BusinessType.DELETE)
@DeleteMapping("/lines/{lineIds}")
public AjaxResult removeLines(@PathVariable Long[] lineIds)
{
return toAjax(payPostcodeService.deleteLines(lineIds));
}
/** 按国家去重区块,供附加费编辑分区下拉 */
@PreAuthorize("@ss.hasPermi('data:payPostcode:list')")
@GetMapping("/blockOptions")
public AjaxResult blockOptions(@RequestParam(required = false) String countryCode,
@RequestParam(required = false) String countryName)
{
return success(payPostcodeService.selectBlockTitlesByCountry(countryCode, countryName));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:query')")
@GetMapping("/{groupId}")
public AjaxResult getInfo(@PathVariable Long groupId)
{
return success(payPostcodeService.selectGroupById(groupId));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:edit')")
@Log(title = "应付邮编配置", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody PayPostcodeGroup group)
{
return toAjax(payPostcodeService.updateGroup(group));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:query')")
@GetMapping("/line")
public TableDataInfo lines(PayPostcodeLine query)
{
startPage();
List<PayPostcodeLine> list = payPostcodeService.selectLineList(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:import')")
@Log(title = "应付邮编配置", businessType = BusinessType.IMPORT)
@PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public AjaxResult importExcel(MultipartFile file) throws Exception
{
if (file == null || file.isEmpty())
{
throw PaymentMesEnum.BMS_PAY_PICK_XLS.exception();
}
String name = file.getOriginalFilename() == null ? "" : file.getOriginalFilename().toLowerCase(Locale.ROOT);
if (!name.endsWith(".xlsx"))
{
throw PaymentMesEnum.BMS_PAY_XLSX_ONLY.exception();
}
return success(payPostcodeService.importExcel(file.getBytes(), file.getOriginalFilename(), getUsername()));
}
@PreAuthorize("@ss.hasPermi('data:payPostcode:remove')")
@Log(title = "应付邮编配置", businessType = BusinessType.DELETE)
@DeleteMapping("/{groupIds}")
public AjaxResult remove(@PathVariable Long[] groupIds)
{
return toAjax(payPostcodeService.deleteByIds(groupIds));
}
}
@@ -0,0 +1,96 @@
package com.bms.web.controller.masterdata;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.bms.common.annotation.Log;
import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.page.TableDataInfo;
import com.bms.common.enums.BusinessType;
import com.bms.common.utils.poi.ExcelUtil;
import com.bms.masterdata.domain.LineProduct;
import com.bms.masterdata.service.ILineProductService;
/**
* 路线产品管理(srv_line_product)
*/
@RestController
@RequestMapping("/masterdata/lineproduct")
public class LineProductController extends BaseController
{
@Autowired
private ILineProductService lineProductService;
@PreAuthorize("@ss.hasPermi('data:lineProduct:list')")
@GetMapping("/list")
public TableDataInfo list(LineProduct query)
{
startPage();
List<LineProduct> list = lineProductService.selectLineProductList(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('data:lineProduct:export')")
@Log(title = "路线产品", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, LineProduct query)
{
List<LineProduct> list = lineProductService.selectLineProductList(query);
ExcelUtil<LineProduct> util = new ExcelUtil<LineProduct>(LineProduct.class);
util.exportExcel(response, list, "路线产品");
}
@PreAuthorize("@ss.hasPermi('data:lineProduct:query')")
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable String id)
{
return success(lineProductService.selectLineProductById(id));
}
@PreAuthorize("@ss.hasPermi('data:lineProduct:add')")
@Log(title = "路线产品", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody LineProduct product)
{
String username = getUsername();
product.setCreateName(username);
product.setModifier(username);
return toAjax(lineProductService.insertLineProduct(product));
}
@PreAuthorize("@ss.hasPermi('data:lineProduct:edit')")
@Log(title = "路线产品", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody LineProduct product)
{
product.setModifier(getUsername());
return toAjax(lineProductService.updateLineProduct(product));
}
@PreAuthorize("@ss.hasPermi('data:lineProduct:edit')")
@Log(title = "路线产品", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestBody LineProduct product)
{
product.setModifier(getUsername());
return toAjax(lineProductService.updateLineProductStatus(product));
}
@PreAuthorize("@ss.hasPermi('data:lineProduct:remove')")
@Log(title = "路线产品", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable String[] ids)
{
return toAjax(lineProductService.deleteLineProductByIds(ids));
}
}
@@ -1,17 +1,29 @@
package com.bms.web.controller.masterdata;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.bms.common.annotation.Log;
import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.page.TableDataInfo;
import com.bms.common.enums.BusinessType;
import com.bms.common.utils.poi.ExcelUtil;
import com.bms.masterdata.domain.ServiceChannel;
import com.bms.masterdata.service.IServiceChannelService;
/**
* 服务渠道(老系统镜像 srv_service_channel)
* 渠道管理(srv_service_channel)
* 下拉选项仍走 /optionselect,登录即可,供供应商绑定渠道使用。
*
* @author bms
* @date 2026-10-12
@@ -23,6 +35,32 @@ public class ServiceChannelController extends BaseController
@Autowired
private IServiceChannelService serviceChannelService;
/**
* 分页查询渠道列表。
* 渠道编码、渠道名称、服务商编码、服务商名称、目的港/目的地区域、发货人名称均可检索,名称类条件为模糊匹配。
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:list')")
@GetMapping("/list")
public TableDataInfo list(ServiceChannel query)
{
startPage();
List<ServiceChannel> list = serviceChannelService.selectServiceChannelList(query);
return getDataTable(list);
}
/**
* 导出渠道列表,筛选条件与列表一致。
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:export')")
@Log(title = "渠道管理", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, ServiceChannel query)
{
List<ServiceChannel> list = serviceChannelService.selectServiceChannelList(query);
ExcelUtil<ServiceChannel> util = new ExcelUtil<ServiceChannel>(ServiceChannel.class);
util.exportExcel(response, list, "渠道数据");
}
/**
* 服务渠道下拉选项(非分页)。
* 供供应商绑定渠道等场景选择渠道;不做权限控制(仍需登录)。
@@ -33,4 +71,63 @@ public class ServiceChannelController extends BaseController
List<ServiceChannel> list = serviceChannelService.selectServiceChannelList(query);
return success(list);
}
/**
* 查询渠道详情
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:query')")
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable String id)
{
return success(serviceChannelService.selectServiceChannelById(id));
}
/**
* 新增渠道
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:add')")
@Log(title = "渠道管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody ServiceChannel channel)
{
String username = getUsername();
channel.setCreateName(username);
channel.setModifier(username);
return toAjax(serviceChannelService.insertServiceChannel(channel));
}
/**
* 修改渠道
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:edit')")
@Log(title = "渠道管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody ServiceChannel channel)
{
channel.setModifier(getUsername());
return toAjax(serviceChannelService.updateServiceChannel(channel));
}
/**
* 启用或停用渠道
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:edit')")
@Log(title = "渠道管理", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestBody ServiceChannel channel)
{
channel.setModifier(getUsername());
return toAjax(serviceChannelService.updateServiceChannelStatus(channel));
}
/**
* 删除渠道。已被产品渠道或供应商引用时不允许删除。
*/
@PreAuthorize("@ss.hasPermi('data:serviceChannel:remove')")
@Log(title = "渠道管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable String[] ids)
{
return toAjax(serviceChannelService.deleteServiceChannelByIds(ids));
}
}
@@ -24,7 +24,7 @@ import com.bms.price.enums.BillTaskSuccessStatus;
import com.bms.price.service.IPrcBillingTaskService;
/**
* Monitor: failed / waiting prc_billing_task list and manual resync.
* 监控:失败/等待中的 prc_billing_task 列表,以及手工重同步。
*/
@RestController
@RequestMapping("/monitor/billingTask")
@@ -33,7 +33,7 @@ public class BillingTaskMonitorController extends BaseController
@Autowired
private IPrcBillingTaskService billingTaskService;
/** Default list = FAILED abnormal tasks. */
/** 默认列表 = FAILED 异常任务。 */
@PreAuthorize("@ss.hasPermi('monitor:billingTask:list')")
@GetMapping("/list")
public TableDataInfo list(PrcBillingTask query)
@@ -58,7 +58,7 @@ public class BillingTaskMonitorController extends BaseController
return success(billingTaskService.getById(taskId));
}
/** Manual resync one task (reset WAITING then process). */
/** 手工重同步单个任务(先重置为 WAITING 再处理)。 */
@PreAuthorize("@ss.hasPermi('monitor:billingTask:retry')")
@Log(title = "billing task retry", businessType = BusinessType.UPDATE)
@PostMapping("/retry/{taskId}")
@@ -67,7 +67,7 @@ public class BillingTaskMonitorController extends BaseController
return success(billingTaskService.retryTask(taskId));
}
/** Manual resync selected tasks. */
/** 手工重同步选中的任务。 */
@PreAuthorize("@ss.hasPermi('monitor:billingTask:retry')")
@Log(title = "billing task batch retry", businessType = BusinessType.UPDATE)
@PostMapping("/retry")
@@ -116,8 +116,8 @@ public class BillingTaskMonitorController extends BaseController
}
/**
* Async resync by customer + bill_time (batched ID pages to avoid OOM).
* Returns asyncTaskId; poll {@code GET /retryTask/{asyncTaskId}}.
* 按客户 + 计费时间异步重同步(ID 分页批处理,避免 OOM)。
* 返回 asyncTaskId,通过 {@code GET /retryTask/{asyncTaskId}} 轮询进度。
*/
@PreAuthorize("@ss.hasPermi('monitor:billingTask:retry')")
@Log(title = "billing task filter retry", businessType = BusinessType.UPDATE)
@@ -17,7 +17,7 @@ import com.bms.price.search.BillSearchPage;
import com.bms.price.search.IBillSearchStore;
/**
* Generic Elasticsearch business-log viewer.
* 通用 Elasticsearch 业务日志查看。
*/
@RestController
@RequestMapping("/monitor/eslog")
@@ -39,7 +39,7 @@ public class EsLogController extends BaseController
BillSearchPage page = billSearchStore.search(logType, bizId, status, pageNum, pageSize);
TableDataInfo rsp = new TableDataInfo();
rsp.setCode(HttpStatus.SUCCESS);
rsp.setMsg("\u67e5\u8be2\u6210\u529f");
rsp.setMsg("查询成功");
rsp.setRows(page.getRows());
rsp.setTotal(page.getTotal());
return rsp;
@@ -0,0 +1,83 @@
package com.bms.web.controller.monitor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.bms.common.constant.HttpStatus;
import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.page.PageDomain;
import com.bms.common.core.page.TableDataInfo;
import com.bms.common.core.page.TableSupport;
import com.bms.price.search.BillSearchPage;
import com.bms.price.search.EsLogType;
import com.bms.price.search.IBillSearchStore;
import com.bms.price.search.PriceChangeGroupPage;
/**
* 来自 ES 的价格变更前后日志(销售价 / 产品价 / 红线价)。
*/
@RestController
@RequestMapping("/monitor/priceLog")
public class PriceLogController extends BaseController
{
@Autowired
private IBillSearchStore billSearchStore;
@PreAuthorize("@ss.hasPermi('monitor:priceLog:list')")
@GetMapping("/list")
public TableDataInfo list(
@RequestParam(value = "bizId", required = false) String bizId,
@RequestParam(value = "status", required = false) String status,
@RequestParam(value = "psvId", required = false) Long psvId,
@RequestParam(value = "priceKind", required = false) String priceKind,
@RequestParam(value = "productCode", required = false) String productCode,
@RequestParam(value = "updateTime", required = false) String updateTime,
@RequestParam(value = "updateTimePrefix", required = false) String updateTimePrefix,
@RequestParam(value = "countryKeyword", required = false) String countryKeyword)
{
PageDomain pageDomain = TableSupport.buildPageRequest();
int pageNum = pageDomain.getPageNum() == null ? 1 : pageDomain.getPageNum().intValue();
int pageSize = pageDomain.getPageSize() == null ? 10 : pageDomain.getPageSize().intValue();
BillSearchPage page = billSearchStore.search(EsLogType.PRICE_CHANGE, bizId, status, psvId, priceKind,
productCode, updateTime, updateTimePrefix, countryKeyword, pageNum, pageSize);
TableDataInfo rsp = new TableDataInfo();
rsp.setCode(HttpStatus.SUCCESS);
rsp.setMsg("查询成功");
rsp.setRows(page.getRows());
rsp.setTotal(page.getTotal());
return rsp;
}
/** 按 productCode + 写入时间分组,用于套餐版本下钻。 */
@PreAuthorize("@ss.hasPermi('monitor:priceLog:list')")
@GetMapping("/groups")
public TableDataInfo groups(
@RequestParam(value = "psvId", required = true) Long psvId,
@RequestParam(value = "status", required = false) String status,
@RequestParam(value = "priceKind", required = false) String priceKind)
{
PageDomain pageDomain = TableSupport.buildPageRequest();
int pageNum = pageDomain.getPageNum() == null ? 1 : pageDomain.getPageNum().intValue();
int pageSize = pageDomain.getPageSize() == null ? 10 : pageDomain.getPageSize().intValue();
PriceChangeGroupPage page = billSearchStore.searchPriceChangeGroups(psvId, priceKind, status, pageNum,
pageSize);
TableDataInfo rsp = new TableDataInfo();
rsp.setCode(HttpStatus.SUCCESS);
rsp.setMsg("查询成功");
rsp.setRows(page.getRows());
rsp.setTotal(page.getTotal());
return rsp;
}
@PreAuthorize("@ss.hasPermi('monitor:priceLog:list')")
@GetMapping("/{docId}")
public AjaxResult getInfo(@PathVariable("docId") String docId)
{
return success(billSearchStore.getByDocId(docId));
}
}
@@ -24,16 +24,29 @@ import com.bms.common.core.page.TableSupport;
import com.bms.common.enums.BusinessType;
import com.bms.common.utils.StringUtils;
import com.bms.price.domain.PrcBillingTaskRetryTask;
import com.bms.price.domain.vo.TabOrderCompareTask;
import com.bms.price.domain.vo.TabOrderMonitorQuery;
import com.bms.price.domain.vo.TabOrderMonitorVo;
import com.bms.price.domain.vo.TabOrderProductCheckResult;
import com.bms.price.oracle.CustomerKeywordResolver;
import com.bms.price.oracle.TabOrderPageResult;
import com.bms.price.oracle.TabOrderMonitorService;
import com.bms.price.oracle.TabOrderProductCheckService;
import com.bms.price.search.BillSearchPage;
import com.bms.price.search.EsLogType;
import com.bms.price.search.IBillSearchStore;
import com.bms.price.search.TabOrderSyncEsLog;
import com.bms.price.task.TabOrderCompareAsyncRunner;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import jakarta.servlet.http.HttpServletResponse;
import com.bms.common.config.BmsConfig;
import com.bms.common.utils.DateUtils;
import com.bms.common.utils.file.FileUtils;
import com.bms.common.utils.uuid.IdUtils;
import com.bms.price.domain.vo.TabOrderExportTask;
import com.bms.price.task.TabOrderExportAsyncRunner;
import com.bms.price.task.TabOrderSyncAsyncRunner;
/**
@@ -52,6 +65,12 @@ public class TabOrderMonitorController extends BaseController
@Autowired
private TabOrderSyncAsyncRunner tabOrderSyncAsyncRunner;
@Autowired
private TabOrderCompareAsyncRunner tabOrderCompareAsyncRunner;
@Autowired
private TabOrderExportAsyncRunner tabOrderExportAsyncRunner;
@Autowired
private IBillSearchStore billSearchStore;
@@ -61,10 +80,61 @@ public class TabOrderMonitorController extends BaseController
@PreAuthorize("@ss.hasPermi('monitor:orderSource:list')")
@GetMapping("/list")
public TableDataInfo list(TabOrderMonitorQuery query)
{
PageDomain pageDomain = TableSupport.buildPageRequest();
int pageNum = pageDomain.getPageNum() == null ? 1 : pageDomain.getPageNum().intValue();
int pageSize = pageDomain.getPageSize() == null ? 10 : pageDomain.getPageSize().intValue();
return listPage(query, pageNum, pageSize);
}
/**
* POST 查询支持较长的多单号筛选,避免把单号列表拼进 GET URL。
*/
@PreAuthorize("@ss.hasPermi('monitor:orderSource:list')")
@PostMapping("/list")
public TableDataInfo listPost(@RequestBody TabOrderMonitorQuery query,
@RequestParam(value = "pageNum", required = false) Integer pageNum,
@RequestParam(value = "pageSize", required = false) Integer pageSize)
{
return listPage(query, pageNum == null ? 1 : pageNum.intValue(),
pageSize == null ? 10 : pageSize.intValue());
}
/**
* 比对缺失转单号回填搜索专用:仅按转单号列查询,
* 不走普通列表/三列单号收集路径。
*/
@PreAuthorize("@ss.hasPermi('monitor:orderSource:list')")
@PostMapping("/listByTransferNos")
public TableDataInfo listByTransferNos(@RequestBody TabOrderMonitorQuery query,
@RequestParam(value = "pageNum", required = false) Integer pageNum,
@RequestParam(value = "pageSize", required = false) Integer pageSize)
{
TableDataInfo rsp = new TableDataInfo();
rsp.setCode(HttpStatus.SUCCESS);
rsp.setMsg("\u67e5\u8be2\u6210\u529f");
rsp.setMsg("查询成功");
if (query == null || !hasNonBlankItem(query.getOrderIdentifiers()))
{
rsp.setRows(Collections.emptyList());
rsp.setTotal(0L);
return rsp;
}
// 清空时间,避免共用解析器误复用按月时间窗口
query.setBeginTime(null);
query.setEndTime(null);
customerKeywordResolver.resolve(query);
TabOrderPageResult page = tabOrderMonitorService.searchPageByTransferNos(
query, pageNum == null ? 1 : pageNum.intValue(), pageSize == null ? 10 : pageSize.intValue());
rsp.setRows(page.getRows());
rsp.setTotal(page.getTotal());
return rsp;
}
private TableDataInfo listPage(TabOrderMonitorQuery query, int pageNum, int pageSize)
{
TableDataInfo rsp = new TableDataInfo();
rsp.setCode(HttpStatus.SUCCESS);
rsp.setMsg("查询成功");
if (!hasListFilters(query))
{
rsp.setRows(Collections.emptyList());
@@ -73,18 +143,53 @@ public class TabOrderMonitorController extends BaseController
}
// 在切换 Oracle 数据源之前,把客户名称解析为客户代码
customerKeywordResolver.resolve(query);
PageDomain pageDomain = TableSupport.buildPageRequest();
int pageNum = pageDomain.getPageNum() == null ? 1 : pageDomain.getPageNum().intValue();
int pageSize = pageDomain.getPageSize() == null ? 10 : pageDomain.getPageSize().intValue();
long total = tabOrderMonitorService.count(query);
List<TabOrderMonitorVo> rows = total <= 0L
? Collections.emptyList()
: tabOrderMonitorService.selectPage(query, pageNum, pageSize);
rsp.setRows(rows);
rsp.setTotal(total);
// 大批量单号场景一次收集即可同时得到总数和当前页,避免重复扫描 Oracle
TabOrderPageResult page = tabOrderMonitorService.searchPage(query, pageNum, pageSize);
rsp.setRows(page.getRows());
rsp.setTotal(page.getTotal());
return rsp;
}
/**
* 订单比对(异步):按客户+提货时间分页比对转单号(上游有/本地无)。
*/
@PreAuthorize("@ss.hasPermi('monitor:orderSource:list')")
@Log(title = "order source compare", businessType = BusinessType.OTHER)
@PostMapping("/compareByFilter")
public AjaxResult compareByFilter(@RequestBody TabOrderMonitorQuery query)
{
if (!hasRequiredFilters(query))
{
return error("订单比对需先选择客户和提货时间");
}
// 比对不受列表单号/回填影响
query.setOrderIdentifiers(null);
query.setOrderId(null);
query.setOrgOrderId(null);
query.setTransferOrderId(null);
customerKeywordResolver.resolve(query);
String asyncTaskId = UUID.randomUUID().toString().replace("-", "");
tabOrderCompareAsyncRunner.put(asyncTaskId, TabOrderCompareTask.STATUS_PENDING, 0, "queued",
0, 0, 0, null, null);
tabOrderCompareAsyncRunner.run(asyncTaskId, query);
Map<String, Object> data = new HashMap<String, Object>();
data.put("asyncTaskId", asyncTaskId);
TabOrderSyncEsLog.save(billSearchStore, asyncTaskId, "COMPARE", query, data, "SUCCESS", null);
return success(data);
}
@PreAuthorize("@ss.hasPermi('monitor:orderSource:list')")
@GetMapping("/compareTask/{asyncTaskId}")
public AjaxResult compareTaskProgress(@PathVariable("asyncTaskId") String asyncTaskId)
{
TabOrderCompareTask task = tabOrderCompareAsyncRunner.get(asyncTaskId);
if (task == null)
{
return error("compare task not found or expired");
}
return success(task);
}
@PreAuthorize("@ss.hasPermi('monitor:orderSource:list')")
@PostMapping("/checkProducts")
public AjaxResult checkProducts(@RequestBody TabOrderMonitorQuery query)
@@ -114,17 +219,22 @@ public class TabOrderMonitorController extends BaseController
return success(tabOrderMonitorService.selectOrderIdsByProduct(query));
}
@PreAuthorize("@ss.hasPermi('monitor:orderSource:sync')")
@PreAuthorize("@ss.hasPermi('monitor:orderSource:sync') or @ss.hasPermi('price:orderBill:rebill')")
@Log(title = "order source sync filter", businessType = BusinessType.UPDATE)
@PostMapping("/syncByFilter")
public AjaxResult syncByFilter(@RequestBody TabOrderMonitorQuery query)
{
if (!hasRequiredFilters(query))
// 仅覆盖上游字段(不触发计费)。筛选条件与列表查询一致。
if (!hasListFilters(query))
{
return error("customerCodes and pickup time required");
return error("orderIdentifiers or (customer and pickup time) required");
}
customerKeywordResolver.resolve(query);
tabOrderMonitorService.count(query);
// 含大批量单号时,异步任务启动时会自行分批收集,这里不预先 count,避免重复全量扫描
if (!hasNonBlankItem(query.getOrderIdentifiers()))
{
tabOrderMonitorService.count(query);
}
String asyncTaskId = UUID.randomUUID().toString().replace("-", "");
tabOrderSyncAsyncRunner.put(asyncTaskId, PrcBillingTaskRetryTask.STATUS_PENDING, 0, "queued",
0, 0, 0, 0, null);
@@ -135,7 +245,7 @@ public class TabOrderMonitorController extends BaseController
return success(data);
}
@PreAuthorize("@ss.hasPermi('monitor:orderSource:sync') or @ss.hasPermi('monitor:orderSource:list')")
@PreAuthorize("@ss.hasPermi('monitor:orderSource:sync') or @ss.hasPermi('monitor:orderSource:list') or @ss.hasPermi('price:orderBill:rebill')")
@GetMapping("/syncTask/{asyncTaskId}")
public AjaxResult syncTaskProgress(@PathVariable("asyncTaskId") String asyncTaskId)
{
@@ -147,7 +257,8 @@ public class TabOrderMonitorController extends BaseController
return success(task);
}
@PreAuthorize("@ss.hasPermi('monitor:orderSource:sync')")
/** 选中行:用 Oracle 数据覆盖本地账单字段;不做报价/重算。 */
@PreAuthorize("@ss.hasPermi('monitor:orderSource:sync') or @ss.hasPermi('price:orderBill:rebill')")
@Log(title = "order source sync selected", businessType = BusinessType.UPDATE)
@PostMapping("/sync")
public AjaxResult syncSelected(@RequestBody List<TabOrderMonitorVo> rows)
@@ -171,7 +282,7 @@ public class TabOrderMonitorController extends BaseController
return success(data);
}
@PreAuthorize("@ss.hasPermi('monitor:orderSource:list')")
@PreAuthorize("@ss.hasPermi('monitor:orderSource:list') or @ss.hasPermi('price:orderBill:list')")
@GetMapping("/syncLog/list")
public TableDataInfo syncLogList(
@RequestParam(value = "bizId", required = false) String bizId,
@@ -183,13 +294,13 @@ public class TabOrderMonitorController extends BaseController
BillSearchPage page = billSearchStore.search(EsLogType.ORDER_SOURCE_SYNC, bizId, status, pageNum, pageSize);
TableDataInfo rsp = new TableDataInfo();
rsp.setCode(HttpStatus.SUCCESS);
rsp.setMsg("\u67e5\u8be2\u6210\u529f");
rsp.setMsg("查询成功");
rsp.setRows(page.getRows());
rsp.setTotal(page.getTotal());
return rsp;
}
@PreAuthorize("@ss.hasPermi('monitor:orderSource:list')")
@PreAuthorize("@ss.hasPermi('monitor:orderSource:list') or @ss.hasPermi('price:orderBill:list')")
@GetMapping("/syncLog/{docId}")
public AjaxResult syncLogInfo(@PathVariable("docId") String docId)
{
@@ -207,13 +318,14 @@ public class TabOrderMonitorController extends BaseController
{
continue;
}
if (StringUtils.isNotEmpty(row.getOrderId()))
{
return prefix + "_" + row.getOrderId();
}
// 优先使用转单号作为 bizId(与 BILL / 上游同步 ES 一致)。
if (StringUtils.isNotEmpty(row.getTransferOrderId()))
{
return prefix + "_" + row.getTransferOrderId();
return prefix + "_" + row.getTransferOrderId().trim();
}
if (StringUtils.isNotEmpty(row.getOrderId()))
{
return prefix + "_" + row.getOrderId().trim();
}
}
}
@@ -223,6 +335,78 @@ public class TabOrderMonitorController extends BaseController
/**
* 列表查询:有任一单号即可查询;无单号时必须客户(名称或代码)+提货时间。
*/
/**
* 异步导出订单数源:按当前筛选(须有单号,或客户+提货时间)。
*/
@PreAuthorize("@ss.hasPermi('monitor:orderSource:export')")
@Log(title = "订单数源", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public AjaxResult export(@RequestBody(required = false) TabOrderMonitorQuery query)
{
if (query == null)
{
query = new TabOrderMonitorQuery();
}
if (!hasListFilters(query))
{
return error("请先设置列表查询条件后再导出");
}
customerKeywordResolver.resolve(query);
String taskId = IdUtils.fastSimpleUUID();
String fileName = "订单数源_" + DateUtils.dateTimeNow() + ".xlsx";
tabOrderExportAsyncRunner.put(taskId, TabOrderExportTask.STATUS_PENDING, 0, "queued", null,
fileName, null, 0);
tabOrderExportAsyncRunner.run(taskId, query, fileName);
Map<String, Object> data = new HashMap<String, Object>();
data.put("taskId", taskId);
return success(data);
}
@PreAuthorize("@ss.hasPermi('monitor:orderSource:export')")
@GetMapping("/export/task/{taskId}")
public AjaxResult exportTask(@PathVariable("taskId") String taskId)
{
TabOrderExportTask task = tabOrderExportAsyncRunner.get(taskId);
if (task == null)
{
return error("export task not found or expired");
}
return success(task);
}
@PreAuthorize("@ss.hasPermi('monitor:orderSource:export')")
@GetMapping("/export/download/{taskId}")
public void exportDownload(@PathVariable("taskId") String taskId, HttpServletResponse response)
throws Exception
{
TabOrderExportTask task = tabOrderExportAsyncRunner.get(taskId);
if (task == null)
{
throw new com.bms.common.exception.ServiceException("export task not found or expired");
}
if (!TabOrderExportTask.STATUS_SUCCESS.equals(task.getStatus())
|| StringUtils.isEmpty(task.getStorageKey()))
{
throw new com.bms.common.exception.ServiceException("export file not ready");
}
if (!FileUtils.checkAllowDownload(task.getStorageKey()))
{
throw new com.bms.common.exception.ServiceException("export file missing");
}
Path downloadRoot = Paths.get(BmsConfig.getDownloadPath()).toAbsolutePath().normalize();
Path filePath = downloadRoot.resolve(task.getStorageKey()).normalize();
if (!filePath.startsWith(downloadRoot) || !Files.isRegularFile(filePath))
{
throw new com.bms.common.exception.ServiceException("export file missing");
}
String fileName = StringUtils.isNotEmpty(task.getFileName()) ? task.getFileName() : (taskId + ".xlsx");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
FileUtils.setAttachmentResponseHeader(response, fileName);
FileUtils.writeBytes(filePath.toString(), response.getOutputStream());
}
private static boolean hasListFilters(TabOrderMonitorQuery query)
{
return hasRequiredFilters(query) || hasNonBlankItem(query.getOrderIdentifiers());
@@ -0,0 +1,106 @@
package com.bms.web.controller.monitor;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.bms.common.annotation.Log;
import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.page.TableDataInfo;
import com.bms.common.enums.BusinessType;
import com.bms.price.migration.domain.MigBiJobLog;
import com.bms.price.migration.service.IUuidToNewMonitorService;
/**
* 监控:UUID -> bigint 阴影同步进度与开关
*/
@RestController
@RequestMapping("/monitor/uuidToNew")
public class UuidToNewMonitorController extends BaseController
{
@Autowired
private IUuidToNewMonitorService monitorService;
@PreAuthorize("@ss.hasPermi('monitor:uuidToNew:list')")
@GetMapping("/progress")
public AjaxResult progress()
{
return success(monitorService.getProgress());
}
@PreAuthorize("@ss.hasPermi('monitor:uuidToNew:list')")
@GetMapping("/jobLog/list")
public TableDataInfo jobLogList(MigBiJobLog query)
{
startPage();
List<MigBiJobLog> list = monitorService.selectJobLogList(query);
return getDataTable(list);
}
/**
* 打开/关闭连续同步。
* body: { "enabled": true, "threadCount": 2, "batchSize": 200 }
*/
@PreAuthorize("@ss.hasPermi('monitor:uuidToNew:switch')")
@Log(title = "UUID阴影同步开关", businessType = BusinessType.UPDATE)
@PostMapping("/enabled")
public AjaxResult setEnabled(@RequestBody Map<String, Object> body)
{
boolean enabled = false;
Integer threadCount = null;
Integer batchSize = null;
if (body != null)
{
if (body.get("enabled") != null)
{
enabled = Boolean.parseBoolean(String.valueOf(body.get("enabled")));
}
threadCount = toInt(body.get("threadCount"));
batchSize = toInt(body.get("batchSize"));
}
monitorService.setEnabled(enabled, threadCount, batchSize);
return success(monitorService.getProgress());
}
/**
* 仅开关关闭时修改线程/批次。
* body: { "threadCount": 2, "batchSize": 200 }
*/
@PreAuthorize("@ss.hasPermi('monitor:uuidToNew:switch')")
@Log(title = "UUID阴影同步配置", businessType = BusinessType.UPDATE)
@PostMapping("/config")
public AjaxResult updateConfig(@RequestBody Map<String, Object> body)
{
Integer threadCount = null;
Integer batchSize = null;
if (body != null)
{
threadCount = toInt(body.get("threadCount"));
batchSize = toInt(body.get("batchSize"));
}
monitorService.updateRuntimeConfig(threadCount, batchSize);
return success(monitorService.getProgress());
}
private Integer toInt(Object v)
{
if (v == null || "".equals(String.valueOf(v).trim()))
{
return null;
}
try
{
return Integer.valueOf(String.valueOf(v).trim());
}
catch (Exception e)
{
return null;
}
}
}
@@ -0,0 +1,126 @@
package com.bms.web.controller.price;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.bms.common.annotation.Log;
import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.enums.BusinessType;
import com.bms.common.utils.poi.ExcelUtil;
import com.bms.price.airbill.domain.SrvBillAirFeeImportRow;
import com.bms.price.airbill.domain.SrvBillAirRoleFeeCommand;
import com.bms.price.airbill.domain.SrvBillAirRoleFeeQuery;
import com.bms.price.domain.vo.SrvBillAirQuery;
import com.bms.price.service.ISrvBillAirFeeService;
import com.bms.price.service.ISrvBillAirService;
/**
* 空运、报关、清关三个角色往提单上添加费用。
*/
@RestController
@RequestMapping("/price/airFee")
public class AirFeeRoleController extends BaseController
{
private static final int MAX_BILLS = 50;
@Autowired
private ISrvBillAirFeeService srvBillAirFeeService;
@Autowired
private ISrvBillAirService srvBillAirService;
/** 按提单号查出可绑定的提单,支持一次多选。 */
@PreAuthorize("@ss.hasAnyPermi('price:airFee:air,price:airFee:declare,price:airFee:clear')")
@GetMapping("/bills")
public AjaxResult bills(@RequestParam(value = "billCodes", required = false) String billCodes)
{
List<String> codes = splitCodes(billCodes);
if (codes.isEmpty())
{
return success(List.of());
}
if (codes.size() > MAX_BILLS)
{
return error("单次最多选择" + MAX_BILLS + "个提单");
}
SrvBillAirQuery query = new SrvBillAirQuery();
query.setBillCodes(codes);
return success(srvBillAirService.selectSrvBillAirList(query));
}
/** 查询已绑定到这些提单、且属于当前入口的费用。 */
@PreAuthorize("@ss.hasAnyPermi('price:airFee:air,price:airFee:declare,price:airFee:clear')")
@GetMapping("/list")
public AjaxResult list(@RequestParam("scene") String scene, @RequestParam(value = "billCodes", required = false) String billCodes)
{
SrvBillAirRoleFeeQuery query = new SrvBillAirRoleFeeQuery();
query.setScene(scene);
query.setBillCodes(splitCodes(billCodes));
return success(srvBillAirFeeService.listRoleFees(query));
}
/** 保存当前入口的费用。空运写入 b 段,报关和清关写入 c 段。 */
@PreAuthorize("@ss.hasAnyPermi('price:airFee:air,price:airFee:declare,price:airFee:clear')")
@Log(title = "提单角色费用", businessType = BusinessType.UPDATE)
@PostMapping("/save")
public AjaxResult save(@RequestBody SrvBillAirRoleFeeCommand command)
{
return success(srvBillAirFeeService.saveRole(command));
}
/** 下载导入模板,模板中带一行示例。 */
@PreAuthorize("@ss.hasAnyPermi('price:airFee:air,price:airFee:declare,price:airFee:clear')")
@PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response)
{
SrvBillAirFeeImportRow example = new SrvBillAirFeeImportRow();
example.setFeeName("燃油附加费");
example.setPrice(new BigDecimal("1000"));
example.setCurrency("EUR");
example.setRemark("导入时需清空这行示例数据");
List<SrvBillAirFeeImportRow> rows = new ArrayList<>();
rows.add(example);
new ExcelUtil<>(SrvBillAirFeeImportRow.class).exportExcel(response, rows, "提单费用导入模板");
}
/** 解析导入文件,不直接落库。示例行会被跳过。 */
@PreAuthorize("@ss.hasAnyPermi('price:airFee:air,price:airFee:declare,price:airFee:clear')")
@Log(title = "提单角色费用导入", businessType = BusinessType.IMPORT)
@PostMapping("/import")
public AjaxResult importFee(MultipartFile file, @RequestParam("scene") String scene) throws Exception
{
if (file == null || file.isEmpty())
{
return error("请选择导入文件");
}
return success(srvBillAirFeeService.parseImport(scene, file.getInputStream()));
}
private static List<String> splitCodes(String billCodes)
{
LinkedHashSet<String> codes = new LinkedHashSet<>();
if (billCodes != null)
{
for (String part : billCodes.split("[,,\\s]+"))
{
if (part != null && !part.isBlank())
{
codes.add(part.trim());
}
}
}
return new ArrayList<>(codes);
}
}