package com.pj.api.invoice.service; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.codec.Base64; import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Snowflake; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSON; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.pj.api.invoice.bo.InvoiceApply; import com.pj.api.invoice.bo.InvoiceApplyCallBackSub; import com.pj.api.invoice.bo.InvoiceApplySub; import com.pj.api.invoice.bo.InvoiceApplySubDetail; import com.pj.api.invoice.utils.InvoiceUtils; import com.pj.api.wx.bo.Attach; import com.pj.api.wx.bo.PriceBO; import com.pj.current.config.InvoiceConfig; import com.pj.project.tb_fee_details.TbFeeDetails; import com.pj.project.tb_fee_details.TbFeeDetailsService; import com.pj.project.tb_fee_statistics.TbFeeStatistics; import com.pj.project.tb_invoice_details.TbInvoiceDetails; import com.pj.project.tb_invoice_details.TbInvoiceDetailsService; import com.pj.project.tb_invoice_info.TbInvoiceInfo; import com.pj.project.tb_invoice_info.TbInvoiceInfoService; import com.pj.project.tb_invoice_info.dto.FeeDeatilsGroup; import com.pj.project.tb_invoice_order.TbInvoiceOrder; import com.pj.project.tb_invoice_order.TbInvoiceOrderService; import com.pj.project.tb_order.TbOrder; import com.pj.project.tb_order.TbOrderService; import com.pj.project4sp.global.BusinessException; import com.pj.utils.sg.AjaxError; import com.pj.utils.so.SoMap; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; /** * Created with IntelliJ IDEA. * * @Auther: lzm * @Date: 2022/08/09/14:51 * @Description: */ @Service @Transactional @Slf4j public class InvoiceApplyService { @Resource TbInvoiceDetailsService tbInvoiceDetailsService; @Resource TbInvoiceInfoService tbInvoiceInfoService; @Resource TbInvoiceOrderService tbInvoiceOrderService; @Resource TbFeeDetailsService tbFeeDetailsService; @Resource InvoiceConfig invoiceConfig; public String applyInvoice(String infoId) { String code = this.preApply(infoId); if (!StrUtil.equals("200", code)) { throw new BusinessException("开票申请推送失败!"); } return code; } public String preApply(String infoId) { Date now = new Date(); Map param = new HashMap<>(); param.put("action", invoiceConfig.getApplyAction()); param.put("appid", invoiceConfig.getAppId()); param.put("timestamp", InvoiceUtils.date2StrByInt(now, "yyyyMMddHHmmssFFF")); param.put("transid", InvoiceUtils.genTransId()); String sign = InvoiceUtils.createSign(InvoiceUtils.getSortedMap(param), invoiceConfig.getAppSecret()); param.put("sign", sign); //拼装请求url String url = InvoiceUtils.getUrl(invoiceConfig.getApplyUrl(), param); TbInvoiceInfo info = tbInvoiceInfoService.getById(infoId); List invoiceDetails = tbInvoiceDetailsService.findByInfoId(infoId); //开始组装接口参数 InvoiceApply invoiceApply = new InvoiceApply(); invoiceApply.setRequestId(now.getTime() + "") .setBusinessSystemCode("SW_TEST") .setInterfaceCode("BILL.PUSH"); List applys = new ArrayList<>(); for (TbInvoiceDetails invoiceDetail : invoiceDetails) { InvoiceApplySub apply = new InvoiceApplySub(); apply.setBillNo(invoiceDetail.getId()).setPayType("微信支付") .setBillDate(DateUtil.format(now, "yyyy-MM-dd")) .setTotalAmount(invoiceDetail.getMoney()).setIncludeTaxFlag(1) .setAutoInvoice(1).setAutoMerge(1) .setInvoiceType("026") .setBuyerName(info.getEntityName()).setBuyerTaxpayerId(info.getTaxIdNo()) .setBuyerRecipientMail(info.getEmail()) .setBuyerProperty(0) .setBuyerBankAndAccount(info.getBank() + info.getBankNo()) .setTextField1(info.getCustomerName()) .setSellerName(invoiceConfig.getSellerName()) .setSellerTaxpayerId(invoiceConfig.getSellerTaxpayerId()) .setTaxationStyle(0) .setDrawer(invoiceConfig.getDrawer()) .setPayee(invoiceConfig.getPayee()).setReviewer(invoiceConfig.getReviewer()); //将所有开票订单的收费明细放在一个集合中,并对其分组 List orders = tbInvoiceOrderService.findByDetailId(invoiceDetail.getId()); List feeDetailsGroupList = grouping(orders); List applyDetails = new ArrayList<>(); Snowflake snowflake = IdUtil.getSnowflake(1, 1); for (FeeDeatilsGroup group : feeDetailsGroupList) { String detailId = snowflake.nextIdStr(); InvoiceApplySubDetail applyDetail = new InvoiceApplySubDetail(); applyDetail.setAmount(group.getItemPrice()) .setDetailId(detailId) .setGoodsName(group.getItemTypeName()) .setLineProperty(2) .setQuantity(group.getNum()) .setPrice(group.getUnitPrice()) .setTaxRate(group.getTaxRate().toString()); if (StrUtil.equals("0.09", applyDetail.getTaxRate())) { applyDetail.setRevenueCode(invoiceConfig.getCarTaxRateCode()); } else { applyDetail.setRevenueCode(invoiceConfig.getBusinessTaxRateCode()); } applyDetails.add(applyDetail); } apply.setBillDetail(applyDetails); applys.add(apply); } log.info("invoice apply url:" + url); String applysJson = JSONUtil.toJsonStr(applys); log.info("invoice apply data:" + applysJson); String applysBase64 = Base64.encode(applysJson); invoiceApply.setData(applysBase64); String paramStr = JSONUtil.toJsonStr(invoiceApply); log.info("invoice apply paramStr:" + paramStr); String result = HttpUtil.createPost(url).header("Content-Type", "application/json").body(paramStr).execute().body(); log.info("invoice apply result:" + result); JSONObject jsonResult = JSONUtil.parseObj(result); if (StrUtil.equals("0", jsonResult.getStr("code"))) { info.setApplyAble(1).setStatus(2); tbInvoiceInfoService.updateById(info); return "200"; } else { throw new AjaxError("开票失败"); } } private List grouping(List invoiceOrderList) { List feeDetailsList = new ArrayList<>(); for (TbInvoiceOrder invoiceOrder : invoiceOrderList) { List detailsList = tbFeeDetailsService.findByTransactionId(invoiceOrder.getTransactionId()); feeDetailsList.addAll(detailsList); } List list = new ArrayList<>(); for (TbFeeDetails detail : feeDetailsList) { FeeDeatilsGroup group = new FeeDeatilsGroup(); BeanUtil.copyProperties(detail, group); String hash = (detail.getItemTypeName() + detail.getUnitPrice()).hashCode() + ""; group.setGroupHash(hash); list.add(group); } Map> collect = list.stream() .collect(Collectors.groupingBy(FeeDeatilsGroup::getGroupHash)); List completeGroups = new ArrayList<>(); for (String key : collect.keySet()) { List partGroups = collect.get(key); FeeDeatilsGroup realGroup = new FeeDeatilsGroup(); realGroup.setItemTypeName(partGroups.get(0).getItemTypeName()) .setUnitPrice(partGroups.get(0).getUnitPrice()) .setTaxRate(partGroups.get(0).getTaxRate()); for (FeeDeatilsGroup partGroup : partGroups) { realGroup.setItemPrice(realGroup.getItemPrice().add(partGroup.getItemPrice())) .setNoTaxPrice(realGroup.getNoTaxPrice().add(partGroup.getNoTaxPrice())) .setTaxPrice(realGroup.getTaxPrice().add(partGroup.getTaxPrice())) .setNum(realGroup.getNum() + partGroup.getNum()); } completeGroups.add(realGroup); } return completeGroups; } public synchronized Map callBack(String sub) { log.info("进入开票回调:"); Map map = new LinkedHashMap<>(); JSONObject jsonObject = JSONUtil.parseObj(sub); InvoiceApplyCallBackSub callBackSub = JSONUtil.toBean(jsonObject, InvoiceApplyCallBackSub.class); TbInvoiceDetails invoiceDetail = tbInvoiceDetailsService.getById(callBackSub.getBillNo()); if (invoiceDetail == null) { log.info("开票信息子记录{}不存在:", callBackSub.getBillNo()); map.put("code", 500); map.put("message", "失败,开票信息数据异常"); return map; } if (invoiceDetail.getIsApply() == 2) { log.info("重复回调,开票信息子记录{}已开票成功:", callBackSub.getBillNo()); } else { invoiceDetail.setIsApply(2).setInvoiceNo(callBackSub.getInvoiceNum()) .setInvoiceCode(callBackSub.getInvoiceCode()) .setFileUrl(callBackSub.getInvoiceFileUrl()).setImageUrl(callBackSub.getInvoiceImageUrl()); tbInvoiceDetailsService.updateById(invoiceDetail); TbInvoiceInfo info = tbInvoiceInfoService.getById(invoiceDetail.getInfoId()); // List infoAllDetails = tbInvoiceDetailsService.findByInfoId(info.getId()); // String newInvoiceNo = ""; // for (TbInvoiceDetails detail : infoAllDetails) { // newInvoiceNo = StrUtil.isEmpty(newInvoiceNo) ? // detail.getInvoiceNo() : newInvoiceNo+","+detail.getInvoiceNo(); // } String status = callBackSub.getInvoiceStatus(); if ("0".equals(status)) { //开票成功 info.setStatus(1); info.setIsApply(2); } else if ("".equals(status)){ info.setStatus(Integer.parseInt(status)); } tbInvoiceInfoService.updateById(info); String oldInvoiceNo = info.getInvoiceNo(); String newInvoiceNo = StrUtil.isEmpty(oldInvoiceNo) ? callBackSub.getInvoiceNum() : oldInvoiceNo + "," + callBackSub.getInvoiceNum(); SoMap so = new SoMap(); so.put("id", info.getId()); so.put("invoiceTime", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")); so.put("invoiceNo", newInvoiceNo); tbInvoiceInfoService.complete(so); } map.put("code", 200); map.put("message", "成功"); return map; } }