소스 검색

MC海天二期开收票

xmy 1 개월 전
부모
커밋
cc223f4a03

+ 11 - 0
mjava-mc/pom.xml

@@ -41,6 +41,17 @@
             <artifactId>junit</artifactId>
             <scope>test</scope>
         </dependency>
+        <!-- Spring Data Redis 依赖 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+        <!-- 连接池(可选但推荐) -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>

+ 8 - 0
mjava-mc/src/main/java/com/malk/mc/controller/McYdController.java

@@ -190,6 +190,14 @@ public class McYdController {
         return mcYdService.goodsInandOut(map);
     }
 
+    //海天二期开发(开票)
+    @PostMapping("/Invoicing")
+    public  McR Invoicing(@RequestBody Map map){return mcYdService.Invoicing(map);}
+
+    //海天二期开发(收票)
+    @PostMapping("/receiveInvoice")
+    public McR receiveInvoice(@RequestBody Map map){return mcYdService.receiveInvoice(map);}
+
     /**
      * 分享数据权限
      * @param map compId 表单分享权限所属, userIds 分享人及被分享人, userId 分享人, content 代办标题, atUserId 被分享人, appUrl 移动端地址, pcUrl PC端地址

+ 4 - 0
mjava-mc/src/main/java/com/malk/mc/service/McYdService.java

@@ -31,6 +31,10 @@ public interface McYdService {
 
     McR goodsInandOut(Map map);
 
+    McR Invoicing(Map map);
+
+    McR receiveInvoice(Map map);
+
     void batchUpdateSpecifiedQuantityData(Map map);
 
     McR shareRecord(Map map);

+ 341 - 0
mjava-mc/src/main/java/com/malk/mc/service/impl/McYdServiceImpl.java

@@ -26,6 +26,7 @@ import com.malk.service.dingtalk.DDClient_Workflow;
 import com.malk.utils.*;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.util.Strings;
 import org.slf4j.MDC;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -948,6 +949,346 @@ public class McYdServiceImpl implements McYdService {
 
     }
 
+    // 表单及认证常量
+    private static final String FINANCE_FORM_UUID = "FORM-05EDB5C275A448EBBE3A1F2578B2C73CPGSL";
+    private static final String INVOICING_FORM_UUID = "FORM-A36B38B28F684590A9C60DA07EF446DD6QXP";
+    private static final String RECEIVE_FORM_UUID = "FORM-27421C0D0ACA41DFB85D05A9878161B1SDCE";
+    private static final String QUERY_APP_TYPE = "APP_GNQ1RGK68X4JNZUEU8RQ";
+    private static final String QUERY_SYSTEM_TOKEN = "XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5";
+    private static final String QUERY_USER_ID = "332051151139376769";
+    private static final String UPDATE_APP_TYPE = "APP_GNQ1RGK68X4JNZUEU8RQ";
+    private static final String UPDATE_SYSTEM_TOKEN = "XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5";
+    private static final int ERROR_CODE = 500;  // 通用错误码
+
+
+    @Override
+    public McR Invoicing(Map map) {
+        String formInstId = UtilMap.getString(map, "formInstId");
+        log.info("开票流程实例ID: {}", formInstId);
+        try {
+            // 1. 查询开票主表及子表
+            YDParam queryMainParam = YDParam.builder()
+                    .formInstId(formInstId)
+                    .formUuid(INVOICING_FORM_UUID)
+                    .appType(QUERY_APP_TYPE)
+                    .systemToken(QUERY_SYSTEM_TOKEN)
+                    .userId(QUERY_USER_ID)
+                    .build();
+            Map mainData = ydClient.queryData(queryMainParam, YDConf.FORM_QUERY.retrieve_id).getFormData();
+            if (mainData == null || mainData.isEmpty()) {
+                log.error("查询开票主表返回空数据,实例ID: {}", formInstId);
+                return McR.error(String.valueOf(ERROR_CODE), "未查询到开票主表数据,请检查实例ID");
+            }
+            List<Map> subList = (List<Map>) mainData.get("tableField_m8wqi75l");
+            if (subList == null || subList.isEmpty()) {
+                log.warn("开票子表无数据,实例ID: {}", formInstId);
+                return McR.success("子表无明细,无需处理");
+            }
+
+            // 2. 分页查询全部财务数据(每条记录含 formData 嵌套)
+            List<Map> financeList = new ArrayList<>();
+            YDParam queryFinanceParam = YDParam.builder()
+                    .formUuid(FINANCE_FORM_UUID)
+                    .appType(QUERY_APP_TYPE)
+                    .systemToken(QUERY_SYSTEM_TOKEN)
+                    .userId(QUERY_USER_ID)
+                    .build();
+            queryFinanceParam.setPageSize(1);
+            long totalCount = ydClient.queryData(queryFinanceParam, YDConf.FORM_QUERY.retrieve_search_form).getTotalCount();
+            if (totalCount > 0) {
+                int pageSize = 100;
+                int totalPages = (int) Math.ceil((double) totalCount / pageSize);
+                for (int page = 1; page <= totalPages; page++) {
+                    queryFinanceParam.setCurrentPage(page);
+                    queryFinanceParam.setPageSize(pageSize);
+                    List<Map> pageData = (List<Map>) ydClient.queryData(queryFinanceParam, YDConf.FORM_QUERY.retrieve_search_form).getData();
+                    if (pageData != null && !pageData.isEmpty()) {
+                        financeList.addAll(pageData);
+                    }
+                }
+            }
+            log.info("财务数据总条数: {}", financeList.size());
+
+            // 3. 遍历子表,匹配并更新
+            for (Map subItem : subList) {
+                String productCode = UtilMap.getString(subItem, "textField_m8wqi75n");
+                Double saleQtyObj = getDouble(subItem.get("numberField_m8wqi75o"));
+                Double salePriceObj = getDouble(subItem.get("numberField_mqgczkw0")); // 折扣后成本(元)作为销售单价
+                String month = UtilMap.getString(subItem, "textField_mfkfg5u5");
+                if (StringUtils.isBlank(productCode) || saleQtyObj == null || StringUtils.isBlank(month)) {
+                    log.warn("子表明细缺少必要字段,跳过: {}", subItem);
+                    continue;
+                }
+                double saleQty = saleQtyObj;
+                Double salePrice = (salePriceObj != null) ? salePriceObj : 0.0; // 若单价为空,用0.0
+                String trimmedProductCode = productCode.trim();
+
+                // ---- 在财务列表中匹配 ----
+                Map matchedRecord = null;      // 整个记录(外层)
+                Map matchedFormData = null;    // 内层 formData
+                String matchedStatMonth = null;
+
+                // 优先级1:物料编码相同且统计时间等于当前月份 → 累加
+                for (Map record : financeList) {
+                    Map formData = (Map) record.get("formData");
+                    if (formData == null) {
+                        continue;
+                    }
+                    String code = UtilMap.getString(formData, "textField_miy91ty1");
+                    String statMonth = UtilMap.getString(formData, "textField_ml0pe9ut");
+                    if (code == null) continue;
+                    String trimmedCode = code.trim();
+                    if (trimmedProductCode.equals(trimmedCode) && month.equals(statMonth)) {
+                        matchedRecord = record;
+                        matchedFormData = formData;
+                        matchedStatMonth = statMonth;
+                        break;
+                    }
+                }
+
+                // 优先级2:物料编码相同且统计时间不等于当前月份(含空) → 首次覆盖
+                if (matchedRecord == null) {
+                    for (Map record : financeList) {
+                        Map formData = (Map) record.get("formData");
+                        if (formData == null) {
+                            continue;
+                        }
+                        String code = UtilMap.getString(formData, "textField_miy91ty1");
+                        String statMonth = UtilMap.getString(formData, "textField_ml0pe9ut");
+                        if (code == null) continue;
+                        String trimmedCode = code.trim();
+                        if (trimmedProductCode.equals(trimmedCode) && !month.equals(statMonth)) {
+                            matchedRecord = record;
+                            matchedFormData = formData;
+                            matchedStatMonth = statMonth;
+                            log.info("找到物料编码相同但月份不同的财务记录,物料: {}, 财务统计时间: {}, 当前月份: {}, 视为首次操作",
+                                    trimmedProductCode, statMonth, month);
+                            break;
+                        }
+                    }
+                }
+
+                if (matchedRecord == null) {
+                    log.warn("未找到物料编码为 {} 的任何财务记录,无法更新", trimmedProductCode);
+                    continue;
+                }
+
+                // 获取财务记录字段(从 formData 中取)
+                String financeInstId = UtilMap.getString(matchedRecord, "formInstanceId");
+                if (StringUtils.isBlank(financeInstId)) {
+                    log.error("财务记录缺少formInstanceId,跳过更新: {}", matchedRecord);
+                    continue;
+                }
+                double currentSale = getDouble(matchedFormData.get("numberField_mizd11a3"));
+                double currentPurchase = getDouble(matchedFormData.get("numberField_mizd11a5"));
+                double currentBegin = getDouble(matchedFormData.get("numberField_mizd11a2"));
+
+                // 判断是否为首次
+                boolean isFirst = !month.equals(matchedStatMonth);
+
+                double newSale;
+                if (isFirst) {
+                    newSale = saleQty;
+                } else {
+                    newSale = currentSale + saleQty;
+                }
+                double newEnd = currentBegin + currentPurchase - newSale;
+
+                // 构建更新数据(直接更新表单字段)
+                Map<String, Object> updateData = new HashMap<>();
+                updateData.put("numberField_mizd11a3", newSale);          // 本期销售
+                updateData.put("numberField_mizd11a4", newEnd);           // 期末数量
+                updateData.put("numberField_mqhqmysl", salePrice);        // 本期销售单价(始终用最新子表单价)
+                if (isFirst) {
+                    updateData.put("textField_ml0pe9ut", month);          // 统计时间
+                }
+
+                String updateJson = JSONObject.toJSONString(updateData);
+                YDParam updateParam = YDParam.builder()
+                        .appType(UPDATE_APP_TYPE)
+                        .systemToken(UPDATE_SYSTEM_TOKEN)
+                        .formInstanceId(financeInstId)
+                        .updateFormDataJson(updateJson)
+                        .build();
+                ydClient.operateData(updateParam, YDConf.FORM_OPERATION.update);
+                log.info("开票更新财务记录成功,实例ID: {}, 首次: {}, 新销售: {}, 新单价: {}, 新期末: {}, 月份更新为: {}",
+                        financeInstId, isFirst, newSale, salePrice, newEnd, isFirst ? month : matchedStatMonth);
+            }
+            return McR.success("开票处理完成");
+        } catch (Exception e) {
+            log.error("开票处理异常", e);
+            return McR.error(String.valueOf(ERROR_CODE), "开票处理失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public McR receiveInvoice(Map map) {
+        String formInstId = UtilMap.getString(map, "formInstId");
+        log.info("收票流程实例ID: {}", formInstId);
+        try {
+            // 1. 查询收票主表及子表
+            YDParam queryMainParam = YDParam.builder()
+                    .formInstId(formInstId)
+                    .formUuid(RECEIVE_FORM_UUID)
+                    .appType(QUERY_APP_TYPE)
+                    .systemToken(QUERY_SYSTEM_TOKEN)
+                    .userId(QUERY_USER_ID)
+                    .build();
+            Map mainData = ydClient.queryData(queryMainParam, YDConf.FORM_QUERY.retrieve_id).getFormData();
+            if (mainData == null || mainData.isEmpty()) {
+                log.error("查询收票主表返回空数据,实例ID: {}", formInstId);
+                return McR.error(String.valueOf(ERROR_CODE), "未查询到收票主表数据,请检查实例ID");
+            }
+            List<Map> subList = (List<Map>) mainData.get("tableField_m8wtvnvs");
+            if (subList == null || subList.isEmpty()) {
+                log.warn("收票子表无数据,实例ID: {}", formInstId);
+                return McR.success("子表无明细,无需处理");
+            }
+
+            // 2. 分页查询全部财务数据
+            List<Map> financeList = new ArrayList<>();
+            YDParam queryFinanceParam = YDParam.builder()
+                    .formUuid(FINANCE_FORM_UUID)
+                    .appType(QUERY_APP_TYPE)
+                    .systemToken(QUERY_SYSTEM_TOKEN)
+                    .userId(QUERY_USER_ID)
+                    .build();
+            queryFinanceParam.setPageSize(1);
+            long totalCount = ydClient.queryData(queryFinanceParam, YDConf.FORM_QUERY.retrieve_search_form).getTotalCount();
+            if (totalCount > 0) {
+                int pageSize = 100;
+                int totalPages = (int) Math.ceil((double) totalCount / pageSize);
+                for (int page = 1; page <= totalPages; page++) {
+                    queryFinanceParam.setCurrentPage(page);
+                    queryFinanceParam.setPageSize(pageSize);
+                    List<Map> pageData = (List<Map>) ydClient.queryData(queryFinanceParam, YDConf.FORM_QUERY.retrieve_search_form).getData();
+                    if (pageData != null && !pageData.isEmpty()) {
+                        financeList.addAll(pageData);
+                    }
+                }
+            }
+            log.info("财务数据总条数: {}", financeList.size());
+
+            // 3. 遍历子表,匹配并更新
+            for (Map subItem : subList) {
+                String productCode = UtilMap.getString(subItem, "textField_mfdo4a28");
+                Double purchaseQtyObj = getDouble(subItem.get("numberField_m8wtyd58"));
+                Double purchasePriceObj = getDouble(subItem.get("numberField_mqgd5wvl")); // 折扣后成本(元)作为购入单价
+                String month = UtilMap.getString(subItem, "textField_mfkfi8ov");
+                if (StringUtils.isBlank(productCode) || purchaseQtyObj == null || StringUtils.isBlank(month)) {
+                    log.warn("子表明细缺少必要字段,跳过: {}", subItem);
+                    continue;
+                }
+                double purchaseQty = purchaseQtyObj;
+                Double purchasePrice = (purchasePriceObj != null) ? purchasePriceObj : 0.0;
+                String trimmedProductCode = productCode.trim();
+
+                // ---- 在财务列表中匹配 ----
+                Map matchedRecord = null;
+                Map matchedFormData = null;
+                String matchedStatMonth = null;
+
+                // 优先级1:物料编码相同且统计时间等于当前月份 → 累加
+                for (Map record : financeList) {
+                    Map formData = (Map) record.get("formData");
+                    if (formData == null) continue;
+                    String code = UtilMap.getString(formData, "textField_miy91ty1");
+                    String statMonth = UtilMap.getString(formData, "textField_ml0pe9ut");
+                    if (code == null) continue;
+                    String trimmedCode = code.trim();
+                    if (trimmedProductCode.equals(trimmedCode) && month.equals(statMonth)) {
+                        matchedRecord = record;
+                        matchedFormData = formData;
+                        matchedStatMonth = statMonth;
+                        break;
+                    }
+                }
+
+                // 优先级2:物料编码相同且统计时间不等于当前月份(含空) → 首次覆盖
+                if (matchedRecord == null) {
+                    for (Map record : financeList) {
+                        Map formData = (Map) record.get("formData");
+                        if (formData == null) continue;
+                        String code = UtilMap.getString(formData, "textField_miy91ty1");
+                        String statMonth = UtilMap.getString(formData, "textField_ml0pe9ut");
+                        if (code == null) continue;
+                        String trimmedCode = code.trim();
+                        if (trimmedProductCode.equals(trimmedCode) && !month.equals(statMonth)) {
+                            matchedRecord = record;
+                            matchedFormData = formData;
+                            matchedStatMonth = statMonth;
+                            log.info("找到物料编码相同但月份不同的财务记录,物料: {}, 财务统计时间: {}, 当前月份: {}, 视为首次操作",
+                                    trimmedProductCode, statMonth, month);
+                            break;
+                        }
+                    }
+                }
+
+                if (matchedRecord == null) {
+                    log.warn("未找到物料编码为 {} 的任何财务记录,无法更新", trimmedProductCode);
+                    continue;
+                }
+
+                String financeInstId = UtilMap.getString(matchedRecord, "formInstanceId");
+                if (StringUtils.isBlank(financeInstId)) {
+                    log.error("财务记录缺少formInstanceId,跳过更新: {}", matchedRecord);
+                    continue;
+                }
+                double currentSale = getDouble(matchedFormData.get("numberField_mizd11a3"));
+                double currentPurchase = getDouble(matchedFormData.get("numberField_mizd11a5"));
+                double currentBegin = getDouble(matchedFormData.get("numberField_mizd11a2"));
+
+                boolean isFirst = !month.equals(matchedStatMonth);
+
+                double newPurchase;
+                if (isFirst) {
+                    newPurchase = purchaseQty;
+                } else {
+                    newPurchase = currentPurchase + purchaseQty;
+                }
+                double newEnd = currentBegin + newPurchase - currentSale;
+
+                Map<String, Object> updateData = new HashMap<>();
+                updateData.put("numberField_mizd11a5", newPurchase);    // 本期购入
+                updateData.put("numberField_mizd11a4", newEnd);         // 期末数量
+                updateData.put("numberField_mqhqmysm", purchasePrice);  // 本期购入单价(始终用最新子表单价)
+                if (isFirst) {
+                    updateData.put("textField_ml0pe9ut", month);        // 统计时间
+                }
+
+                String updateJson = JSONObject.toJSONString(updateData);
+                YDParam updateParam = YDParam.builder()
+                        .appType(UPDATE_APP_TYPE)
+                        .systemToken(UPDATE_SYSTEM_TOKEN)
+                        .formInstanceId(financeInstId)
+                        .updateFormDataJson(updateJson)
+                        .build();
+                ydClient.operateData(updateParam, YDConf.FORM_OPERATION.update);
+                log.info("收票更新财务记录成功,实例ID: {}, 首次: {}, 新购入: {}, 新单价: {}, 新期末: {}, 月份更新为: {}",
+                        financeInstId, isFirst, newPurchase, purchasePrice, newEnd, isFirst ? month : matchedStatMonth);
+            }
+            return McR.success("收票处理完成");
+        } catch (Exception e) {
+            log.error("收票处理异常", e);
+            return McR.error(String.valueOf(ERROR_CODE), "收票处理失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 安全转换 Object 为 Double,null 或无效值返回 null
+     */
+    private Double getDouble(Object value) {
+        if (value == null) return null;
+        if (value instanceof Number) {
+            return ((Number) value).doubleValue();
+        }
+        try {
+            return Double.parseDouble(value.toString());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
     @Override
     public McR shareRecord(Map data) {
         String pid = getString(data.get("pid"));