新增通过消费订单明细id获取明细

This commit is contained in:
潘荣晟
2025-11-06 16:06:16 +08:00
parent 48b9209fd1
commit 292d4a534d
16 changed files with 328 additions and 26 deletions

View File

@@ -0,0 +1,26 @@
package com.zt.plat.module.erp.api;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.module.erp.api.dto.ErpInvoiceticketSubmitReqDTO;
import com.zt.plat.module.erp.api.dto.ErpInvoiceticketSubmitRespDTO;
import com.zt.plat.module.erp.api.dto.ErpSubmitReqDTO;
import com.zt.plat.module.erp.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.HashMap;
@FeignClient(name = ApiConstants.NAME)
@Tag(name = "RPC 服务 - ERP")
public interface InvoiceticketApi {
String PREFIX = ApiConstants.PREFIX + "/invoiceticket";
@PostMapping(PREFIX + "/submit")
@Operation(summary = "erp数据提交")
CommonResult<ErpInvoiceticketSubmitRespDTO> submitDataToErp(@Valid @RequestBody ErpInvoiceticketSubmitReqDTO reqDTO);
}

View File

@@ -0,0 +1,29 @@
package com.zt.plat.module.erp.api.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Data
@Schema(description = "管理后台 - 发票相关操作 Request VO")
public class ErpInvoiceticketSubmitReqDTO {
@Schema(description = "id,用作bskey", requiredMode = Schema.RequiredMode.REQUIRED)
private String id;
@Schema(description = "发票类型;RE-采购发票RV-销售发票", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "发票类型不能为空")
@Size(min = 2, max = 2, message = "发票类型必须为2位字符")
@Pattern(regexp = "^(RE|RV)$", message = "发票类型仅支持RE(采购发票)、RV(销售发票)")
private String vouchertype;
@Schema(description = "发票编号", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "发票编号不能为空")
@Size(min = 1, max = 10, message = "发票编号长度不能超过10位")
private String voucherno;
@Schema(description = "会计年度;发票类型为RE(采购发票)时必填格式为4位数字如2025")
@Pattern(regexp = "^\\d{4}$", message = "会计年度必须为4位数字如2025")
private String voucheryear;
}

View File

@@ -0,0 +1,61 @@
package com.zt.plat.module.erp.api.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@Schema(description = "管理后台 - 发票相关操作 响应 VO")
public class ErpInvoiceticketSubmitRespDTO {
@Schema(description = "发票过账日期格式为YYYYMMDD如20251106")
private String postDate;
@Schema(description = "业务单据号长度20位字符")
private String settlementsCode;
@Schema(description = "状态码详见《发票状态》表长度1位字符")
private String state;
@Schema(description = "消息文本生单失败、驳回、过账失败等状态时返回共享端和SAP消息")
private String reason;
@Schema(description = "会计凭证编号已生成会计凭证的情况下返回长度10位字符")
private String refDoc;
@Schema(description = "冲销凭证号状态为已冲销时返回长度10位字符")
private String revDoc;
@Schema(description = "冲销凭证会计年度仅RE发票采购发票且状态为已冲销时返回4位数字")
private String revYear;
@Schema(description = "冲销凭证过账日期状态为已冲销时返回格式为YYYYMMDD如20251106")
private String revDate;
@Schema(description = "采购发票过账差异明细仅RE发票采购发票且状态为3时返回")
private List<CallBackSettlementDetail> callBackSettlementDetails;
/**
* 采购发票过账差异明细子项
*/
@Schema(description = "采购发票过账差异明细子项")
@Data
public static class CallBackSettlementDetail {
@Schema(description = "工厂编号")
private String factoryCode;
@Schema(description = "物料编号")
private String materialCode;
@Schema(description = "物料凭证号")
private String matDoc;
@Schema(description = "物料描述")
private String materialDesc;
@Schema(description = "差异金额")
private BigDecimal differenceAmount;
}
}

View File

@@ -0,0 +1,25 @@
package com.zt.plat.module.erp.api;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.module.erp.api.dto.ErpInvoiceticketSubmitReqDTO;
import com.zt.plat.module.erp.api.dto.ErpInvoiceticketSubmitRespDTO;
import com.zt.plat.module.erp.service.erp.ErpInvoiceticketService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.zt.plat.framework.common.pojo.CommonResult.success;
@RestController
@Validated
@Slf4j
public class InvoiceticketImpl implements InvoiceticketApi {
@Resource
private ErpInvoiceticketService erpInvoiceticketService;
@Override
public CommonResult<ErpInvoiceticketSubmitRespDTO> submitDataToErp(ErpInvoiceticketSubmitReqDTO reqDTO) {
return success(erpInvoiceticketService.sbumitToErp020(reqDTO));
}
}

View File

@@ -0,0 +1,8 @@
package com.zt.plat.module.erp.service.erp;
import com.zt.plat.module.erp.api.dto.ErpInvoiceticketSubmitReqDTO;
import com.zt.plat.module.erp.api.dto.ErpInvoiceticketSubmitRespDTO;
public interface ErpInvoiceticketService {
ErpInvoiceticketSubmitRespDTO sbumitToErp020(ErpInvoiceticketSubmitReqDTO reqDTO);
}

