|
@@ -0,0 +1,138 @@
|
|
|
|
|
+package com.ruoyi.logistics.service.impl;
|
|
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
|
|
+import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
+import com.ruoyi.common.redis.service.RedisIdGenerator;
|
|
|
|
|
+import com.ruoyi.logistics.config.InvoiceConfig;
|
|
|
|
|
+import com.ruoyi.logistics.domain.InvoiceRequest;
|
|
|
|
|
+import com.ruoyi.logistics.service.InvoiceService;
|
|
|
|
|
+import com.ruoyi.logistics.util.Base64Util;
|
|
|
|
|
+import com.ruoyi.logistics.util.HttpUtil;
|
|
|
|
|
+import com.ruoyi.logistics.util.SignUtil;
|
|
|
|
|
+import com.ruoyi.logistics.util.TaxAmountCalculator;
|
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
|
+import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 开票相关接口
|
|
|
|
|
+ *
|
|
|
|
|
+ * @author zxf
|
|
|
|
|
+ * @date 2026-02-11
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+@Service
|
|
|
|
|
+public class InvoiceServiceImpl implements InvoiceService {
|
|
|
|
|
+ private static final Logger logger = LoggerFactory.getLogger(InvoiceServiceImpl.class);
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private RedisIdGenerator redisIdGenerator;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private InvoiceConfig invoiceConfig;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 电子发票专票开据
|
|
|
|
|
+ * @param InvoiceRequest 开票相入参
|
|
|
|
|
+ * @return 运单明细
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Map invoiceIssuance(InvoiceRequest invoiceRequest) throws JsonProcessingException {
|
|
|
|
|
+ logger.info("收到开票请求参数:参数{}",invoiceRequest);
|
|
|
|
|
+ // 1. 组装正票申请的业务报文(content)
|
|
|
|
|
+ JSONObject content = new JSONObject();
|
|
|
|
|
+ // 必选参数
|
|
|
|
|
+ content.put("djbh", redisIdGenerator.generateUniqueId("BWKP")); // 全局唯一单据编号
|
|
|
|
|
+ content.put("kpzddm", invoiceConfig.getKpZddm()); // 开票终端代码
|
|
|
|
|
+ content.put("fplxdm", "01"); // 发票类型:01=专票,02=普票
|
|
|
|
|
+ content.put("kplx", "0"); // 开票类型:0=蓝字发票
|
|
|
|
|
+ content.put("zsfs", "0"); // 征收方式:0=普通征税
|
|
|
|
|
+ content.put("khmc", invoiceRequest.getKhmc()); // 购货单位名称
|
|
|
|
|
+ content.put("hsje", invoiceRequest.getHsje()); // 含税金额(价税合计)
|
|
|
|
|
+ content.put("gsdm", "7600"); // 公司代码
|
|
|
|
|
+ content.put("yhdm", "ec014266e63344698642d6e5c5b8b556"); // 用户代码
|
|
|
|
|
+ content.put("sjlx", "1"); // 数据类型(批发系统,由平台提供)
|
|
|
|
|
+ content.put("sfwzzfp", "N"); // 非纸质发票(默认N)
|
|
|
|
|
+ content.put("hsbz", "1"); // 含税标志(1=含税,默认)
|
|
|
|
|
+ //可选参数
|
|
|
|
|
+ content.put("khsh", invoiceRequest.getKhsh()); // 购货单位税号(专票必填)
|
|
|
|
|
+ content.put("khdzdh", invoiceRequest.getKhdzdh()); // 购货单位地址电话
|
|
|
|
|
+ content.put("khyhzh", invoiceRequest.getKhyhzh()); // 购货单位银行账号
|
|
|
|
|
+ content.put("gmfMobile", invoiceRequest.getGmfMobile()); // 电子发票手机号
|
|
|
|
|
+ content.put("gmfEmail", invoiceRequest.getGmfEmail()); // 电子发票邮箱
|
|
|
|
|
+ content.put("bz", invoiceRequest.getBz()); // 备注
|
|
|
|
|
+ // 商品明细(mxxx,必选)
|
|
|
|
|
+ JSONObject goodsItem = new JSONObject();
|
|
|
|
|
+ goodsItem.put("djhh", "1"); // 单据行号
|
|
|
|
|
+ goodsItem.put("fphxz", "0"); // 发票行性质:0=正常行
|
|
|
|
|
+ goodsItem.put("spmc", "测试商品"); // 商品名称
|
|
|
|
|
+ goodsItem.put("jldw", "月"); //计量单位
|
|
|
|
|
+ goodsItem.put("spsl", 1.00); // 商品数量
|
|
|
|
|
+ goodsItem.put("ssbm", "3040802010100000000"); // 19位税收编码
|
|
|
|
|
+ goodsItem.put("hsdj", invoiceRequest.getHsje()); // 含税单价
|
|
|
|
|
+ goodsItem.put("hsje", invoiceRequest.getHsje()); // 商品含税金额
|
|
|
|
|
+ BigDecimal[] result =TaxAmountCalculator.calculateFromTaxIncluded(invoiceRequest.getHsje(), BigDecimal.valueOf(0.06));
|
|
|
|
|
+ goodsItem.put("tax", 0.06); // 税率13%
|
|
|
|
|
+ goodsItem.put("se", result[1]); // 商品税额
|
|
|
|
|
+ content.put("mxxx", new JSONObject[]{goodsItem});
|
|
|
|
|
+ logger.info("开票参数组装完成 参数{}",content);
|
|
|
|
|
+ String contentBase64 = Base64Util.encode(content.toJSONString());
|
|
|
|
|
+ // 3. 构建签名参数,生成签名值
|
|
|
|
|
+ Map<String, String> signParams = new HashMap<>();
|
|
|
|
|
+ signParams.put("appid", invoiceConfig.getAppId());
|
|
|
|
|
+ signParams.put("serviceid", invoiceConfig.getServiceId());
|
|
|
|
|
+ signParams.put("content", contentBase64);
|
|
|
|
|
+ String signature = SignUtil.sign(invoiceConfig.getSignType(), invoiceConfig.getAppSecret(), signParams);
|
|
|
|
|
+ // 4. 组装接口请求的公共参数
|
|
|
|
|
+ JSONObject requestParam = new JSONObject();
|
|
|
|
|
+ requestParam.put("appid", invoiceConfig.getAppId());
|
|
|
|
|
+ requestParam.put("serviceid", invoiceConfig.getServiceId());
|
|
|
|
|
+ requestParam.put("content", contentBase64);
|
|
|
|
|
+ requestParam.put("signature", signature);
|
|
|
|
|
+ requestParam.put("signType", invoiceConfig.getSignType());
|
|
|
|
|
+ String responseJson = HttpUtil.doPostJson(invoiceConfig.getBaseUrl(), requestParam.toJSONString());
|
|
|
|
|
+ ObjectMapper objectMapper = new ObjectMapper();
|
|
|
|
|
+ // JsonNode jsonNode = objectMapper.readTree(responseJson);
|
|
|
|
|
+ Map<String, Object> invoiceMap = objectMapper.readValue(
|
|
|
|
|
+ responseJson,
|
|
|
|
|
+ new TypeReference<Map<String, Object>>() {}
|
|
|
|
|
+ );
|
|
|
|
|
+ return invoiceMap;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 电子发票正票擦汗寻
|
|
|
|
|
+ * @param InvoiceRequest 开票相入参
|
|
|
|
|
+ * @return 运单明细
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Map selectInvoice(Map param) {
|
|
|
|
|
+ // 1. 组装正票申请的业务报文(content)
|
|
|
|
|
+ JSONObject content = new JSONObject();
|
|
|
|
|
+ content.put("djbh",param.get("djbh"));
|
|
|
|
|
+ String contentBase64 = Base64Util.encode(content.toJSONString());
|
|
|
|
|
+ Map<String, String> signParams = new HashMap<>();
|
|
|
|
|
+ signParams.put("appid", invoiceConfig.getAppId());
|
|
|
|
|
+ signParams.put("serviceid", invoiceConfig.getServiceSelect());
|
|
|
|
|
+ signParams.put("content", contentBase64);
|
|
|
|
|
+ String signature = SignUtil.sign(invoiceConfig.getSignType(), invoiceConfig.getAppSecret(), signParams);
|
|
|
|
|
+ JSONObject requestParam = new JSONObject();
|
|
|
|
|
+ requestParam.put("appid", invoiceConfig.getAppId());
|
|
|
|
|
+ requestParam.put("serviceid", invoiceConfig.getServiceSelect());
|
|
|
|
|
+ requestParam.put("content", contentBase64);
|
|
|
|
|
+ requestParam.put("signature", signature);
|
|
|
|
|
+ requestParam.put("signType", invoiceConfig.getSignType());
|
|
|
|
|
+ String responseJson = HttpUtil.doPostJson(invoiceConfig.getBaseUrl(), requestParam.toJSONString());
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|