|
|
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import com.ruoyi.common.core.utils.StringUtils;
|
|
|
import com.ruoyi.common.redis.service.RedisIdGenerator;
|
|
|
+import com.ruoyi.common.redis.service.RedisService;
|
|
|
import com.ruoyi.logistics.config.InvoiceConfig;
|
|
|
import com.ruoyi.logistics.domain.InvoiceRequest;
|
|
|
import com.ruoyi.logistics.domain.OrderRequest;
|
|
|
@@ -18,6 +19,7 @@ import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import java.math.BigDecimal;
|
|
|
import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
@@ -26,6 +28,7 @@ import java.time.format.DateTimeFormatter;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
import org.springframework.http.HttpEntity;
|
|
|
import org.springframework.http.HttpHeaders;
|
|
|
import org.springframework.http.MediaType;
|
|
|
@@ -54,6 +57,9 @@ public class InvoiceServiceImpl implements InvoiceService {
|
|
|
@Autowired
|
|
|
private IRptFinancialMonthSummaryService rptFinancialMonthSummaryService;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private RedisService redisService;
|
|
|
+
|
|
|
/**
|
|
|
* 电子发票专票开据
|
|
|
* @param InvoiceRequest 开票相入参
|
|
|
@@ -254,6 +260,128 @@ public class InvoiceServiceImpl implements InvoiceService {
|
|
|
return shopMap;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 一键回传票据(异步执行)
|
|
|
+ * 处理所有已开票(status=3)的月度账单,回传到商城
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Async
|
|
|
+ public void batchReturnShop() {
|
|
|
+ // Redis 唯一 key,防止重复处理
|
|
|
+ String redisKey = "invoice:batch_return_shop:processing";
|
|
|
+
|
|
|
+ // 检查是否已有任务在处理
|
|
|
+ Boolean isProcessing = redisService.hasKey(redisKey);
|
|
|
+ if (Boolean.TRUE.equals(isProcessing)) {
|
|
|
+ logger.warn("一键回传票据任务正在执行中,请勿重复提交");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 设置 Redis key,过期时间设置为 1 小时,防止异常情况下 key 永久存在
|
|
|
+ redisService.setCacheObject(redisKey, "1", 1L, TimeUnit.HOURS);
|
|
|
+ logger.info("开始执行一键回传票据任务");
|
|
|
+
|
|
|
+ // 查询所有 status=3(已开票)的月度账单
|
|
|
+ List<Map<String, Object>> invoiceList = jdbcTemplate.queryForList(
|
|
|
+ "SELECT summary_id, payable_amount, bw_djbh, kprq, dept_name, invoice_name, dept_code, leader " +
|
|
|
+ "FROM rpt_financial_month_summary a " +
|
|
|
+ "LEFT JOIN sys_dept b ON a.dept_id = b.dept_id " +
|
|
|
+ "WHERE a.status = '3'"
|
|
|
+ );
|
|
|
+
|
|
|
+ if (invoiceList == null || invoiceList.isEmpty()) {
|
|
|
+ logger.info("没有需要回传的票据数据");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.info("共找到 {} 条已开票数据需要回传", invoiceList.size());
|
|
|
+
|
|
|
+ int successCount = 0;
|
|
|
+ int failureCount = 0;
|
|
|
+
|
|
|
+ // 遍历处理每一条数据
|
|
|
+ for (int i = 0; i < invoiceList.size(); i++) {
|
|
|
+ Map<String, Object> map = invoiceList.get(i);
|
|
|
+ Long summaryId = ((Number) map.get("summary_id")).longValue();
|
|
|
+
|
|
|
+ try {
|
|
|
+ logger.info("正在处理第 {}/{} 条数据,summaryId: {}", i + 1, invoiceList.size(), summaryId);
|
|
|
+
|
|
|
+ // 构建回传商城的请求参数
|
|
|
+ String url = invoiceConfig.getShopUrl();
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
+
|
|
|
+ BigDecimal free = new BigDecimal(map.get("payable_amount").toString());
|
|
|
+ OrderRequest request = new OrderRequest();
|
|
|
+ request.setOrderNumber(map.get("bw_djbh").toString());
|
|
|
+ request.setSkuId("787");
|
|
|
+ request.setGzTime(map.get("kprq") != null ? map.get("kprq").toString() : LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
|
|
+ request.setOutCode("3204");
|
|
|
+ request.setUserId(map.get("leader") != null ? map.get("leader").toString() : "");
|
|
|
+ request.setUserCompanyName(map.get("invoice_name") != null ? map.get("invoice_name").toString() : "");
|
|
|
+ request.setSapCode(map.get("dept_code") != null ? map.get("dept_code").toString() : "");
|
|
|
+ request.setShopName(map.get("dept_name") != null ? map.get("dept_name").toString() : "");
|
|
|
+ request.setPayType(1);
|
|
|
+ request.setProdName("快递服务");
|
|
|
+ request.setProdCount("1");
|
|
|
+ request.setBuyMoney(free); // 销售金额 含税
|
|
|
+ request.setBuyPrice(free); // 采购单价 含税
|
|
|
+ request.setSaleMoney(free); // 销售金额 含税
|
|
|
+ request.setPurchaseRate(BigDecimal.valueOf(0.06)); // 进项税率
|
|
|
+ request.setPrice(free); // 销售单价 含税
|
|
|
+
|
|
|
+ BigDecimal[] result = TaxAmountCalculator.calculateFromTaxIncluded(free, BigDecimal.valueOf(0.06));
|
|
|
+ request.setBuyMoneyNoTax(result[0]); // 采购金额(不含税)
|
|
|
+ request.setJxse(result[1]); // 进项税额
|
|
|
+
|
|
|
+ BigDecimal[] result1 = TaxAmountCalculator.calculateFromTaxIncluded(free, BigDecimal.valueOf(0.06));
|
|
|
+ request.setOutputRate(BigDecimal.valueOf(0.06)); // 销项税率
|
|
|
+ request.setXxse(result1[1]); // 销项税额
|
|
|
+
|
|
|
+ HttpEntity<OrderRequest> entity = new HttpEntity<>(request, headers);
|
|
|
+ ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
|
|
|
+
|
|
|
+ ObjectMapper objectMapper = new ObjectMapper();
|
|
|
+ Map<String, Object> shopMap = objectMapper.readValue(
|
|
|
+ response.getBody(),
|
|
|
+ new TypeReference<Map<String, Object>>() {}
|
|
|
+ );
|
|
|
+
|
|
|
+ // 判断回传是否成功
|
|
|
+ if ("0".equals(shopMap.get("code").toString())) {
|
|
|
+ // 更新状态为 4(已回传商城)
|
|
|
+ RptFinancialMonthSummary rptFinancialMonthSummary = new RptFinancialMonthSummary();
|
|
|
+ rptFinancialMonthSummary.setStatus("4");
|
|
|
+ rptFinancialMonthSummary.setSummaryId(summaryId);
|
|
|
+ rptFinancialMonthSummaryService.updateRptFinancialMonthSummary(rptFinancialMonthSummary);
|
|
|
+ successCount++;
|
|
|
+ logger.info("第 {}/{} 条数据回传成功,summaryId: {}", i + 1, invoiceList.size(), summaryId);
|
|
|
+ } else {
|
|
|
+ failureCount++;
|
|
|
+ logger.error("第 {}/{} 条数据回传失败,summaryId: {}, 原因: {}",
|
|
|
+ i + 1, invoiceList.size(), summaryId, shopMap.get("msg"));
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ failureCount++;
|
|
|
+ logger.error("第 {}/{} 条数据处理异常,summaryId: {}", i + 1, invoiceList.size(), summaryId, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.info("一键回传票据任务执行完成,总计: {}, 成功: {}, 失败: {}",
|
|
|
+ invoiceList.size(), successCount, failureCount);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("一键回传票据任务执行异常", e);
|
|
|
+ } finally {
|
|
|
+ // 删除 Redis key,允许下次执行
|
|
|
+ redisService.deleteObject(redisKey);
|
|
|
+ logger.info("一键回传票据任务结束,Redis 锁已释放");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
|
|
|
}
|