View File

@@ -0,0 +1,126 @@
package com.zt.plat.module.erp.service.erp;
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
import com.zt.plat.module.erp.api.ErpExternalApi;
import com.zt.plat.module.erp.api.dto.ErpInvoiceticketSubmitReqDTO;
import com.zt.plat.module.erp.api.dto.ErpInvoiceticketSubmitRespDTO;
import com.zt.plat.module.erp.api.dto.ErpSubmitReqDTO;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@Validated
public class ErpInvoiceticketServiceImpl implements ErpInvoiceticketService {
@Resource
public ErpExternalApi erpExternalApi;
@Override
public ErpInvoiceticketSubmitRespDTO sbumitToErp020(ErpInvoiceticketSubmitReqDTO erpInvoiceticketSubmitReqDTO) {
ErpSubmitReqDTO reqDTO = new ErpSubmitReqDTO();
reqDTO.setFuncnr("020");
reqDTO.setBskey(erpInvoiceticketSubmitReqDTO.getId());
reqDTO.setUsrid(String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
reqDTO.setUsrnm((SecurityFrameworkUtils.getLoginUserNickname()));
Map<String, Object> req = new HashMap<>();
req.put("vouchertype", erpInvoiceticketSubmitReqDTO.getVouchertype());
req.put("voucherno", erpInvoiceticketSubmitReqDTO.getVoucherno());
req.put("voucheryear", erpInvoiceticketSubmitReqDTO.getVoucheryear());
reqDTO.setReq(req);
// 1. 调用ERP接口获取HashMap结果
HashMap<String, String> result = erpExternalApi.submitDataToErp(reqDTO);
// 2. 初始化响应实体
ErpInvoiceticketSubmitRespDTO respDTO = new ErpInvoiceticketSubmitRespDTO();
// 3. 基础字段映射String类型直接赋值兼容空值
respDTO.setPostDate(getStringValue(result, "postDate"));
respDTO.setSettlementsCode(getStringValue(result, "settlementsCode"));
respDTO.setState(getStringValue(result, "state"));
respDTO.setReason(getStringValue(result, "reason"));
respDTO.setRefDoc(getStringValue(result, "refDoc"));
respDTO.setRevDoc(getStringValue(result, "revDoc"));
respDTO.setRevYear(getStringValue(result, "revYear"));
respDTO.setRevDate(getStringValue(result, "revDate"));
// 4. 子列表 callBackSettlementDetails 映射
respDTO.setCallBackSettlementDetails(convertSettlementDetails(result));
return respDTO;
}
/**
* 转换采购发票过账差异明细列表
* 假设HashMap中子列表字段格式为callBackSettlementDetails[0].factoryCode、callBackSettlementDetails[0].materialCode...
*/
private List<ErpInvoiceticketSubmitRespDTO.CallBackSettlementDetail> convertSettlementDetails(Map<String, String> result) {
List<ErpInvoiceticketSubmitRespDTO.CallBackSettlementDetail> detailList = new ArrayList<>();
if (result == null) {
return detailList;
}
// 按索引遍历子列表数据,直到无对应字段为止
int index = 0;
while (true) {
// 拼接子字段的key根据实际返回的key格式调整此处为标准嵌套格式
String factoryCodeKey = String.format("callBackSettlementDetails[%d].factoryCode", index);
String materialCodeKey = String.format("callBackSettlementDetails[%d].materialCode", index);
String matDocKey = String.format("callBackSettlementDetails[%d].matDoc", index);
String materialDescKey = String.format("callBackSettlementDetails[%d].materialDesc", index);
String differenceAmountKey = String.format("callBackSettlementDetails[%d].differenceAmount", index);
// 若核心字段如factoryCode为空说明无更多子项退出循环
if (StringUtils.isBlank(getStringValue(result, factoryCodeKey))) {
break;
}
// 构建子明细实体
ErpInvoiceticketSubmitRespDTO.CallBackSettlementDetail detail = new ErpInvoiceticketSubmitRespDTO.CallBackSettlementDetail();
detail.setFactoryCode(getStringValue(result, factoryCodeKey));
detail.setMaterialCode(getStringValue(result, materialCodeKey));
detail.setMatDoc(getStringValue(result, matDocKey));
detail.setMaterialDesc(getStringValue(result, materialDescKey));
// 金额字段转换(兼容空值和非数字场景)
detail.setDifferenceAmount(getBigDecimalValue(result, differenceAmountKey));
detailList.add(detail);
index++;
}
// 无数据时返回null避免前端接收空列表
return detailList.isEmpty() ? null : detailList;
}
/**
* 安全获取String值避免null指针
*/
private String getStringValue(Map<String, String> map, String key) {
return map.getOrDefault(key, StringUtils.EMPTY);
}
/**
* 安全转换BigDecimal处理空值和格式错误
*/
private BigDecimal getBigDecimalValue(Map<String, String> map, String key) {
String value = map.get(key);
if (StringUtils.isBlank(value)) {
return null;
}
try {
return new BigDecimal(value);
} catch (NumberFormatException e) {
// 若金额格式错误可根据业务选择返回null或抛出异常
return null;
}
}
}