|
@@ -6,12 +6,8 @@ import cn.hutool.core.date.DateUtil;
|
|
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
|
|
import cn.hutool.core.io.IoUtil;
|
|
import cn.hutool.core.io.IoUtil;
|
|
|
import cn.hutool.core.util.RandomUtil;
|
|
import cn.hutool.core.util.RandomUtil;
|
|
|
-import cn.hutool.core.util.URLUtil;
|
|
|
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
|
import com.baomidou.dynamic.datasource.annotation.DS;
|
|
import com.baomidou.dynamic.datasource.annotation.DS;
|
|
|
-import com.baomidou.dynamic.datasource.annotation.DSTransactional;
|
|
|
|
|
-import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
|
|
|
|
|
-import com.kym.common.config.WxFapiaoConfig;
|
|
|
|
|
import com.kym.common.config.WxPayConfig;
|
|
import com.kym.common.config.WxPayConfig;
|
|
|
import com.kym.common.constant.ResponseEnum;
|
|
import com.kym.common.constant.ResponseEnum;
|
|
|
import com.kym.common.exception.BusinessException;
|
|
import com.kym.common.exception.BusinessException;
|
|
@@ -20,9 +16,7 @@ import com.kym.common.utils.LambadaTools;
|
|
|
import com.kym.common.utils.OrderUtils;
|
|
import com.kym.common.utils.OrderUtils;
|
|
|
import com.kym.entity.miniapp.Account;
|
|
import com.kym.entity.miniapp.Account;
|
|
|
import com.kym.entity.miniapp.*;
|
|
import com.kym.entity.miniapp.*;
|
|
|
-import com.kym.entity.wechat.*;
|
|
|
|
|
import com.kym.service.admin.ActivityService;
|
|
import com.kym.service.admin.ActivityService;
|
|
|
-import com.kym.service.admin.InvoiceDetailService;
|
|
|
|
|
import com.kym.common.cache.PlatformCache;
|
|
import com.kym.common.cache.PlatformCache;
|
|
|
import com.kym.service.miniapp.*;
|
|
import com.kym.service.miniapp.*;
|
|
|
import com.kym.service.platform.PlatformApiService;
|
|
import com.kym.service.platform.PlatformApiService;
|
|
@@ -89,8 +83,6 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
|
|
|
|
|
private final WxPayConfig conf;
|
|
private final WxPayConfig conf;
|
|
|
|
|
|
|
|
- private final WxFapiaoConfig fapiaoConfig;
|
|
|
|
|
-
|
|
|
|
|
private final WalletDetailService walletDetailService;
|
|
private final WalletDetailService walletDetailService;
|
|
|
|
|
|
|
|
private final PayLogService payLogService;
|
|
private final PayLogService payLogService;
|
|
@@ -101,42 +93,29 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
|
|
|
|
|
private final RefundLogService refundLogService;
|
|
private final RefundLogService refundLogService;
|
|
|
|
|
|
|
|
- private final InvoiceService invoiceService;
|
|
|
|
|
-
|
|
|
|
|
- private final InvoiceTitleService invoiceTitleService;
|
|
|
|
|
-
|
|
|
|
|
private final PlatformApiService platformApiService;
|
|
private final PlatformApiService platformApiService;
|
|
|
|
|
|
|
|
private final ActivityService activityService;
|
|
private final ActivityService activityService;
|
|
|
|
|
|
|
|
private final UserRechargeRightsService userRechargeRightsService;
|
|
private final UserRechargeRightsService userRechargeRightsService;
|
|
|
|
|
|
|
|
- private final InvoiceDetailService invoiceDetailService;
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 微信支付专用,支持自动签名验签解密等
|
|
|
|
|
- */
|
|
|
|
|
private OkHttpClientAdapter wxHttpClient;
|
|
private OkHttpClientAdapter wxHttpClient;
|
|
|
|
|
|
|
|
|
|
|
|
|
- public WxPayServiceImpl(WxPayConfig conf, WxFapiaoConfig fapiaoConfig, WalletDetailService walletDetailService,
|
|
|
|
|
|
|
+ public WxPayServiceImpl(WxPayConfig conf, WalletDetailService walletDetailService,
|
|
|
PayLogService payLogService, AccountService accountService, ChargeOrderService chargeOrderService,
|
|
PayLogService payLogService, AccountService accountService, ChargeOrderService chargeOrderService,
|
|
|
- RefundLogService refundLogService, InvoiceService invoiceService, InvoiceTitleService invoiceTitleService,
|
|
|
|
|
- PlatformApiService platformApiService, ActivityService activityService, UserRechargeRightsService userRechargeRightsService, InvoiceDetailService invoiceDetailService) {
|
|
|
|
|
|
|
+ RefundLogService refundLogService,
|
|
|
|
|
+ PlatformApiService platformApiService, ActivityService activityService, UserRechargeRightsService userRechargeRightsService) {
|
|
|
this.conf = conf;
|
|
this.conf = conf;
|
|
|
- this.fapiaoConfig = fapiaoConfig;
|
|
|
|
|
this.walletDetailService = walletDetailService;
|
|
this.walletDetailService = walletDetailService;
|
|
|
this.payLogService = payLogService;
|
|
this.payLogService = payLogService;
|
|
|
this.accountService = accountService;
|
|
this.accountService = accountService;
|
|
|
this.chargeOrderService = chargeOrderService;
|
|
this.chargeOrderService = chargeOrderService;
|
|
|
this.refundLogService = refundLogService;
|
|
this.refundLogService = refundLogService;
|
|
|
- this.invoiceService = invoiceService;
|
|
|
|
|
- this.invoiceTitleService = invoiceTitleService;
|
|
|
|
|
this.platformApiService = platformApiService;
|
|
this.platformApiService = platformApiService;
|
|
|
this.activityService = activityService;
|
|
this.activityService = activityService;
|
|
|
this.userRechargeRightsService = userRechargeRightsService;
|
|
this.userRechargeRightsService = userRechargeRightsService;
|
|
|
- this.invoiceDetailService = invoiceDetailService;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -783,365 +762,4 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //================================================================发票=====================================================================
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 微信电子发票配置开发选项,例如回调地址、全部账单展示开发票入口开关
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public Object devConfig() {
|
|
|
|
|
- // 创建卡券模版
|
|
|
|
|
- cardTemplate();
|
|
|
|
|
- var headers = new HttpHeaders();
|
|
|
|
|
- headers.addHeader("Accept", "application/json");
|
|
|
|
|
- headers.addHeader("Content-Type", "application/json");
|
|
|
|
|
- var params = JSONObject.of("callback_url", "https://www.kuaiyuman.cn/api/invoice/notify", "show_fapiao_cell", false);
|
|
|
|
|
- var requestBody = new JsonRequestBody.Builder().body(params.toJSONString()).build();
|
|
|
|
|
- var res = wxHttpClient.patch(headers, fapiaoConfig.getDevConfig(), requestBody, JSONObject.class);
|
|
|
|
|
- LOGGER.info("微信电子发票开发设置:{}", res.toString());
|
|
|
|
|
- return res.getServiceResponse();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 创建电子发票卡券模版
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public void cardTemplate() {
|
|
|
|
|
- var headers = new HttpHeaders();
|
|
|
|
|
- headers.addHeader("Accept", "application/json");
|
|
|
|
|
- headers.addHeader("Content-Type", "application/json");
|
|
|
|
|
- var params = JSONObject.of(
|
|
|
|
|
- "card_appid", "wx93b0ef1be901bd19", // 公众号appid,不是小程序appid
|
|
|
|
|
- "card_template_information", JSONObject.of(
|
|
|
|
|
- "logo_url", "https://kym-static.oss-cn-shenzhen.aliyuncs.com/logo/K7.png"
|
|
|
|
|
- )
|
|
|
|
|
- );
|
|
|
|
|
- var requestBody = new JsonRequestBody.Builder().body(params.toJSONString()).build();
|
|
|
|
|
- var res = wxHttpClient.post(headers, fapiaoConfig.getCardTemplate(), requestBody, JSONObject.class);
|
|
|
|
|
- LOGGER.info("创建电子发票卡券模版:{}", res);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 查询商户配置的开发选项
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public Object getDevConfig() {
|
|
|
|
|
- var headers = new HttpHeaders();
|
|
|
|
|
- headers.addHeader("Accept", "application/json");
|
|
|
|
|
- headers.addHeader("Content-Type", "application/json");
|
|
|
|
|
- var res = wxHttpClient.get(headers, fapiaoConfig.getDevConfig(), JSONObject.class);
|
|
|
|
|
- LOGGER.info("查询微信电子发票开发设置:{}", res.toString());
|
|
|
|
|
- return res;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取用户抬头信息填写URL
|
|
|
|
|
- *
|
|
|
|
|
- * @param invoice
|
|
|
|
|
- * @return
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public TitleUrl titleUrl(Invoice invoice) {
|
|
|
|
|
- var headers = new HttpHeaders();
|
|
|
|
|
- var params = Map.of(
|
|
|
|
|
- "fapiao_apply_id", invoice.getApplyId(),
|
|
|
|
|
- "appid", conf.getAppid(),
|
|
|
|
|
- "openid", invoice.getOpenid(),
|
|
|
|
|
- "total_amount", invoice.getInvoiceAmount(),
|
|
|
|
|
- "source", "MINIPROGRAM"
|
|
|
|
|
- );
|
|
|
|
|
- headers.addHeader("Accept", "application/json");
|
|
|
|
|
- var res = wxHttpClient.get(headers, fapiaoConfig.getTitleUrl().concat("?").concat(URLUtil.buildQuery(params, StandardCharsets.UTF_8)), TitleUrl.class);
|
|
|
|
|
- return res.getServiceResponse();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 处理发票抬头填写完成通知
|
|
|
|
|
- * event_type为FAPIAO.USER_APPLIED
|
|
|
|
|
- *
|
|
|
|
|
- * @param notifyRes
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public void titleWriteNotice(Object[] notifyRes) {
|
|
|
|
|
- try {
|
|
|
|
|
- TitleWriteNotification titleWriteNotification = ((NotificationParser) notifyRes[1]).parse((RequestParam) notifyRes[0], TitleWriteNotification.class);
|
|
|
|
|
-
|
|
|
|
|
- // 查询用户填写的抬头信息
|
|
|
|
|
- var applyId = titleWriteNotification.getFapiaoApplyId();
|
|
|
|
|
- LOGGER.info("回调成功,applyId:{}", applyId);
|
|
|
|
|
- var buyerInformation = userTitle(applyId);
|
|
|
|
|
-
|
|
|
|
|
- // 更新invoice表数据
|
|
|
|
|
- var invoice = invoiceService.lambdaQuery().eq(Invoice::getApplyId, applyId).one();
|
|
|
|
|
- invoice.setInvoiceType(buyerInformation.getType())
|
|
|
|
|
- .setInvoiceTitle(buyerInformation.getName())
|
|
|
|
|
- .setTaxId(buyerInformation.getTaxpayer_id())
|
|
|
|
|
- .setAddress(buyerInformation.getAddress())
|
|
|
|
|
- .setTelephone(buyerInformation.getTelephone())
|
|
|
|
|
- .setBankName(buyerInformation.getBank_name())
|
|
|
|
|
- .setBankAccount(buyerInformation.getBank_account())
|
|
|
|
|
- .setEmail(buyerInformation.getEmail())
|
|
|
|
|
- .setPhone(buyerInformation.getPhone());
|
|
|
|
|
- invoiceService.updateById(invoice);
|
|
|
|
|
-
|
|
|
|
|
- // 将发票抬头写入用户抬头表
|
|
|
|
|
- var invoiceTitle = new InvoiceTitle()
|
|
|
|
|
- .setUserId(invoice.getUserId())
|
|
|
|
|
- .setInvoiceType(buyerInformation.getType())
|
|
|
|
|
- .setInvoiceTitle(buyerInformation.getName())
|
|
|
|
|
- .setTaxId(buyerInformation.getTaxpayer_id())
|
|
|
|
|
- .setTelephone(buyerInformation.getTelephone())
|
|
|
|
|
- .setAddress(buyerInformation.getAddress())
|
|
|
|
|
- .setBankName(buyerInformation.getBank_name())
|
|
|
|
|
- .setBankAccount(buyerInformation.getBank_account())
|
|
|
|
|
- .setEmail(buyerInformation.getEmail())
|
|
|
|
|
- .setPhone(buyerInformation.getPhone());
|
|
|
|
|
- boolean exist = invoiceTitleService.lambdaQuery()
|
|
|
|
|
- .eq(InvoiceTitle::getUserId, invoiceTitle.getUserId())
|
|
|
|
|
- .eq(InvoiceTitle::getTaxId, invoiceTitle.getTaxId())
|
|
|
|
|
- .exists();
|
|
|
|
|
- if (!exist) {
|
|
|
|
|
- invoiceTitleService.save(invoiceTitle);
|
|
|
|
|
- }
|
|
|
|
|
- // 运营后台财务操作开具发票
|
|
|
|
|
- } catch (ValidationException e) {
|
|
|
|
|
- // 签名验证失败,返回 401 UNAUTHORIZED 状态码
|
|
|
|
|
- LOGGER.error("微信处理发票抬头填写完成通知验签失败", e);
|
|
|
|
|
- throw new BusinessException("验签失败");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取用户填写的抬头信息
|
|
|
|
|
- *
|
|
|
|
|
- * @param applyId
|
|
|
|
|
- * @return
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public FaPiao.BuyerInformation userTitle(String applyId) {
|
|
|
|
|
- var headers = new HttpHeaders();
|
|
|
|
|
- headers.addHeader("Accept", "application/json");
|
|
|
|
|
- var res = wxHttpClient.get(headers, fapiaoConfig.getUserTitle().formatted(applyId), FaPiao.BuyerInformation.class);
|
|
|
|
|
- LOGGER.info("用户发票申请applyId:{},抬头信息:{}", applyId, res);
|
|
|
|
|
- return res.getServiceResponse();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取商户开票基础信息
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public InvoiceBaseInfo baseInformation() {
|
|
|
|
|
- var headers = new HttpHeaders();
|
|
|
|
|
- headers.addHeader("Accept", "application/json");
|
|
|
|
|
- var res = wxHttpClient.get(headers, fapiaoConfig.getBaseInformation(), InvoiceBaseInfo.class);
|
|
|
|
|
- return res.getServiceResponse();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取商户可开具的商品和服务税收分类编码对照表
|
|
|
|
|
- */
|
|
|
|
|
- private TaxCodes getTaxCodes() {
|
|
|
|
|
- var headers = new HttpHeaders();
|
|
|
|
|
- headers.addHeader("Accept", "application/json");
|
|
|
|
|
- var url = fapiaoConfig.getTaxCodes().concat("?offset=%d&limit=%d").formatted(0, 5);
|
|
|
|
|
- var res = wxHttpClient.get(headers, url, TaxCodes.class);
|
|
|
|
|
- return res.getServiceResponse();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 开具电子发票
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- @DS("db-miniapp")
|
|
|
|
|
- public void fapiaoApplication(String invoiceId) {
|
|
|
|
|
- var invoice = invoiceService.lambdaQuery().eq(Invoice::getId, invoiceId).one();
|
|
|
|
|
- // 开票状态校验
|
|
|
|
|
- if (!invoice.getStatus().equals(Invoice.STATUS_待开票)) {
|
|
|
|
|
- throw new BusinessException("发票状态为开票中或已开票");
|
|
|
|
|
- }
|
|
|
|
|
- // 记录开票人
|
|
|
|
|
- invoiceService.lambdaUpdate().set(Invoice::getBiller, StpUtil.getSession().getString("username")).eq(Invoice::getId, invoice.getId()).update();
|
|
|
|
|
-
|
|
|
|
|
- // 订单金额+ ,服务费优惠金额- 服务费优惠金额单独一个item,金额为负数
|
|
|
|
|
- var itemList = new ArrayList<FaPiao.FaPiaoInfomation.IssueItem>();
|
|
|
|
|
- // 电费 税务商品编码:1100101020000000000
|
|
|
|
|
- var elecMoney = invoice.getOrderDetails().stream().mapToInt(InvoiceOrderDetail::getElecMoney).sum();
|
|
|
|
|
- // 必须为正数
|
|
|
|
|
- if (elecMoney > 0) {
|
|
|
|
|
- var elecMoneyItem = new FaPiao.FaPiaoInfomation.IssueItem().setTotal_amount(elecMoney).setTax_code("1100101020000000000");
|
|
|
|
|
- itemList.add(elecMoneyItem);
|
|
|
|
|
- }
|
|
|
|
|
- // 服务费 税务商品编码:3040100000000000000
|
|
|
|
|
- var serviceMoney = invoice.getOrderDetails().stream().mapToInt(InvoiceOrderDetail::getServiceMoney).sum();
|
|
|
|
|
- // 必须为正数
|
|
|
|
|
- if (serviceMoney > 0) {
|
|
|
|
|
- var serviceMoneyItem = new FaPiao.FaPiaoInfomation.IssueItem().setTotal_amount(serviceMoney).setTax_code("3040100000000000000");
|
|
|
|
|
- itemList.add(serviceMoneyItem);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 服务费优惠 税务商品编码:3040100000000000000 注意:折扣行必须是被折扣行的下一行
|
|
|
|
|
- var serviceMoneyDiscount = -invoice.getOrderDetails().stream().mapToInt(InvoiceOrderDetail::getServiceMoneyDiscount).sum();
|
|
|
|
|
- // 必须为负数
|
|
|
|
|
- if (serviceMoneyDiscount < 0) {
|
|
|
|
|
- var serviceMoneyDiscountItem = new FaPiao.FaPiaoInfomation.IssueItem().setTotal_amount(serviceMoneyDiscount).setTax_code("3040100000000000000").setDiscount(true);
|
|
|
|
|
- itemList.add(serviceMoneyDiscountItem);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- var headers = new HttpHeaders();
|
|
|
|
|
- headers.addHeader("Accept", "application/json");
|
|
|
|
|
- headers.addHeader("Content-Type", "application/json");
|
|
|
|
|
- headers.addHeader("Wechatpay-Serial", conf.getMchsn());
|
|
|
|
|
-
|
|
|
|
|
- // 客户开票信息
|
|
|
|
|
- var buyerInformation = new FaPiao.BuyerInformation()
|
|
|
|
|
- .setType(invoice.getInvoiceType())
|
|
|
|
|
- .setName(invoice.getInvoiceTitle())
|
|
|
|
|
- .setTaxpayer_id(invoice.getTaxId())
|
|
|
|
|
- .setTelephone(invoice.getTelephone())
|
|
|
|
|
- .setAddress(invoice.getAddress())
|
|
|
|
|
- .setBank_name(invoice.getBankName())
|
|
|
|
|
- .setBank_account(invoice.getBankAccount());
|
|
|
|
|
-
|
|
|
|
|
- // 发票信息
|
|
|
|
|
- var fapiaoInformation = new FaPiao.FaPiaoInfomation();
|
|
|
|
|
- // fapiao_id为invoice.id
|
|
|
|
|
- fapiaoInformation.setFapiao_id(String.valueOf(invoice.getId()))
|
|
|
|
|
- .setTotal_amount(invoice.getInvoiceAmount())
|
|
|
|
|
- .setItems(itemList);
|
|
|
|
|
-
|
|
|
|
|
- // 请求参数
|
|
|
|
|
- var fapiao = new FaPiao()
|
|
|
|
|
- .setScene("WITHOUT_WECHATPAY")
|
|
|
|
|
- .setFapiao_apply_id(invoice.getApplyId())
|
|
|
|
|
- .setBuyer_information(buyerInformation)
|
|
|
|
|
- .setFapiao_information(List.of(fapiaoInformation));
|
|
|
|
|
-
|
|
|
|
|
- var requestBody = new JsonRequestBody.Builder().body(JSONObject.toJSONString(fapiao)).build();
|
|
|
|
|
- wxHttpClient.post(headers, fapiaoConfig.getFapiaoApplications(), requestBody, null);
|
|
|
|
|
- // 修改发票状态为开票中
|
|
|
|
|
- invoiceService.lambdaUpdate().set(Invoice::getStatus, Invoice.STATUS_开票中).eq(Invoice::getId, invoiceId).update();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 微信开票结果通知
|
|
|
|
|
- * event_type为FAPIAO.ISSUED
|
|
|
|
|
- *
|
|
|
|
|
- * @param notifyRes
|
|
|
|
|
- * @return
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- @DSTransactional
|
|
|
|
|
- public void wxInvoiceNotify(Object[] notifyRes) {
|
|
|
|
|
- try {
|
|
|
|
|
- InvoiceNotification invoiceNotification = ((NotificationParser) notifyRes[1]).parse((RequestParam) notifyRes[0], InvoiceNotification.class);
|
|
|
|
|
- LOGGER.info("微信开具发票结果通知回调{}:验签解密完毕,数据:\n{}", notifyRes[2], invoiceNotification);
|
|
|
|
|
- // 业务逻辑
|
|
|
|
|
- if (invoiceNotification.getFapiaoInformation().get(0).getFapiaoStatus().equals(InvoiceNotification.FapiaoStatus.ISSUED.name())) {
|
|
|
|
|
- // 更新发票状态
|
|
|
|
|
- invoiceService.lambdaUpdate().set(Invoice::getStatus, Invoice.STATUS_已开票).eq(Invoice::getApplyId, invoiceNotification.getFapiaoApplyId()).update();
|
|
|
|
|
- var invoice = invoiceService.lambdaQuery().eq(Invoice::getApplyId, invoiceNotification.getFapiaoApplyId()).one();
|
|
|
|
|
- // 更新订单开票状态为已开票
|
|
|
|
|
- var chargeOrderSeqs = invoice.getOrderDetails().stream().map(InvoiceOrderDetail::getStartChargeSeq).toList();
|
|
|
|
|
- if (!CommUtil.isEmptyOrNull(chargeOrderSeqs)) {
|
|
|
|
|
- chargeOrderService.lambdaUpdate().set(ChargeOrder::getInvoiceStatus, ChargeOrder.INVOICE_STATUS_已开票).in(ChargeOrder::getStartChargeSeq, chargeOrderSeqs).update();
|
|
|
|
|
- }
|
|
|
|
|
- /*
|
|
|
|
|
- * 销项发票excel数据中需包含:
|
|
|
|
|
- * 1.开票日期
|
|
|
|
|
- * 2.购买方名称及税号
|
|
|
|
|
- * 3.开票明细、金额、税额
|
|
|
|
|
- * 4.开票优惠明细、金额、税额
|
|
|
|
|
- * 5.发票状态是否作废或者红冲
|
|
|
|
|
- */
|
|
|
|
|
- var fapiaoApplications = queryFapiao(invoice.getApplyId());
|
|
|
|
|
- // 手动切换数据源
|
|
|
|
|
- DynamicDataSourceContextHolder.push("db-admin");
|
|
|
|
|
- invoiceDetailService.updateInvoiceDetail(invoice.getApplyId(), fapiaoApplications);
|
|
|
|
|
- DynamicDataSourceContextHolder.poll();
|
|
|
|
|
- } else {
|
|
|
|
|
- LOGGER.error("微信开具发票失败:{}", invoiceNotification);
|
|
|
|
|
- }
|
|
|
|
|
- } catch (ValidationException e) {
|
|
|
|
|
- // 签名验证失败,返回 401 UNAUTHORIZED 状态码
|
|
|
|
|
- LOGGER.error("微信开具发票结果通知验签失败", e);
|
|
|
|
|
- throw new BusinessException("验签失败");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 接收电子发票相关回调通知
|
|
|
|
|
- *
|
|
|
|
|
- * @param request
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
- public void invoiceNotify(HttpServletRequest request) {
|
|
|
|
|
- var notifyRes = handleWxNotify(request);
|
|
|
|
|
- var requestParam = (RequestParam) notifyRes[0];
|
|
|
|
|
- Notification notification = JSONObject.parseObject(requestParam.getBody(), Notification.class);
|
|
|
|
|
- switch (notification.getEventType()) {
|
|
|
|
|
- // 发票抬头填写完成
|
|
|
|
|
- case "FAPIAO.USER_APPLIED" -> titleWriteNotice(notifyRes);
|
|
|
|
|
- // 发票开具结果
|
|
|
|
|
- case "FAPIAO.ISSUED" -> wxInvoiceNotify(notifyRes);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 下载发票,下载链接30s有效
|
|
|
|
|
- *
|
|
|
|
|
- * @param invoiceId
|
|
|
|
|
- * @return
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public Map<String, String> downloadInvoice(String invoiceId) {
|
|
|
|
|
- var invoice = invoiceService.getById(invoiceId);
|
|
|
|
|
- var download = getFapiaoDownloadInfo(invoice.getApplyId());
|
|
|
|
|
- var downloadInfo = download.getFapiao_download_info_list().get(0);
|
|
|
|
|
- // 查询电子发票
|
|
|
|
|
- var fapiaoApplications = queryFapiao(invoice.getApplyId());
|
|
|
|
|
-
|
|
|
|
|
- var params = "&mchid=%s&openid=%s&invoice_code=%s&invoice_no=%s&fapiao_id=%s";
|
|
|
|
|
- // openid 通过查询电子发票接口获取的card_openid
|
|
|
|
|
- var fapiao = fapiaoApplications.getFapiao_information().get(0);
|
|
|
|
|
- var downloadUrl = downloadInfo.getDownload_url().concat(params.formatted(conf.getMchid(),
|
|
|
|
|
- fapiao.getCard_information().getCard_openid(), fapiao.getBlue_fapiao().getFapiao_code(),
|
|
|
|
|
- fapiao.getBlue_fapiao().getFapiao_number(), invoice.getId()));
|
|
|
|
|
- return Map.of("downloadUrl", downloadUrl);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取发票下载信息
|
|
|
|
|
- *
|
|
|
|
|
- * @param applyId
|
|
|
|
|
- * @return
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public FapiaoDownload getFapiaoDownloadInfo(String applyId) {
|
|
|
|
|
- var downloadUrl = fapiaoConfig.getFapiaoFiles().formatted(applyId);
|
|
|
|
|
- var headers = new HttpHeaders();
|
|
|
|
|
- headers.addHeader("Accept", "application/json");
|
|
|
|
|
- var res = wxHttpClient.get(headers, downloadUrl, FapiaoDownload.class);
|
|
|
|
|
- return res.getServiceResponse();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 查询电子发票
|
|
|
|
|
- *
|
|
|
|
|
- * @param applyId
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public FapiaoApplications queryFapiao(String applyId) {
|
|
|
|
|
- var headers = new HttpHeaders();
|
|
|
|
|
- headers.addHeader("Accept", "application/json");
|
|
|
|
|
- headers.addHeader("Content-Type", "application/json");
|
|
|
|
|
- var res = wxHttpClient.get(headers, fapiaoConfig.getQueryFapiao().formatted(applyId), FapiaoApplications.class);
|
|
|
|
|
- return res.getServiceResponse();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
}
|
|
}
|