| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- package com.smqjh.agent.mcp;
- import com.fasterxml.jackson.databind.node.ArrayNode;
- import com.fasterxml.jackson.databind.node.ObjectNode;
- import java.time.LocalDate;
- import java.time.format.DateTimeFormatter;
- import java.util.List;
- import java.util.Locale;
- final class MonthlySettlementPlanner {
- private static final List<Enterprise> ENTERPRISES = List.of(
- new Enterprise(54, "1", "招商银行贵阳分行"),
- new Enterprise(55, "2", "中数未来"),
- new Enterprise(58, "5", "铜仁移动")
- );
- ObjectNode plan(String enterpriseInput, String month) {
- Enterprise enterprise = findEnterprise(enterpriseInput);
- if (enterprise == null) {
- throw new IllegalArgumentException("未找到月结企业: " + enterpriseInput);
- }
- LocalDate start = parseMonth(month);
- LocalDate end = start.plusMonths(1);
- ObjectNode root = Jsons.object();
- root.put("title", enterprise.name() + " " + month + " 月结处理计划");
- root.put("enterpriseName", enterprise.name());
- root.put("channelId", enterprise.channelId());
- root.put("channelNo", enterprise.channelNo());
- root.put("month", month);
- root.put("startTime", start + " 00:00:00");
- root.put("endTime", end + " 00:00:00");
- root.put("settlementScope", "企业用户定时月结;所有已付款订单;逻辑删除订单不参与。");
- ArrayNode exportRows = exports(enterprise, start, end);
- root.set("columns", Jsons.MAPPER.valueToTree(new String[] {"name", "method", "adminEndpoint", "params", "backendEvidence", "note"}));
- root.set("rows", exportRows);
- root.set("exports", exportRows);
- root.set("rules", rules());
- root.set("invoiceStates", invoiceStates());
- root.put("adminTenantRule", "顶级 admin 登录/调用不需要 tenantCode;非 admin 仍需要 tenantCode 或租户上下文。");
- root.put("mcpUsage", "后续可由 Agent 先调用本工具生成计划,再调用导出接口、只读 SQL 和 Excel 处理工具生成结算报告。");
- return root;
- }
- ObjectNode enterprises() {
- ObjectNode root = Jsons.object();
- ArrayNode rows = Jsons.MAPPER.createArrayNode();
- for (Enterprise enterprise : ENTERPRISES) {
- ObjectNode row = Jsons.object();
- row.put("channelId", enterprise.channelId());
- row.put("channelNo", enterprise.channelNo());
- row.put("enterpriseName", enterprise.name());
- row.put("settlementType", "企业用户定时月结");
- row.put("scope", "所有已付款订单,排除逻辑删除订单");
- rows.add(row);
- }
- root.put("title", "月结企业清单");
- root.set("columns", Jsons.MAPPER.valueToTree(new String[] {"channelId", "channelNo", "enterpriseName", "settlementType", "scope"}));
- root.set("rows", rows);
- root.put("rowCount", rows.size());
- root.put("note", "来自管理员确认的 sm_channel 月结企业配置;顶级 admin 不需要 tenantCode。");
- return root;
- }
- private ArrayNode exports(Enterprise enterprise, LocalDate start, LocalDate end) {
- ArrayNode exports = Jsons.MAPPER.createArrayNode();
- exports.add(exportSpec(
- "员工列表积分情况",
- "GET",
- "/plt/admin/enterprise/export",
- "channelIdList[0]=" + enterprise.channelId(),
- "业务代码证据:smqjh-system /api/v1/members/enterprise/export;积分充值表 sm_points_recharge;会员表 sm_member。",
- "用于员工、手机号、充值积分、消费积分、可用积分核对;汇总时按 user_id + channel_id。"
- ));
- exports.add(exportSpec(
- "订单表",
- "GET/POST",
- "/plt/platform/order/export",
- "channelIdList[0]=" + enterprise.channelId() + "&orderStatus=all&startTime=" + start + "%2000:00:00&endTime=" + end + "%2000:00:00",
- "业务代码证据:OrderController POST /api/v1/order/export?exportType=ORDER;OmsOrderMapper.exportOrderList;oms_order。",
- "导出后需要按 is_payed=1 和 COALESCE(delete_status,0)=0 口径核对,金额差异标记需人工确认。"
- ));
- exports.add(exportSpec(
- "商品订单表",
- "GET/POST",
- "/plt/platform/order/export",
- "channelIdList[0]=" + enterprise.channelId() + "&orderStatus=all&exportType=PRODUCT&startTime=" + start + "%2000:00:00&endTime=" + end + "%2000:00:00",
- "业务代码证据:OrderController POST /api/v1/order/export?exportType=PRODUCT;OmsOrderMapper.exportProductList;oms_order_item + tz_sku。",
- "从商品表补齐海博编码、商品编码、SKU 编码;汇总商品总额、数量和规格。"
- ));
- exports.add(exportSpec(
- "运费账单表",
- "GET",
- "/plt/platform/sku/freightStatisticsExcel",
- "channelIds[0]=" + enterprise.channelId(),
- "业务代码证据:运费导出入口由后台提供;优先按订单号和配送单号与 oms_order 关联。",
- "汇总总运费;订单号无法关联或金额不一致时标记需人工确认。"
- ));
- exports.add(exportSpec(
- "对账汇总表模板",
- "GET",
- "/plt/platform/sku/skuStatisticsExcel",
- "channelIds[0]=" + enterprise.channelId(),
- "业务代码证据:后台对账汇总导出模板;Agent 负责补充汇总公式和蓝色核对区。",
- "业务系统导出的模板本身可用,但缺少自动汇总计算和小蓝表核对区。"
- ));
- return exports;
- }
- private ObjectNode exportSpec(String name, String method, String endpoint, String params, String evidence, String note) {
- ObjectNode item = Jsons.object();
- item.put("name", name);
- item.put("method", method);
- item.put("adminEndpoint", endpoint);
- item.put("params", params);
- item.put("backendEvidence", evidence);
- item.put("note", note);
- return item;
- }
- private ArrayNode rules() {
- ArrayNode rules = Jsons.MAPPER.createArrayNode();
- rules.add("商品总额 = 已付款商品订单明细小计汇总。");
- rules.add("总运费 = 运费账单按订单号或配送单号匹配后汇总。");
- rules.add("负数积分抵扣表示充值转换为积分后的抵扣金额。");
- rules.add("商品金额、运费、积分抵扣、现金支付任意差异不为 0,标记为“需人工确认”。");
- rules.add("只标记差异,不自动修改业务系统数据。");
- rules.add("结算报告生成后发送客户核对,再打印盖章、开电子发票、等待客户付款。");
- return rules;
- }
- private ArrayNode invoiceStates() {
- ArrayNode states = Jsons.MAPPER.createArrayNode();
- states.add("待客户核对");
- states.add("待打印盖章");
- states.add("待开电子发票");
- states.add("待客户付款");
- states.add("已完成");
- return states;
- }
- private Enterprise findEnterprise(String input) {
- String normalized = input == null ? "" : input.trim().toLowerCase(Locale.ROOT);
- return ENTERPRISES.stream()
- .filter(item -> item.name().toLowerCase(Locale.ROOT).contains(normalized)
- || item.channelNo().equals(normalized)
- || String.valueOf(item.channelId()).equals(normalized))
- .findFirst()
- .orElse(null);
- }
- private LocalDate parseMonth(String month) {
- if (month == null || !month.matches("\\d{4}-\\d{2}")) {
- throw new IllegalArgumentException("month 必须是 YYYY-MM");
- }
- return LocalDate.parse(month + "-01", DateTimeFormatter.ISO_LOCAL_DATE);
- }
- private record Enterprise(int channelId, String channelNo, String name) {
- }
- }
|