diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueProjectOrderInfoController.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueProjectOrderInfoController.java index 8df4bcff..d172a98c 100644 --- a/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueProjectOrderInfoController.java +++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/vue/VueProjectOrderInfoController.java @@ -152,7 +152,7 @@ public class VueProjectOrderInfoController extends BaseController { @PostMapping("/export") public AjaxResult export(@RequestBody ProjectOrderInfo projectOrderInfo) { // 在Vue前端,通常是先调用这个接口生成文件,拿到文件名,然后再通过/common/download接口下载 - String fileName = projectOrderInfoService.exportList(projectOrderInfo); + String fileName = projectOrderInfoService.exportMcpList(projectOrderInfo); return AjaxResult.success(fileName); } } diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/OmsInventoryInner.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/OmsInventoryInner.java index b1cd121b..37140d62 100644 --- a/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/OmsInventoryInner.java +++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/OmsInventoryInner.java @@ -79,5 +79,6 @@ public class OmsInventoryInner extends BaseEntity { private BigDecimal taxTotal; private Long itemId; private List productTypeList; + private List orderCodeList; private List inventoryInfoList; } diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectInfo.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectInfo.java index 9e79eb96..e29c925e 100644 --- a/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectInfo.java +++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectInfo.java @@ -27,6 +27,7 @@ public class ProjectInfo extends BaseEntity /** */ private Long id; private String ids; + private String orderCode; /** 项目编码 */ @Excel(name = "项目编号") diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/llm/tools/OutboundOrderInventoryInfoToolProvider.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/llm/tools/OutboundOrderInventoryInfoToolProvider.java index c4d527fa..a869e37a 100644 --- a/ruoyi-sip/src/main/java/com/ruoyi/sip/llm/tools/OutboundOrderInventoryInfoToolProvider.java +++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/llm/tools/OutboundOrderInventoryInfoToolProvider.java @@ -1,217 +1,217 @@ -package com.ruoyi.sip.llm.tools; - -import com.ruoyi.sip.domain.InventoryInfo; -import com.ruoyi.sip.domain.InventoryOuter; -import com.ruoyi.sip.domain.ProductInfo; -import com.ruoyi.sip.llm.tools.support.AbstractMcpToolProvider; -import com.ruoyi.sip.service.IInventoryInfoService; -import com.ruoyi.sip.service.IInventoryOuterService; -import com.ruoyi.sip.service.IProductInfoService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -@Component -public class OutboundOrderInventoryInfoToolProvider extends AbstractMcpToolProvider { - - @Autowired - private IInventoryInfoService inventoryInfoService; - - @Autowired - private IInventoryOuterService inventoryOuterService; - - @Autowired - private IProductInfoService productInfoService; - - @Override - protected String getToolName() { - return "outbound_order_inventory_info"; - } - - @Override - protected String getToolDescription() { - return "Batch query barcode and price details by outbound order codes."; - } - - @Override - protected Map buildInputSchema() { - Map outerCodeListProperty = new LinkedHashMap<>(); - outerCodeListProperty.put("type", "array"); - outerCodeListProperty.put("description", "Outbound order code list."); - outerCodeListProperty.put("items", stringProperty("Outbound order code")); - outerCodeListProperty.put("minItems", 1); - - Map properties = new LinkedHashMap<>(); - properties.put("outer_code_list", outerCodeListProperty); - return objectSchema(properties, "outer_code_list"); - } - - @Override - protected Object handle(Map params) { - List outerCodeList = getStringList(params, "outer_code_list"); - if (outerCodeList.isEmpty()) { - throw new RuntimeException("outer_code_list is required"); - } - - List inventoryOuters = loadInventoryOuters(outerCodeList); - Map productNameMap = loadProductNameMap(inventoryOuters); - Map> inventoryInfoMap = loadInventoryInfoMap(outerCodeList); - - List> items = new ArrayList<>(); - for (InventoryOuter inventoryOuter : inventoryOuters) { - items.add(toOutboundOrderItem(inventoryOuter, productNameMap, inventoryInfoMap)); - } - - Map query = new LinkedHashMap<>(); - query.put("outer_code_list", outerCodeList); - - Map data = new LinkedHashMap<>(); - data.put("total", items.size()); - data.put("items", items); - - Map metadata = new LinkedHashMap<>(); - metadata.put("tool", getToolName()); - metadata.put("description", "Batch query outbound-order barcode details from oms_inventory_info."); - metadata.put("query_fields", mapOf( - "outer_code_list", "Outbound order code list" - )); - metadata.put("data_fields", mapOf( - "total", "Matched outbound orders count", - "items", "Outbound order detail list" - )); - metadata.put("item_fields", mapOf( - "outboundOrderCode", "Outbound order code", - "orderCode", "Order code", - "productCode", "Product code", - "productName", "Product name", - "quantity", "Outbound quantity", - "inventoryCount", "Barcode detail count", - "inventoryInfos", "Barcode detail list" - )); - metadata.put("inventory_info_fields", mapOf( - "productSn", "Barcode / serial number", - "innerPrice", "Inner price", - "outerPrice", "Outer price", - "taxRate", "Tax rate" - )); - - return response(metadata, query, data); - } - - private List loadInventoryOuters(List outerCodeList) { - InventoryOuter query = new InventoryOuter(); - query.setOuterCodeList(outerCodeList); - List inventoryOuters = inventoryOuterService.selectInventoryOuterList(query); - if (inventoryOuters == null || inventoryOuters.isEmpty()) { - return Collections.emptyList(); - } - - Map outerMap = inventoryOuters.stream().collect(Collectors.toMap( - InventoryOuter::getOuterCode, - item -> item, - (first, second) -> first, - LinkedHashMap::new - )); - - List ordered = new ArrayList<>(); - for (String outerCode : outerCodeList) { - InventoryOuter inventoryOuter = outerMap.get(outerCode); - if (inventoryOuter != null) { - ordered.add(inventoryOuter); - } - } - return ordered; - } - - private Map loadProductNameMap(List inventoryOuters) { - if (inventoryOuters == null || inventoryOuters.isEmpty()) { - return Collections.emptyMap(); - } - - Set productCodes = inventoryOuters.stream() - .map(InventoryOuter::getProductCode) - .filter(code -> !isBlank(code)) - .collect(Collectors.toCollection(LinkedHashSet::new)); - if (productCodes.isEmpty()) { - return Collections.emptyMap(); - } - - List productInfos = productInfoService.selectProductInfoByCodeList(new ArrayList<>(productCodes)); - if (productInfos == null || productInfos.isEmpty()) { - return Collections.emptyMap(); - } - return productInfos.stream().collect(Collectors.toMap(ProductInfo::getProductCode, ProductInfo::getProductName, (a, b) -> a)); - } - - private Map> loadInventoryInfoMap(List outerCodeList) { - List inventoryInfos = inventoryInfoService.selectInventoryInfoByOuterCodeList(outerCodeList); - if (inventoryInfos == null || inventoryInfos.isEmpty()) { - return Collections.emptyMap(); - } - return inventoryInfos.stream() - .filter(item -> !isBlank(item.getOuterCode())) - .collect(Collectors.groupingBy(InventoryInfo::getOuterCode, LinkedHashMap::new, Collectors.toList())); - } - - private Map toOutboundOrderItem(InventoryOuter inventoryOuter, - Map productNameMap, - Map> inventoryInfoMap) { - List inventoryInfos = inventoryInfoMap.get(inventoryOuter.getOuterCode()); - List> inventoryInfoItems = new ArrayList<>(); - if (inventoryInfos != null) { - for (InventoryInfo inventoryInfo : inventoryInfos) { - inventoryInfoItems.add(toInventoryInfoItem(inventoryInfo)); - } - } - - Map item = new LinkedHashMap<>(); - item.put("outboundOrderCode", inventoryOuter.getOuterCode()); - item.put("orderCode", inventoryOuter.getOrderCode()); - item.put("productCode", inventoryOuter.getProductCode()); - item.put("productName", productNameMap.get(inventoryOuter.getProductCode())); - item.put("quantity", inventoryOuter.getQuantity()); - item.put("inventoryCount", inventoryInfoItems.size()); - item.put("inventoryInfos", inventoryInfoItems); - return item; - } - - private Map toInventoryInfoItem(InventoryInfo inventoryInfo) { - Map item = new LinkedHashMap<>(); - item.put("productSn", inventoryInfo.getProductSn()); - item.put("innerPrice", inventoryInfo.getInnerPrice()); - item.put("outerPrice", inventoryInfo.getOuterPrice()); - item.put("taxRate", inventoryInfo.getTaxRate()); - return item; - } - - private List getStringList(Map params, String key) { - if (params == null) { - return Collections.emptyList(); - } - Object value = params.get(key); - if (!(value instanceof List)) { - return Collections.emptyList(); - } - - List rawList = (List) value; - List result = new ArrayList<>(); - for (Object raw : rawList) { - if (raw == null) { - continue; - } - String item = String.valueOf(raw).trim(); - if (!item.isEmpty()) { - result.add(item); - } - } - return result; - } -} +//package com.ruoyi.sip.llm.tools; +// +//import com.ruoyi.sip.domain.InventoryInfo; +//import com.ruoyi.sip.domain.InventoryOuter; +//import com.ruoyi.sip.domain.ProductInfo; +//import com.ruoyi.sip.llm.tools.support.AbstractMcpToolProvider; +//import com.ruoyi.sip.service.IInventoryInfoService; +//import com.ruoyi.sip.service.IInventoryOuterService; +//import com.ruoyi.sip.service.IProductInfoService; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.stereotype.Component; +// +//import java.util.ArrayList; +//import java.util.Collections; +//import java.util.LinkedHashMap; +//import java.util.LinkedHashSet; +//import java.util.List; +//import java.util.Map; +//import java.util.Set; +//import java.util.stream.Collectors; +// +//@Component +//public class OutboundOrderInventoryInfoToolProvider extends AbstractMcpToolProvider { +// +// @Autowired +// private IInventoryInfoService inventoryInfoService; +// +// @Autowired +// private IInventoryOuterService inventoryOuterService; +// +// @Autowired +// private IProductInfoService productInfoService; +// +// @Override +// protected String getToolName() { +// return "outbound_order_inventory_info"; +// } +// +// @Override +// protected String getToolDescription() { +// return "Batch query barcode and price details by outbound order codes."; +// } +// +// @Override +// protected Map buildInputSchema() { +// Map outerCodeListProperty = new LinkedHashMap<>(); +// outerCodeListProperty.put("type", "array"); +// outerCodeListProperty.put("description", "Outbound order code list."); +// outerCodeListProperty.put("items", stringProperty("Outbound order code")); +// outerCodeListProperty.put("minItems", 1); +// +// Map properties = new LinkedHashMap<>(); +// properties.put("outer_code_list", outerCodeListProperty); +// return objectSchema(properties, "outer_code_list"); +// } +// +// @Override +// protected Object handle(Map params) { +// List outerCodeList = getStringList(params, "outer_code_list"); +// if (outerCodeList.isEmpty()) { +// throw new RuntimeException("outer_code_list is required"); +// } +// +// List inventoryOuters = loadInventoryOuters(outerCodeList); +// Map productNameMap = loadProductNameMap(inventoryOuters); +// Map> inventoryInfoMap = loadInventoryInfoMap(outerCodeList); +// +// List> items = new ArrayList<>(); +// for (InventoryOuter inventoryOuter : inventoryOuters) { +// items.add(toOutboundOrderItem(inventoryOuter, productNameMap, inventoryInfoMap)); +// } +// +// Map query = new LinkedHashMap<>(); +// query.put("outer_code_list", outerCodeList); +// +// Map data = new LinkedHashMap<>(); +// data.put("total", items.size()); +// data.put("items", items); +// +// Map metadata = new LinkedHashMap<>(); +// metadata.put("tool", getToolName()); +// metadata.put("description", "Batch query outbound-order barcode details from oms_inventory_info."); +// metadata.put("query_fields", mapOf( +// "outer_code_list", "Outbound order code list" +// )); +// metadata.put("data_fields", mapOf( +// "total", "Matched outbound orders count", +// "items", "Outbound order detail list" +// )); +// metadata.put("item_fields", mapOf( +// "outboundOrderCode", "Outbound order code", +// "orderCode", "Order code", +// "productCode", "Product code", +// "productName", "Product name", +// "quantity", "Outbound quantity", +// "inventoryCount", "Barcode detail count", +// "inventoryInfos", "Barcode detail list" +// )); +// metadata.put("inventory_info_fields", mapOf( +// "productSn", "Barcode / serial number", +// "innerPrice", "Inner price", +// "outerPrice", "Outer price", +// "taxRate", "Tax rate" +// )); +// +// return response(metadata, query, data); +// } +// +// private List loadInventoryOuters(List outerCodeList) { +// InventoryOuter query = new InventoryOuter(); +// query.setOuterCodeList(outerCodeList); +// List inventoryOuters = inventoryOuterService.selectInventoryOuterList(query); +// if (inventoryOuters == null || inventoryOuters.isEmpty()) { +// return Collections.emptyList(); +// } +// +// Map outerMap = inventoryOuters.stream().collect(Collectors.toMap( +// InventoryOuter::getOuterCode, +// item -> item, +// (first, second) -> first, +// LinkedHashMap::new +// )); +// +// List ordered = new ArrayList<>(); +// for (String outerCode : outerCodeList) { +// InventoryOuter inventoryOuter = outerMap.get(outerCode); +// if (inventoryOuter != null) { +// ordered.add(inventoryOuter); +// } +// } +// return ordered; +// } +// +// private Map loadProductNameMap(List inventoryOuters) { +// if (inventoryOuters == null || inventoryOuters.isEmpty()) { +// return Collections.emptyMap(); +// } +// +// Set productCodes = inventoryOuters.stream() +// .map(InventoryOuter::getProductCode) +// .filter(code -> !isBlank(code)) +// .collect(Collectors.toCollection(LinkedHashSet::new)); +// if (productCodes.isEmpty()) { +// return Collections.emptyMap(); +// } +// +// List productInfos = productInfoService.selectProductInfoByCodeList(new ArrayList<>(productCodes)); +// if (productInfos == null || productInfos.isEmpty()) { +// return Collections.emptyMap(); +// } +// return productInfos.stream().collect(Collectors.toMap(ProductInfo::getProductCode, ProductInfo::getProductName, (a, b) -> a)); +// } +// +// private Map> loadInventoryInfoMap(List outerCodeList) { +// List inventoryInfos = inventoryInfoService.selectInventoryInfoByOuterCodeList(outerCodeList); +// if (inventoryInfos == null || inventoryInfos.isEmpty()) { +// return Collections.emptyMap(); +// } +// return inventoryInfos.stream() +// .filter(item -> !isBlank(item.getOuterCode())) +// .collect(Collectors.groupingBy(InventoryInfo::getOuterCode, LinkedHashMap::new, Collectors.toList())); +// } +// +// private Map toOutboundOrderItem(InventoryOuter inventoryOuter, +// Map productNameMap, +// Map> inventoryInfoMap) { +// List inventoryInfos = inventoryInfoMap.get(inventoryOuter.getOuterCode()); +// List> inventoryInfoItems = new ArrayList<>(); +// if (inventoryInfos != null) { +// for (InventoryInfo inventoryInfo : inventoryInfos) { +// inventoryInfoItems.add(toInventoryInfoItem(inventoryInfo)); +// } +// } +// +// Map item = new LinkedHashMap<>(); +// item.put("outboundOrderCode", inventoryOuter.getOuterCode()); +// item.put("orderCode", inventoryOuter.getOrderCode()); +// item.put("productCode", inventoryOuter.getProductCode()); +// item.put("productName", productNameMap.get(inventoryOuter.getProductCode())); +// item.put("quantity", inventoryOuter.getQuantity()); +// item.put("inventoryCount", inventoryInfoItems.size()); +// item.put("inventoryInfos", inventoryInfoItems); +// return item; +// } +// +// private Map toInventoryInfoItem(InventoryInfo inventoryInfo) { +// Map item = new LinkedHashMap<>(); +// item.put("productSn", inventoryInfo.getProductSn()); +// item.put("innerPrice", inventoryInfo.getInnerPrice()); +// item.put("outerPrice", inventoryInfo.getOuterPrice()); +// item.put("taxRate", inventoryInfo.getTaxRate()); +// return item; +// } +// +// private List getStringList(Map params, String key) { +// if (params == null) { +// return Collections.emptyList(); +// } +// Object value = params.get(key); +// if (!(value instanceof List)) { +// return Collections.emptyList(); +// } +// +// List rawList = (List) value; +// List result = new ArrayList<>(); +// for (Object raw : rawList) { +// if (raw == null) { +// continue; +// } +// String item = String.valueOf(raw).trim(); +// if (!item.isEmpty()) { +// result.add(item); +// } +// } +// return result; +// } +//} diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/llm/tools/ProjectOrderInfoToolProvider.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/llm/tools/ProjectOrderInfoToolProvider.java index 4b3a2b7e..3bdc746e 100644 --- a/ruoyi-sip/src/main/java/com/ruoyi/sip/llm/tools/ProjectOrderInfoToolProvider.java +++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/llm/tools/ProjectOrderInfoToolProvider.java @@ -1,18 +1,33 @@ package com.ruoyi.sip.llm.tools; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.DictUtils; +import com.ruoyi.sip.domain.InventoryInfo; import com.ruoyi.sip.domain.InventoryOuter; -import com.ruoyi.sip.domain.ProductInfo; +import com.ruoyi.sip.domain.OmsInventoryInner; +import com.ruoyi.sip.domain.OmsPurchaseOrderItem; +import com.ruoyi.sip.domain.OmsReceivableBill; +import com.ruoyi.sip.domain.ProjectInfo; import com.ruoyi.sip.domain.ProjectOrderInfo; +import com.ruoyi.sip.domain.ProjectProductInfo; import com.ruoyi.sip.llm.tools.support.AbstractMcpToolProvider; +import com.ruoyi.sip.mapper.InventoryInfoMapper; +import com.ruoyi.sip.mapper.OmsInventoryInnerMapper; +import com.ruoyi.sip.mapper.OmsPurchaseOrderMapper; +import com.ruoyi.sip.mapper.ProjectInfoMapper; +import com.ruoyi.sip.service.IInventoryInfoService; import com.ruoyi.sip.service.IInventoryOuterService; -import com.ruoyi.sip.service.IProductInfoService; +import com.ruoyi.sip.service.IOmsReceivableBillService; import com.ruoyi.sip.service.IProjectOrderInfoService; +import com.ruoyi.sip.service.IProjectProductInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.LinkedHashMap; @@ -25,58 +40,37 @@ import java.util.stream.Collectors; @Component public class ProjectOrderInfoToolProvider extends AbstractMcpToolProvider { - private static final List FIXED_ITEM_KEYS = Arrays.asList( - "projectCode", - "orderDate", - "orderEffectiveDate", - "requiredDeliveryDate", - "orderCode", - "projectName", - "agentName", - "ownerName", - "orderChannel", - "supplierName", - "customerName", - "bgName", - "industryType", - "projectPartnerName", - "businessContactName", - "businessContactPhone", - "currencyType", - "partnerName", - "partnerLevel", - "partnerContactName", - "partnerContactPhone", - "executionDeadline", - "archiveTime", - "wssQuantity", - "wssAmount", - "wssTaxRate", - "wspQuantity", - "wspAmount", - "wspTaxRate", - "lsQuantity", - "lsAmount", - "lsTaxRate" - ); - - private static final List TAIL_ITEM_KEYS = Arrays.asList( - "shipmentAmount", - "totalAmount", - "maintenanceAmount", - "softwareSubtotal", - "hardwareSubtotal", - "serviceSubtotal" - ); + private static final String INDUSTRY_TYPE_DICT_TYPE = "bg_hysy"; + private static final String INDUSTRY_TYPE_YYS_DICT_TYPE = "bg_yys"; + private static final String PROJECT_STAGE_DICT_TYPE = "project_stage"; + private static final String NOT_DELIVERED_TEXT = "未发货完成"; @Autowired private IProjectOrderInfoService projectOrderInfoService; + @Autowired + private IProjectProductInfoService projectProductInfoService; + @Autowired private IInventoryOuterService inventoryOuterService; @Autowired - private IProductInfoService productInfoService; + private IInventoryInfoService inventoryInfoService; + + @Autowired + private InventoryInfoMapper inventoryInfoMapper; + + @Autowired + private OmsInventoryInnerMapper omsInventoryInnerMapper; + + @Autowired + private OmsPurchaseOrderMapper omsPurchaseOrderMapper; + + @Autowired + private ProjectInfoMapper projectInfoMapper; + + @Autowired + private IOmsReceivableBillService omsReceivableBillService; @Override protected String getToolName() { @@ -108,156 +102,569 @@ public class ProjectOrderInfoToolProvider extends AbstractMcpToolProvider { queryCondition.setCreateTimeStart(parseDateTime(createTimeStart)); queryCondition.setCreateTimeEnd(parseDateTime(createTimeEnd)); - List> exportRows = projectOrderInfoService.listExportData(queryCondition); - Map>> outboundOrderMap = loadOutboundOrderMap(exportRows); - - List> items = new ArrayList<>(); - for (Map exportRow : exportRows) { - items.add(attachExtraInfo(exportRow, outboundOrderMap)); + List> items = listItems(queryCondition); + if (CollUtil.isEmpty(items)) { + Map data = new LinkedHashMap<>(); + data.put("total", 0); + data.put("items", Collections.emptyList()); + return response(buildMetadata(), mapOf( + "create_time_start", createTimeStart, + "create_time_end", createTimeEnd + ), data); } - Map query = mapOf( - "create_time_start", createTimeStart, - "create_time_end", createTimeEnd - ); - Map data = new LinkedHashMap<>(); data.put("total", items.size()); data.put("items", items); - Map metadata = new LinkedHashMap<>(); - metadata.put("tool", getToolName()); - metadata.put("description", "根据创建时间范围查询项目订单信息,data.items 使用英文驼峰字段返回"); - metadata.put("query_fields", mapOf( - "create_time_start", "创建时间范围开始,包含边界", - "create_time_end", "创建时间范围结束,包含边界" - )); - metadata.put("data_fields", mapOf( - "total", "命中的项目订单数量", - "items", "项目订单列表,字段键已统一为英文驼峰" - )); - metadata.put("item_fields", buildItemFieldMetadata()); - metadata.put("dynamic_field_rules", mapOf( - "details", "产品明细列表", - "outboundOrders", "出库单列表" - )); - metadata.put("detail_fields", mapOf( - "productCode", "产品编码", - "model", "型号", - "quantity", "数量", - "amount", "金额", - "taxRate", "税率" - )); - metadata.put("outbound_order_fields", mapOf( - "outboundOrderCode", "出库单号", - "productCode", "产品编码", - "productName", "产品名称", - "quantity", "数量" - )); - - return response(metadata, query, data); + return response(buildMetadata(), mapOf( + "create_time_start", createTimeStart, + "create_time_end", createTimeEnd + ), data); } - private Map attachExtraInfo(Map exportRow, - Map>> outboundOrderMap) { - Map result = toCamelCaseItem(exportRow); - String orderCode = stringValue(exportRow.get("_order_code")); - List> outboundOrders = outboundOrderMap.get(orderCode); - result.put("outboundOrders", outboundOrders == null ? Collections.emptyList() : outboundOrders); - return result; + public List> listItems(ProjectOrderInfo queryCondition) { + if (queryCondition == null) { + queryCondition = new ProjectOrderInfo(); + } + List orderInfos = projectOrderInfoService.selectProjectOrderInfoList(queryCondition); + if (CollUtil.isEmpty(orderInfos)) { + return Collections.emptyList(); + } + + List orderCodes = orderInfos.stream() + .map(ProjectOrderInfo::getOrderCode) + .filter(code -> !isBlank(code)) + .distinct() + .collect(Collectors.toList()); + Map> productMap = loadProductMap(orderInfos); + PurchaseTaxRateContext purchaseTaxRateContext = loadPurchaseTaxRateContext(orderCodes); + Map> shipmentSummaryMap = loadShipmentSummaryMap(orderCodes, purchaseTaxRateContext); + Map> serviceCostMap = loadServiceCostMap(purchaseTaxRateContext); + Map receivableSummaryMap = loadReceivableSummaryMap(orderInfos); + Map projectInfoMap = loadProjectInfoMap(orderCodes); + + List> items = new ArrayList<>(); + for (ProjectOrderInfo orderInfo : orderInfos) { + items.add(buildItem(orderInfo, productMap, shipmentSummaryMap, serviceCostMap, receivableSummaryMap, projectInfoMap)); + } + return items; } - private Map toCamelCaseItem(Map exportRow) { - List values = new ArrayList<>(); - for (Map.Entry entry : exportRow.entrySet()) { - if ("_order_code".equals(entry.getKey()) || "_project_id".equals(entry.getKey())) { - continue; - } - values.add(entry.getValue()); + private Map buildItem(ProjectOrderInfo orderInfo, + Map> productMap, + Map> shipmentSummaryMap, + Map> serviceCostMap, + Map receivableSummaryMap, + Map projectInfoMap) { + List productInfos = productMap.getOrDefault(orderInfo.getProjectId(), Collections.emptyList()); + List softwareList = filterByType(productInfos, "1"); + List hardwareList = filterByType(productInfos, "2"); + List serviceList = filterByType(productInfos, "3"); + + Map orderShipmentMap = shipmentSummaryMap.getOrDefault(orderInfo.getOrderCode(), Collections.emptyMap()); + ReceivableSummary receivableSummary = receivableSummaryMap.getOrDefault(orderInfo.getOrderCode(), new ReceivableSummary()); + ProjectInfo projectInfo = projectInfoMap.get(orderInfo.getOrderCode()); + + Map item = new LinkedHashMap<>(); + item.put("projectStage", getProjectStage(projectInfo)); + item.put("orderDate", formatDate(orderInfo.getEstimatedOrderTime())); + item.put("orderEffectiveDate", formatDate(orderInfo.getApproveTime())); + item.put("requiredDeliveryDate", formatDate(orderInfo.getDeliveryTime())); + item.put("contractCode", orderInfo.getOrderCode()); + item.put("projectName", orderInfo.getProjectName()); + item.put("agentName", orderInfo.getAgentName()); + item.put("orderStatus", DictUtils.getDictLabel("order_status", orderInfo.getOrderStatus())); + item.put("ownerName", orderInfo.getDutyName()); + item.put("orderChannel", getOrderChannelName(orderInfo.getOrderChannel())); + item.put("supplierName", orderInfo.getSupplier()); + item.put("customerName", orderInfo.getCustomerName()); + item.put("bgName", DictUtils.getDictLabel("bg_type", orderInfo.getBgProperty())); + item.put("industryType", getIndustryTypeName(orderInfo)); + item.put("constructionType", ""); + item.put("projectPartnerName", orderInfo.getProjectPartnerName()); + item.put("businessContactName", orderInfo.getBusinessPerson()); + item.put("businessContactPhone", orderInfo.getBusinessPhone()); + item.put("currencyType", DictUtils.getDictLabel("currency_type", orderInfo.getCurrencyType())); + item.put("partnerName", orderInfo.getPartnerName()); + item.put("partnerLevel", DictUtils.getDictLabel("identify_level", orderInfo.getLevel())); + item.put("partnerContactName", orderInfo.getPartnerUserName()); + item.put("partnerContactPhone", orderInfo.getPartnerPhone()); + item.put("executionDeadline", formatDate(orderInfo.getOrderEndTime())); + item.put("archiveTime", formatDateTime(orderInfo.getApproveTime())); + + ProductGroupSummary softwareSummary = appendProductFields(item, "software", softwareList, + orderShipmentMap, Collections.emptyMap(), true); + ProductGroupSummary hardwareSummary = appendProductFields(item, "hardware", hardwareList, + orderShipmentMap, Collections.emptyMap(), true); + ProductGroupSummary serviceSummary = appendProductFields(item, "service", serviceList, + Collections.emptyMap(), serviceCostMap.getOrDefault(orderInfo.getOrderCode(), Collections.emptyMap()), false); + + BigDecimal orderAmountWithTax = defaultValue(orderInfo.getShipmentAmount()); + BigDecimal discountAmountWithTax = softwareSummary.salesWithTax + .add(hardwareSummary.salesWithTax) + .add(serviceSummary.salesWithTax); + BigDecimal discountAmountWithoutTax = softwareSummary.salesWithoutTax + .add(hardwareSummary.salesWithoutTax) + .add(serviceSummary.salesWithoutTax); + boolean allDelivered = softwareSummary.allDelivered && hardwareSummary.allDelivered && serviceSummary.allDelivered; + BigDecimal costWithTax = softwareSummary.costWithTax.add(hardwareSummary.costWithTax).add(serviceSummary.costWithTax); + BigDecimal costWithoutTax = softwareSummary.costWithoutTax.add(hardwareSummary.costWithoutTax).add(serviceSummary.costWithoutTax); + + item.put("orderAmountWithTax", orderAmountWithTax); + item.put("discountedOrderAmountWithTax", discountAmountWithTax); + item.put("discountedOrderAmountWithoutTax", discountAmountWithoutTax); + item.put("costTotalWithTax", allDelivered ? costWithTax : NOT_DELIVERED_TEXT); + item.put("costTotalWithoutTax", allDelivered ? costWithoutTax : NOT_DELIVERED_TEXT); + + if (allDelivered) { + BigDecimal grossProfit = discountAmountWithoutTax.subtract(costWithoutTax); + item.put("grossProfit", grossProfit); + item.put("grossProfitRate", percentage(grossProfit, costWithoutTax)); + } else { + item.put("grossProfit", NOT_DELIVERED_TEXT); + item.put("grossProfitRate", NOT_DELIVERED_TEXT); } - Map result = new LinkedHashMap<>(); - int fixedCount = Math.min(FIXED_ITEM_KEYS.size(), values.size()); - for (int i = 0; i < fixedCount; i++) { - result.put(FIXED_ITEM_KEYS.get(i), values.get(i)); - } - - int detailStart = fixedCount; - int detailEnd = Math.max(detailStart, values.size() - TAIL_ITEM_KEYS.size()); - List> details = new ArrayList<>(); - for (int i = detailStart; i + 4 < detailEnd; i += 5) { - Map detail = new LinkedHashMap<>(); - detail.put("productCode", values.get(i)); - detail.put("model", values.get(i + 1)); - detail.put("quantity", values.get(i + 2)); - detail.put("amount", values.get(i + 3)); - detail.put("taxRate", values.get(i + 4)); - if (!isEmptyDetail(detail)) { - details.add(detail); - } - } - result.put("details", details); - - int tailStart = Math.max(detailEnd, values.size() - TAIL_ITEM_KEYS.size()); - for (int i = 0; i < TAIL_ITEM_KEYS.size() && tailStart + i < values.size(); i++) { - result.put(TAIL_ITEM_KEYS.get(i), values.get(tailStart + i)); - } - return result; + item.put("deliveryTime", collectDeliveryTimes(orderShipmentMap)); + item.put("expectedReceiptAmount", receivableSummary.totalPriceWithTax); + item.put("receivedAmount", receivableSummary.receivedAmount); + item.put("isCharged", isCharged(orderInfo.getChargeStatus())); + return item; } - private Map>> loadOutboundOrderMap(List> exportRows) { - if (exportRows == null || exportRows.isEmpty()) { + private Map> loadProductMap(List orderInfos) { + List projectIds = orderInfos.stream() + .map(ProjectOrderInfo::getProjectId) + .filter(id -> id != null) + .distinct() + .collect(Collectors.toList()); + if (CollUtil.isEmpty(projectIds)) { return Collections.emptyMap(); } + List productInfos = projectProductInfoService.selectProjectProductInfoListByProjectId(projectIds); + if (CollUtil.isEmpty(productInfos)) { + return Collections.emptyMap(); + } + return productInfos.stream().collect(Collectors.groupingBy(ProjectProductInfo::getProjectId, LinkedHashMap::new, Collectors.toList())); + } - Set orderCodes = exportRows.stream() - .map(row -> stringValue(row.get("_order_code"))) - .filter(code -> !isBlank(code)) - .collect(Collectors.toCollection(LinkedHashSet::new)); - if (orderCodes.isEmpty()) { + private Map> loadShipmentSummaryMap(List orderCodes, + PurchaseTaxRateContext purchaseTaxRateContext) { + if (CollUtil.isEmpty(orderCodes)) { return Collections.emptyMap(); } InventoryOuter query = new InventoryOuter(); - query.setOrderCodeList(new ArrayList<>(orderCodes)); + query.setOrderCodeList(orderCodes); List inventoryOuters = inventoryOuterService.selectInventoryOuterList(query); - if (inventoryOuters == null || inventoryOuters.isEmpty()) { + if (CollUtil.isEmpty(inventoryOuters)) { return Collections.emptyMap(); } - Set productCodes = inventoryOuters.stream() - .map(InventoryOuter::getProductCode) + List outerCodes = inventoryOuters.stream() + .map(InventoryOuter::getOuterCode) .filter(code -> !isBlank(code)) - .collect(Collectors.toCollection(LinkedHashSet::new)); - Map productNameMap = loadProductNameMap(productCodes); + .distinct() + .collect(Collectors.toList()); + Map> inventoryInfoMap = Collections.emptyMap(); + if (CollUtil.isNotEmpty(outerCodes)) { + List inventoryInfos = inventoryInfoService.selectInventoryInfoByOuterCodeList(outerCodes); + if (CollUtil.isNotEmpty(inventoryInfos)) { + inventoryInfoMap = inventoryInfos.stream() + .filter(item -> !isBlank(item.getOuterCode())) + .collect(Collectors.groupingBy(InventoryInfo::getOuterCode, LinkedHashMap::new, Collectors.toList())); + } + } - Map>> result = new LinkedHashMap<>(); + Map> result = new LinkedHashMap<>(); for (InventoryOuter inventoryOuter : inventoryOuters) { - String orderCode = inventoryOuter.getOrderCode(); - if (isBlank(orderCode)) { + if (isBlank(inventoryOuter.getOrderCode()) || isBlank(inventoryOuter.getProductCode())) { continue; } - result.computeIfAbsent(orderCode, key -> new ArrayList<>()) - .add(toOutboundOrderItem(inventoryOuter, productNameMap)); + Map productMap = result.computeIfAbsent(inventoryOuter.getOrderCode(), key -> new LinkedHashMap<>()); + ProductShipmentSummary summary = productMap.computeIfAbsent(inventoryOuter.getProductCode(), key -> new ProductShipmentSummary()); + summary.quantity = summary.quantity.add(BigDecimal.valueOf(inventoryOuter.getQuantity() == null ? 0L : inventoryOuter.getQuantity())); + if (inventoryOuter.getDeliveryTime() != null) { + summary.deliveryTimes.add(inventoryOuter.getDeliveryTime()); + } + List inventoryInfos = inventoryInfoMap.getOrDefault(inventoryOuter.getOuterCode(), Collections.emptyList()); + for (InventoryInfo inventoryInfo : inventoryInfos) { + BigDecimal innerPrice = defaultValue(inventoryInfo.getInnerPrice()); + summary.costWithTax = summary.costWithTax.add(innerPrice); + summary.costWithoutTax = summary.costWithoutTax.add(toInventoryAmountWithoutTax( + innerPrice, + purchaseTaxRateContext.resolveTaxRate(inventoryInfo.getInnerCode(), inventoryInfo.getProductCode()) + )); + } } return result; } - private Map toOutboundOrderItem(InventoryOuter inventoryOuter, Map productNameMap) { - Map item = new LinkedHashMap<>(); - item.put("outboundOrderCode", inventoryOuter.getOuterCode()); - item.put("productCode", inventoryOuter.getProductCode()); - item.put("productName", productNameMap.get(inventoryOuter.getProductCode())); - item.put("quantity", inventoryOuter.getQuantity()); - return item; - } - - private Map loadProductNameMap(Set productCodes) { - if (productCodes == null || productCodes.isEmpty()) { + private Map> loadServiceCostMap(PurchaseTaxRateContext purchaseTaxRateContext) { + List inventoryInners = purchaseTaxRateContext.listInventoryInnersByProductType("3"); + if (CollUtil.isEmpty(inventoryInners)) { return Collections.emptyMap(); } - List productInfos = productInfoService.selectProductInfoByCodeList(new ArrayList<>(productCodes)); - return productInfos.stream().collect(Collectors.toMap(ProductInfo::getProductCode, ProductInfo::getProductName, (a, b) -> a)); + + List innerCodes = inventoryInners.stream() + .map(OmsInventoryInner::getInnerCode) + .filter(code -> !isBlank(code)) + .distinct() + .collect(Collectors.toList()); + Map> innerInventoryInfoMap = Collections.emptyMap(); + if (CollUtil.isNotEmpty(innerCodes)) { + List inventoryInfos = inventoryInfoMapper.selectInventoryInfoByInnerCodeList(innerCodes); + if (CollUtil.isNotEmpty(inventoryInfos)) { + innerInventoryInfoMap = inventoryInfos.stream() + .filter(item -> !isBlank(item.getInnerCode())) + .collect(Collectors.groupingBy(InventoryInfo::getInnerCode, LinkedHashMap::new, Collectors.toList())); + } + } + + Map> result = new LinkedHashMap<>(); + for (OmsInventoryInner inventoryInner : inventoryInners) { + if (isBlank(inventoryInner.getOrderCode()) || isBlank(inventoryInner.getProductCode())) { + continue; + } + List inventoryInfos = innerInventoryInfoMap.getOrDefault(inventoryInner.getInnerCode(), Collections.emptyList()); + Map productMap = result.computeIfAbsent(inventoryInner.getOrderCode(), key -> new LinkedHashMap<>()); + ProductCostSummary summary = productMap.computeIfAbsent(inventoryInner.getProductCode(), key -> new ProductCostSummary()); + summary.costWithTax = summary.costWithTax.add(resolveServiceCostWithTax(inventoryInner, inventoryInfos)); + summary.costWithoutTax = summary.costWithoutTax.add( + resolveServiceCostWithoutTax(inventoryInner, inventoryInfos, purchaseTaxRateContext) + ); + } + return result; + } + + private BigDecimal resolveServiceCostWithTax(OmsInventoryInner inventoryInner, List inventoryInfos) { + if (inventoryInner.getTotalAmount() != null) { + return inventoryInner.getTotalAmount(); + } + if (CollUtil.isEmpty(inventoryInfos)) { + return BigDecimal.ZERO; + } + return inventoryInfos.stream() + .map(InventoryInfo::getInnerPrice) + .filter(value -> value != null) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + private BigDecimal resolveServiceCostWithoutTax(OmsInventoryInner inventoryInner, + List inventoryInfos, + PurchaseTaxRateContext purchaseTaxRateContext) { + BigDecimal taxRate = purchaseTaxRateContext.resolveTaxRate(inventoryInner.getInnerCode(), inventoryInner.getProductCode()); + if (CollUtil.isNotEmpty(inventoryInfos)) { + BigDecimal total = BigDecimal.ZERO; + for (InventoryInfo inventoryInfo : inventoryInfos) { + BigDecimal innerPrice = defaultValue(inventoryInfo.getInnerPrice()); + total = total.add(toInventoryAmountWithoutTax(innerPrice, taxRate)); + } + if (total.compareTo(BigDecimal.ZERO) > 0 || inventoryInner.getTotalAmount() == null) { + return total; + } + } + return toInventoryAmountWithoutTax(defaultValue(inventoryInner.getTotalAmount()), taxRate); + } + + private Map loadReceivableSummaryMap(List orderInfos) { + List orderCodes = orderInfos.stream() + .map(ProjectOrderInfo::getOrderCode) + .filter(code -> !isBlank(code)) + .distinct() + .collect(Collectors.toList()); + if (CollUtil.isEmpty(orderCodes)) { + return Collections.emptyMap(); + } + + OmsReceivableBill query = new OmsReceivableBill(); + query.setOrderCodeList(orderCodes); + List receivableBills = omsReceivableBillService.selectOmsReceivableBillList(query); + if (CollUtil.isEmpty(receivableBills)) { + return Collections.emptyMap(); + } + + Map result = new LinkedHashMap<>(); + for (OmsReceivableBill receivableBill : receivableBills) { + if (isBlank(receivableBill.getOrderCode())) { + continue; + } + ReceivableSummary summary = result.computeIfAbsent(receivableBill.getOrderCode(), key -> new ReceivableSummary()); + summary.totalPriceWithTax = summary.totalPriceWithTax.add(defaultValue(receivableBill.getTotalPriceWithTax())); + summary.receivedAmount = summary.receivedAmount.add(defaultValue(receivableBill.getReceivedAmount())); + } + return result; + } + + private Map loadProjectInfoMap(List orderCodes) { + if (CollUtil.isEmpty(orderCodes)) { + return Collections.emptyMap(); + } + List projectInfos = projectInfoMapper.selectProjectInfoByOrderCodeList(orderCodes); + if (CollUtil.isEmpty(projectInfos)) { + return Collections.emptyMap(); + } + Map result = new LinkedHashMap<>(); + for (ProjectInfo projectInfo : projectInfos) { + if (projectInfo == null || isBlank(projectInfo.getOrderCode()) || result.containsKey(projectInfo.getOrderCode())) { + continue; + } + result.put(projectInfo.getOrderCode(), projectInfo); + } + return result; + } + + private PurchaseTaxRateContext loadPurchaseTaxRateContext(List orderCodes) { + if (CollUtil.isEmpty(orderCodes)) { + return new PurchaseTaxRateContext(Collections.emptyMap(), Collections.emptyList(), Collections.emptyMap()); + } + InventoryOuter outerQuery = new InventoryOuter(); + outerQuery.setOrderCodeList(orderCodes); + List inventoryOuters = inventoryOuterService.selectInventoryOuterList(outerQuery); + + List shippedInnerCodes = Collections.emptyList(); + if (CollUtil.isNotEmpty(inventoryOuters)) { + List outerCodes = inventoryOuters.stream() + .map(InventoryOuter::getOuterCode) + .filter(code -> !isBlank(code)) + .distinct() + .collect(Collectors.toList()); + if (CollUtil.isNotEmpty(outerCodes)) { + List shippedInventoryInfos = inventoryInfoService.selectInventoryInfoByOuterCodeList(outerCodes); + if (CollUtil.isNotEmpty(shippedInventoryInfos)) { + shippedInnerCodes = shippedInventoryInfos.stream() + .map(InventoryInfo::getInnerCode) + .filter(code -> !isBlank(code)) + .distinct() + .collect(Collectors.toList()); + } + } + } + + List inventoryInners = new ArrayList<>(); + if (CollUtil.isNotEmpty(shippedInnerCodes)) { + inventoryInners.addAll(omsInventoryInnerMapper.selectOmsInventoryInnerByInnerCodeList(shippedInnerCodes)); + } + List serviceInventoryInners = omsInventoryInnerMapper.selectOmsInventoryInnerByOrderCodeList(orderCodes); + if (CollUtil.isNotEmpty(serviceInventoryInners)) { + serviceInventoryInners.stream() + .filter(item -> "3".equals(item.getProductType())) + .forEach(inventoryInners::add); + } + if (CollUtil.isEmpty(inventoryInners)) { + return new PurchaseTaxRateContext(Collections.emptyMap(), Collections.emptyList(), Collections.emptyMap()); + } + Map innerCodeMap = new LinkedHashMap<>(); + List uniqueInventoryInners = new ArrayList<>(); + for (OmsInventoryInner inventoryInner : inventoryInners) { + if (inventoryInner == null || isBlank(inventoryInner.getInnerCode()) || innerCodeMap.containsKey(inventoryInner.getInnerCode())) { + continue; + } + innerCodeMap.put(inventoryInner.getInnerCode(), inventoryInner); + uniqueInventoryInners.add(inventoryInner); + } + List purchaseNos = uniqueInventoryInners.stream() + .map(OmsInventoryInner::getPurchaseNo) + .filter(code -> !isBlank(code)) + .distinct() + .collect(Collectors.toList()); + Map> purchaseTaxRateMap = Collections.emptyMap(); + if (CollUtil.isNotEmpty(purchaseNos)) { + List purchaseOrderItems = omsPurchaseOrderMapper.listItemByCodeList(purchaseNos); + if (CollUtil.isNotEmpty(purchaseOrderItems)) { + purchaseTaxRateMap = new LinkedHashMap<>(); + for (OmsPurchaseOrderItem purchaseOrderItem : purchaseOrderItems) { + if (isBlank(purchaseOrderItem.getPurchaseNo()) || isBlank(purchaseOrderItem.getProductCode())) { + continue; + } + Map productTaxRateMap = purchaseTaxRateMap.computeIfAbsent( + purchaseOrderItem.getPurchaseNo(), + key -> new LinkedHashMap<>() + ); + BigDecimal currentTaxRate = productTaxRateMap.get(purchaseOrderItem.getProductCode()); + BigDecimal candidateTaxRate = purchaseOrderItem.getTaxRate(); + if (candidateTaxRate != null && (currentTaxRate == null || currentTaxRate.compareTo(BigDecimal.ZERO) == 0)) { + productTaxRateMap.put(purchaseOrderItem.getProductCode(), candidateTaxRate); + } else if (currentTaxRate == null) { + productTaxRateMap.put(purchaseOrderItem.getProductCode(), BigDecimal.ZERO); + } + } + } + } + return new PurchaseTaxRateContext(innerCodeMap, uniqueInventoryInners, purchaseTaxRateMap); + } + + private ProductGroupSummary appendProductFields(Map item, + String prefix, + List productInfos, + Map shipmentMap, + Map serviceCostMap, + boolean shipmentRequired) { + ProductGroupSummary summary = new ProductGroupSummary(); + if (CollUtil.isEmpty(productInfos)) { + return summary; + } + for (int i = 0; i < productInfos.size(); i++) { + int index = i + 1; + ProjectProductInfo productInfo = productInfos.get(i); + ProductCostDisplay costDisplay = shipmentRequired + ? buildShipmentProductCostDisplay(productInfo, shipmentMap.get(productInfo.getProductBomCode())) + : buildServiceProductCostDisplay(serviceCostMap.get(productInfo.getProductBomCode())); + + item.put(prefix + "Code" + index, productInfo.getProductBomCode()); + item.put(prefix + "Level2Type" + index, productInfo.getLevel2Type()); + item.put(prefix + "Model" + index, productInfo.getModel()); + item.put(prefix + "Quantity" + index, productInfo.getQuantity()); + item.put(prefix + "SalesAmount" + index, defaultValue(productInfo.getAllPrice())); + item.put(prefix + "CostAmount" + index, costDisplay.displayValue); + item.put(prefix + "TaxRate" + index, productInfo.getTaxRate()); + + summary.salesWithTax = summary.salesWithTax.add(defaultValue(productInfo.getAllPrice())); + summary.salesWithoutTax = summary.salesWithoutTax.add(toOrderAmountWithoutTax(defaultValue(productInfo.getAllPrice()), productInfo.getTaxRate())); + if (costDisplay.delivered) { + summary.costWithTax = summary.costWithTax.add(costDisplay.costWithTax); + summary.costWithoutTax = summary.costWithoutTax.add(costDisplay.costWithoutTax); + } else { + summary.allDelivered = false; + } + } + return summary; + } + + private ProductCostDisplay buildShipmentProductCostDisplay(ProjectProductInfo productInfo, ProductShipmentSummary shipmentSummary) { + ProductCostDisplay display = new ProductCostDisplay(); + BigDecimal requiredQuantity = BigDecimal.valueOf(productInfo.getQuantity() == null ? 0L : productInfo.getQuantity()); + BigDecimal shippedQuantity = shipmentSummary == null ? BigDecimal.ZERO : shipmentSummary.quantity; + if (requiredQuantity.compareTo(BigDecimal.ZERO) <= 0) { + display.delivered = true; + display.displayValue = BigDecimal.ZERO; + return display; + } + if (shipmentSummary == null || shippedQuantity.compareTo(requiredQuantity) < 0) { + display.delivered = false; + display.displayValue = NOT_DELIVERED_TEXT; + return display; + } + display.delivered = true; + display.costWithTax = shipmentSummary.costWithTax; + display.costWithoutTax = shipmentSummary.costWithoutTax; + display.displayValue = shipmentSummary.costWithTax; + return display; + } + + private ProductCostDisplay buildServiceProductCostDisplay(ProductCostSummary serviceCostSummary) { + ProductCostDisplay display = new ProductCostDisplay(); + display.delivered = true; + if (serviceCostSummary == null) { + display.displayValue = BigDecimal.ZERO; + return display; + } + display.costWithTax = serviceCostSummary.costWithTax; + display.costWithoutTax = serviceCostSummary.costWithoutTax; + display.displayValue = serviceCostSummary.costWithTax; + return display; + } + + private List filterByType(List productInfos, String type) { + if (CollUtil.isEmpty(productInfos)) { + return Collections.emptyList(); + } + return productInfos.stream() + .filter(item -> type.equals(item.getType())) + .collect(Collectors.toList()); + } + + private String collectDeliveryTimes(Map shipmentMap) { + if (shipmentMap == null || shipmentMap.isEmpty()) { + return ""; + } + Set dates = new LinkedHashSet<>(); + for (ProductShipmentSummary summary : shipmentMap.values()) { + for (Date deliveryTime : summary.deliveryTimes) { + dates.add(formatDate(deliveryTime)); + } + } + return String.join(", ", dates); + } + + private String getProjectStage(ProjectInfo projectInfo) { + if (projectInfo == null) { + return ""; + } + return DictUtils.getDictLabel(PROJECT_STAGE_DICT_TYPE, projectInfo.getProjectStage()); + } + + private String getIndustryTypeName(ProjectOrderInfo orderInfo) { + if ("YYS".equals(orderInfo.getBgProperty())) { + return DictUtils.getDictLabel(INDUSTRY_TYPE_YYS_DICT_TYPE, orderInfo.getIndustryType()); + } + return DictUtils.getDictLabel(INDUSTRY_TYPE_DICT_TYPE, orderInfo.getIndustryType()); + } + + private String getOrderChannelName(String orderChannel) { + if (isBlank(orderChannel)) { + return ""; + } + if (ProjectOrderInfo.OrderChannelEnum.TOTAL_GENERATION.getCode().equals(orderChannel)) { + return "总代"; + } + if (ProjectOrderInfo.OrderChannelEnum.DIRECT_SIGNING.getCode().equals(orderChannel)) { + return "直签"; + } + return orderChannel; + } + + private String isCharged(String chargeStatus) { + return "2".equals(chargeStatus) || "3".equals(chargeStatus) ? "是" : "否"; + } + + private BigDecimal toOrderAmountWithoutTax(BigDecimal amountWithTax, BigDecimal taxRate) { + BigDecimal rate = normalizePercentTaxRate(taxRate); + return amountWithTax.divide(BigDecimal.ONE.add(rate), 2, RoundingMode.HALF_UP); + } + + private BigDecimal toInventoryAmountWithoutTax(BigDecimal amountWithTax, BigDecimal taxRate) { + BigDecimal rate = normalizeDecimalTaxRate(taxRate); + return amountWithTax.divide(BigDecimal.ONE.add(rate), 2, RoundingMode.HALF_UP); + } + + private BigDecimal normalizePercentTaxRate(BigDecimal taxRate) { + if (taxRate == null) { + return BigDecimal.ZERO; + } + if (taxRate.compareTo(BigDecimal.ONE) > 0) { + return taxRate.divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP); + } + return taxRate; + } + + private BigDecimal normalizeDecimalTaxRate(BigDecimal taxRate) { + if (taxRate == null) { + return BigDecimal.ZERO; + } + return taxRate.compareTo(BigDecimal.ONE) > 0 + ? taxRate.divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP) + : taxRate; + } + + private BigDecimal percentage(BigDecimal numerator, BigDecimal denominator) { + if (denominator == null || denominator.compareTo(BigDecimal.ZERO) == 0) { + return BigDecimal.ZERO; + } + return numerator.divide(denominator, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")); + } + + private BigDecimal defaultValue(BigDecimal value) { + return value == null ? BigDecimal.ZERO : value; + } + + private String formatDate(Date value) { + return value == null ? "" : DateUtil.format(value, "yyyy-MM-dd"); + } + + private String formatDateTime(Date value) { + return value == null ? "" : DateUtil.format(value, "yyyy-MM-dd HH:mm:ss"); } private Date parseDateTime(String value) { @@ -280,64 +687,138 @@ public class ProjectOrderInfoToolProvider extends AbstractMcpToolProvider { } } - private String stringValue(Object value) { - return value == null ? null : String.valueOf(value); - } - - private boolean isEmptyDetail(Map detail) { - if (detail == null || detail.isEmpty()) { - return true; - } - for (Object value : detail.values()) { - if (value != null && !isBlank(String.valueOf(value))) { - return false; - } - } - return true; + private Map buildMetadata() { + Map metadata = new LinkedHashMap<>(); + metadata.put("tool", getToolName()); + metadata.put("description", "根据创建时间范围查询项目订单信息,data.items 使用英文驼峰字段返回。"); + metadata.put("query_fields", mapOf( + "create_time_start", "创建时间范围开始,包含边界", + "create_time_end", "创建时间范围结束,包含边界" + )); + metadata.put("data_fields", mapOf( + "total", "命中的项目订单数量", + "items", "项目订单列表" + )); + metadata.put("item_fields", buildItemFieldMetadata()); + metadata.put("dynamic_field_rules", mapOf( + "softwareCodeX", "软件产品第 X 行编码,对应 softwareLevel2TypeX/softwareModelX/softwareQuantityX/softwareSalesAmountX/softwareCostAmountX/softwareTaxRateX", + "hardwareCodeX", "硬件产品第 X 行编码,对应 hardwareLevel2TypeX/hardwareModelX/hardwareQuantityX/hardwareSalesAmountX/hardwareCostAmountX/hardwareTaxRateX", + "serviceCodeX", "服务产品第 X 行编码,对应 serviceLevel2TypeX/serviceModelX/serviceQuantityX/serviceSalesAmountX/serviceCostAmountX/serviceTaxRateX", + "cost_rule", "软件和硬件未发货完成时成本字段返回“未发货完成”;服务默认视为已完成;订单不含税成本为各产品按各自税率换算后求和" + )); + return metadata; } private Map buildItemFieldMetadata() { Map metadata = new LinkedHashMap<>(); - metadata.put("projectCode", "项目编号"); + metadata.put("projectStage", "项目阶段"); metadata.put("orderDate", "下单时间"); metadata.put("orderEffectiveDate", "订单生效时间"); metadata.put("requiredDeliveryDate", "要求到货时间"); - metadata.put("orderCode", "合同或订单编号"); + metadata.put("contractCode", "合同编号"); metadata.put("projectName", "项目名称"); metadata.put("agentName", "代表处"); + metadata.put("orderStatus", "订单状态"); metadata.put("ownerName", "汇智责任人"); metadata.put("orderChannel", "下单通路"); metadata.put("supplierName", "供货商"); metadata.put("customerName", "最终客户"); metadata.put("bgName", "BG"); metadata.put("industryType", "行业"); + metadata.put("constructionType", "建设类型(预留)"); metadata.put("projectPartnerName", "运作方"); metadata.put("businessContactName", "进货商接口人"); - metadata.put("businessContactPhone", "进货商接口人联系方式"); + metadata.put("businessContactPhone", "联系方式"); metadata.put("currencyType", "币种"); metadata.put("partnerName", "进货商"); metadata.put("partnerLevel", "进货商类型"); metadata.put("partnerContactName", "进货商联系人"); - metadata.put("partnerContactPhone", "进货商联系方式"); + metadata.put("partnerContactPhone", "联系方式"); metadata.put("executionDeadline", "执行单截至时间"); metadata.put("archiveTime", "归档时间"); - metadata.put("wssQuantity", "WS 瘦授权软件数量"); - metadata.put("wssAmount", "WS 瘦授权软件金额"); - metadata.put("wssTaxRate", "WS 瘦授权软件税率"); - metadata.put("wspQuantity", "WS 胖授权软件数量"); - metadata.put("wspAmount", "WS 胖授权软件金额"); - metadata.put("wspTaxRate", "WS 胖授权软件税率"); - metadata.put("lsQuantity", "LS 软件数量"); - metadata.put("lsAmount", "LS 软件金额"); - metadata.put("lsTaxRate", "LS 软件税率"); - metadata.put("details", "产品明细列表"); - metadata.put("shipmentAmount", "总发货金额"); - metadata.put("totalAmount", "总价合计"); - metadata.put("maintenanceAmount", "维保金额"); - metadata.put("softwareSubtotal", "软件折后小计"); - metadata.put("hardwareSubtotal", "硬件折后小计"); - metadata.put("serviceSubtotal", "服务折后小计"); - metadata.put("outboundOrders", "出库单列表"); + metadata.put("orderAmountWithTax", "订单金额(含税)"); + metadata.put("discountedOrderAmountWithTax", "订单折后金额(含税)"); + metadata.put("discountedOrderAmountWithoutTax", "订单折后总金额(不含税)"); + metadata.put("costTotalWithTax", "成本总计(含税)"); + metadata.put("costTotalWithoutTax", "成本总计(不含税)"); + metadata.put("grossProfit", "整单毛利"); + metadata.put("grossProfitRate", "整单毛利率"); + metadata.put("deliveryTime", "发货时间"); + metadata.put("expectedReceiptAmount", "预计收款金额(元)"); + metadata.put("receivedAmount", "已收金额"); + metadata.put("isCharged", "是否计收"); return metadata; } + + private static class ProductShipmentSummary { + private BigDecimal quantity = BigDecimal.ZERO; + private BigDecimal costWithTax = BigDecimal.ZERO; + private BigDecimal costWithoutTax = BigDecimal.ZERO; + private final List deliveryTimes = new ArrayList<>(); + } + + private static class ProductCostDisplay { + private boolean delivered; + private BigDecimal costWithTax = BigDecimal.ZERO; + private BigDecimal costWithoutTax = BigDecimal.ZERO; + private Object displayValue; + } + + private static class ProductCostSummary { + private BigDecimal costWithTax = BigDecimal.ZERO; + private BigDecimal costWithoutTax = BigDecimal.ZERO; + } + + private static class PurchaseTaxRateContext { + private final Map innerCodeMap; + private final List inventoryInners; + private final Map> purchaseTaxRateMap; + + private PurchaseTaxRateContext(Map innerCodeMap, + List inventoryInners, + Map> purchaseTaxRateMap) { + this.innerCodeMap = innerCodeMap; + this.inventoryInners = inventoryInners; + this.purchaseTaxRateMap = purchaseTaxRateMap; + } + + private BigDecimal resolveTaxRate(String innerCode, String productCode) { + if (isEmpty(innerCode) || isEmpty(productCode)) { + return BigDecimal.ZERO; + } + OmsInventoryInner inventoryInner = innerCodeMap.get(innerCode); + if (inventoryInner == null || isEmpty(inventoryInner.getPurchaseNo())) { + return BigDecimal.ZERO; + } + return purchaseTaxRateMap + .getOrDefault(inventoryInner.getPurchaseNo(), Collections.emptyMap()) + .getOrDefault(productCode, BigDecimal.ZERO); + } + + private List listInventoryInnersByProductType(String productType) { + if (isEmpty(productType)) { + return Collections.emptyList(); + } + return inventoryInners.stream() + .filter(item -> productType.equals(item.getProductType())) + .collect(Collectors.toList()); + } + + private boolean isEmpty(String value) { + return value == null || value.trim().isEmpty(); + } + } + + private static class ProductGroupSummary { + private boolean allDelivered = true; + private BigDecimal salesWithTax = BigDecimal.ZERO; + private BigDecimal salesWithoutTax = BigDecimal.ZERO; + private BigDecimal costWithTax = BigDecimal.ZERO; + private BigDecimal costWithoutTax = BigDecimal.ZERO; + } + + private static class ReceivableSummary { + private BigDecimal totalPriceWithTax = BigDecimal.ZERO; + private BigDecimal receivedAmount = BigDecimal.ZERO; + } } diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/InventoryInfoMapper.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/InventoryInfoMapper.java index 5d689be0..11a1314f 100644 --- a/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/InventoryInfoMapper.java +++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/InventoryInfoMapper.java @@ -81,4 +81,6 @@ public interface InventoryInfoMapper List selectInventoryInfoByOrderCode(List strings); List selectInventoryInfoByOuterCodeList(List outerCodeList); + + List selectInventoryInfoByInnerCodeList(List innerCodeList); } diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/OmsInventoryInnerMapper.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/OmsInventoryInnerMapper.java index 18c01df2..b0ac29ae 100644 --- a/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/OmsInventoryInnerMapper.java +++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/OmsInventoryInnerMapper.java @@ -64,4 +64,8 @@ public interface OmsInventoryInnerMapper List checkDelete(String[] ids); List listById(String[] idArray); + + List selectOmsInventoryInnerByOrderCodeList(List orderCodeList); + + List selectOmsInventoryInnerByInnerCodeList(List innerCodeList); } diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/ProjectInfoMapper.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/ProjectInfoMapper.java index 1961cb5c..b0d9ca11 100644 --- a/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/ProjectInfoMapper.java +++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/mapper/ProjectInfoMapper.java @@ -74,4 +74,6 @@ public interface ProjectInfoMapper void updateCustomerCodeByCode(@Param("oldValue") String oldValue, @Param("newValue")String newValue); ProjectInfo selectProjectInfoByOrderCode(String orderCode); + + List selectProjectInfoByOrderCodeList(List orderCodeList); } diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java index 9939f851..6e9c8767 100644 --- a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java +++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java @@ -78,6 +78,7 @@ public interface IProjectOrderInfoService List< ProjectOrderInfo> selectProjectOrderInfoByProjectId(List projectId); String exportList(ProjectOrderInfo projectOrderInfo); + String exportMcpList(ProjectOrderInfo projectOrderInfo); List> listExportData(ProjectOrderInfo projectOrderInfo); List listHomePageData(HomepageQueryDto dto); diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java index bf7d59ed..0f13171a 100644 --- a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java +++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java @@ -43,6 +43,7 @@ import com.ruoyi.sip.dto.HomepageQueryDto; import com.ruoyi.sip.dto.OrderExcelNumStaticsDto; import com.ruoyi.sip.dto.StatisticsDetailDto; import com.ruoyi.sip.flowable.service.IBuApproveConfigService; +import com.ruoyi.sip.llm.tools.ProjectOrderInfoToolProvider; import com.ruoyi.sip.mapper.OmsStockInfoMapper; import com.ruoyi.sip.mapper.ProjectInfoMapper; import com.ruoyi.sip.service.*; @@ -116,6 +117,7 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To private static final List LS_LIST = Arrays.asList("3130A6LD"); private static final List ONE_STOR_LIST = Arrays.asList("3130A4NA", "3130A4N9", "3130A4N5"); private static final List N_VIDIA_LIST = Arrays.asList("0504A14F", "0504A14G", "0504A1JX"); + private Boolean useMcpExportExcelFormat = Boolean.TRUE; private static final List FILE_INFO_LIST = Arrays.asList( "(请上传商务折扣审批邮件信息).pdf/.jpg/.png","(请上传未盖章合同信息).pdf/.jpg/.png", "(补充附件).zip/.rar/.jpg/.png","(请上传已盖章合同信息).pdf/.jpg/.png"); @Autowired private TaskService taskService; @@ -141,6 +143,10 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To @Autowired @Lazy private IBuApproveConfigService approveConfigService; + + @Autowired + @Lazy + private ProjectOrderInfoToolProvider projectOrderInfoToolProvider; /** * 查询订单管理 * @@ -538,6 +544,9 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To @DataScope(deptAlias = "t5", userAlias = "t5") public String exportList(ProjectOrderInfo projectOrderInfo) { try { + if (Boolean.TRUE.equals(useMcpExportExcelFormat)) { + return exportMcpList(projectOrderInfo); + } // 获取项目信息列表 List projectInfos = this.selectProjectOrderInfoList(projectOrderInfo); @@ -563,6 +572,9 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To @Override @DataScope(deptAlias = "t5", userAlias = "t5") public List> listExportData(ProjectOrderInfo projectOrderInfo) { + if (Boolean.TRUE.equals(useMcpExportExcelFormat)) { + return buildMcpExportItems(projectOrderInfo); + } List projectInfos = this.selectProjectOrderInfoList(projectOrderInfo); if (CollUtil.isEmpty(projectInfos)) { return Collections.emptyList(); @@ -592,6 +604,279 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To return result; } + @Override + @DataScope(deptAlias = "t5", userAlias = "t5") + public String exportMcpList(ProjectOrderInfo projectOrderInfo) { + List> items = buildMcpExportItems(projectOrderInfo); + List fieldNames = buildMcpExportFieldNames(items); + List> header = buildMcpExcelHeader(fieldNames); + List> data = buildMcpExcelData(items, fieldNames); + return writeExcelToFile(header, data); + } + + private List> buildMcpExportItems(ProjectOrderInfo projectOrderInfo) { + return projectOrderInfoToolProvider.listItems(projectOrderInfo); + } + + private List buildMcpExportFieldNames(List> items) { + int maxSoftware = extractMcpDynamicMaxIndex(items, "softwareCode"); + int maxHardware = extractMcpDynamicMaxIndex(items, "hardwareCode"); + int maxService = extractMcpDynamicMaxIndex(items, "serviceCode"); + + List fieldNames = new ArrayList<>(); + Collections.addAll(fieldNames, + "projectStage", + "orderDate", + "orderEffectiveDate", + "requiredDeliveryDate", + "contractCode", + "projectName", + "agentName", + "orderStatus", + "ownerName", + "orderChannel", + "supplierName", + "customerName", + "bgName", + "industryType", + "constructionType", + "projectPartnerName", + "businessContactName", + "businessContactPhone", + "currencyType", + "partnerName", + "partnerLevel", + "partnerContactName", + "partnerContactPhone", + "executionDeadline", + "archiveTime" + ); + addMcpDynamicFieldNames(fieldNames, "software", maxSoftware); + addMcpDynamicFieldNames(fieldNames, "hardware", maxHardware); + addMcpDynamicFieldNames(fieldNames, "service", maxService); + Collections.addAll(fieldNames, + "orderAmountWithTax", + "discountedOrderAmountWithTax", + "discountedOrderAmountWithoutTax", + "costTotalWithTax", + "costTotalWithoutTax", + "grossProfit", + "grossProfitRate", + "deliveryTime", + "expectedReceiptAmount", + "receivedAmount", + "isCharged" + ); + return fieldNames; + } + + private int extractMcpDynamicMaxIndex(List> items, String codePrefix) { + int maxIndex = 0; + for (Map item : items) { + for (String key : item.keySet()) { + if (!key.startsWith(codePrefix)) { + continue; + } + String suffix = key.substring(codePrefix.length()); + if (StringUtils.isNumeric(suffix)) { + maxIndex = Math.max(maxIndex, Integer.parseInt(suffix)); + } + } + } + return maxIndex; + } + + private void addMcpDynamicFieldNames(List fieldNames, String prefix, int count) { + for (int i = 1; i <= count; i++) { + fieldNames.add(prefix + "Code" + i); + fieldNames.add(prefix + "Level2Type" + i); + fieldNames.add(prefix + "Model" + i); + fieldNames.add(prefix + "Quantity" + i); + fieldNames.add(prefix + "SalesAmount" + i); + fieldNames.add(prefix + "CostAmount" + i); + fieldNames.add(prefix + "TaxRate" + i); + } + } + + private List> buildMcpExcelHeader(List fieldNames) { + return fieldNames.stream() + .map(this::toMcpHeaderLabel) + .map(Collections::singletonList) + .collect(Collectors.toList()); + } + + private List> buildMcpExcelData(List> items, List fieldNames) { + List> data = new ArrayList<>(); + for (Map item : items) { + List row = new ArrayList<>(); + for (String fieldName : fieldNames) { + row.add(resolveMcpExportCellValue(item, fieldName)); + } + data.add(row); + } + return data; + } + + private Object resolveMcpExportCellValue(Map item, String fieldName) { + Object value = item.getOrDefault(fieldName, ""); + if (value == null) { + return ""; + } + if (fieldName.startsWith("softwareLevel2Type")) { + return resolveDictLabelOrValue("product_type_1", value); + } + if (fieldName.startsWith("hardwareLevel2Type")) { + return resolveDictLabelOrValue("product_type_2", value); + } + if (fieldName.startsWith("serviceLevel2Type")) { + return resolveDictLabelOrValue("product_type_3", value); + } + return value; + } + + private Object resolveDictLabelOrValue(String dictType, Object value) { + String rawValue = String.valueOf(value); + String label = DictUtils.getDictLabel(dictType, rawValue); + return StringUtils.isEmpty(label) ? rawValue : label; + } + + private String toMcpHeaderLabel(String fieldName) { + switch (fieldName) { + case "projectStage": + return "项目阶段"; + case "orderDate": + return "下单时间"; + case "orderEffectiveDate": + return "订单生效时间"; + case "requiredDeliveryDate": + return "要求到货时间"; + case "contractCode": + return "合同编号"; + case "projectName": + return "项目名称"; + case "agentName": + return "代表处"; + case "orderStatus": + return "订单状态"; + case "ownerName": + return "汇智责任人"; + case "orderChannel": + return "下单通路"; + case "supplierName": + return "供货商"; + case "customerName": + return "最终客户"; + case "bgName": + return "BG"; + case "industryType": + return "行业"; + case "constructionType": + return "建设类型"; + case "projectPartnerName": + return "运作方"; + case "businessContactName": + return "进货商接口人"; + case "businessContactPhone": + return "联系方式"; + case "currencyType": + return "币种"; + case "partnerName": + return "进货商"; + case "partnerLevel": + return "进货商类型"; + case "partnerContactName": + return "进货商联系人"; + case "partnerContactPhone": + return "联系方式"; + case "executionDeadline": + return "执行单截至时间"; + case "archiveTime": + return "归档时间"; + case "orderAmountWithTax": + return "订单金额(含税)"; + case "discountedOrderAmountWithTax": + return "订单折后金额(含税)"; + case "discountedOrderAmountWithoutTax": + return "订单折后总金额(不含税)"; + case "costTotalWithTax": + return "成本总计(含税)"; + case "costTotalWithoutTax": + return "成本总计(不含税)"; + case "grossProfit": + return "整单毛利"; + case "grossProfitRate": + return "整单毛利率"; + case "deliveryTime": + return "发货时间"; + case "expectedReceiptAmount": + return "预计收款金额(元)"; + case "receivedAmount": + return "已收金额"; + case "isCharged": + return "是否计收"; + default: + break; + } + + String dynamicLabel = toMcpDynamicHeaderLabel(fieldName, "software", "软件"); + if (StringUtils.isNotEmpty(dynamicLabel)) { + return dynamicLabel; + } + dynamicLabel = toMcpDynamicHeaderLabel(fieldName, "hardware", "硬件"); + if (StringUtils.isNotEmpty(dynamicLabel)) { + return dynamicLabel; + } + dynamicLabel = toMcpDynamicHeaderLabel(fieldName, "service", "服务"); + if (StringUtils.isNotEmpty(dynamicLabel)) { + return dynamicLabel; + } + return fieldName; + } + + private String toMcpDynamicHeaderLabel(String fieldName, String prefix, String labelPrefix) { + if (!fieldName.startsWith(prefix)) { + return ""; + } + String suffix = fieldName.substring(prefix.length()); + if (suffix.startsWith("Code")) { + return labelPrefix + "编码" + suffix.substring("Code".length()); + } + if (suffix.startsWith("Level2Type")) { + return labelPrefix + "二级类型" + suffix.substring("Level2Type".length()); + } + if (suffix.startsWith("Model")) { + return labelPrefix + "型号" + suffix.substring("Model".length()); + } + if (suffix.startsWith("Quantity")) { + if ("hardware".equals(prefix)) { + return "终端数量" + suffix.substring("Quantity".length()); + } + return labelPrefix + "数量" + suffix.substring("Quantity".length()); + } + if (suffix.startsWith("SalesAmount")) { + if ("software".equals(prefix)) { + return "软件销售金额小计" + suffix.substring("SalesAmount".length()); + } + if ("hardware".equals(prefix)) { + return "硬件金额小计" + suffix.substring("SalesAmount".length()); + } + if ("service".equals(prefix)) { + return "服务金额小计" + suffix.substring("SalesAmount".length()); + } + return labelPrefix + "销售金额小计" + suffix.substring("SalesAmount".length()); + } + if (suffix.startsWith("CostAmount")) { + if ("service".equals(prefix)) { + return "服务成本小计" + suffix.substring("CostAmount".length()); + } + return labelPrefix + "成本金额小计" + suffix.substring("CostAmount".length()); + } + if (suffix.startsWith("TaxRate")) { + return labelPrefix + "税率" + suffix.substring("TaxRate".length()); + } + return ""; + } + @Override public List listHomePageData(HomepageQueryDto dto) { SysUser sysUser = ShiroUtils.getSysUser(); diff --git a/ruoyi-sip/src/main/resources/mapper/inventory/InventoryInfoMapper.xml b/ruoyi-sip/src/main/resources/mapper/inventory/InventoryInfoMapper.xml index d6b06da5..e0cbaaef 100644 --- a/ruoyi-sip/src/main/resources/mapper/inventory/InventoryInfoMapper.xml +++ b/ruoyi-sip/src/main/resources/mapper/inventory/InventoryInfoMapper.xml @@ -118,6 +118,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{item} + diff --git a/ruoyi-sip/src/main/resources/mapper/inventory/OmsInventoryInnerMapper.xml b/ruoyi-sip/src/main/resources/mapper/inventory/OmsInventoryInnerMapper.xml index 3734eb11..9a918cbc 100644 --- a/ruoyi-sip/src/main/resources/mapper/inventory/OmsInventoryInnerMapper.xml +++ b/ruoyi-sip/src/main/resources/mapper/inventory/OmsInventoryInnerMapper.xml @@ -100,6 +100,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{id} + + @@ -179,4 +193,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - \ No newline at end of file + diff --git a/ruoyi-sip/src/main/resources/mapper/sip/ProjectInfoMapper.xml b/ruoyi-sip/src/main/resources/mapper/sip/ProjectInfoMapper.xml index 5252b774..31435bf0 100644 --- a/ruoyi-sip/src/main/resources/mapper/sip/ProjectInfoMapper.xml +++ b/ruoyi-sip/src/main/resources/mapper/sip/ProjectInfoMapper.xml @@ -251,6 +251,71 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where t1.id in (select project_id from project_order_info where order_code = #{orderCode}) + insert into project_info @@ -417,4 +482,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - \ No newline at end of file +