package com.doumee.service.business.impl;
|
|
import com.doumee.core.constants.Constants;
|
import com.doumee.core.constants.ResponseStatus;
|
import com.doumee.core.exception.BusinessException;
|
import com.doumee.core.model.PageData;
|
import com.doumee.core.model.PageWrap;
|
import com.doumee.core.utils.DateUtil;
|
import com.doumee.core.utils.Utils;
|
import com.doumee.core.wx.WxMiniConfig;
|
import com.doumee.core.wx.WxPayProperties;
|
import com.doumee.dao.business.WxBillDetailMapper;
|
import com.doumee.dao.business.WxBillMapper;
|
import com.doumee.dao.business.model.Goodsorder;
|
import com.doumee.dao.business.model.WxBill;
|
import com.doumee.dao.business.model.WxBillDetail;
|
import com.doumee.service.business.WxBillService;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.github.binarywang.wxpay.bean.request.WxPayDownloadBillRequest;
|
import com.github.binarywang.wxpay.bean.result.WxPayBillInfo;
|
import com.github.binarywang.wxpay.bean.result.WxPayBillResult;
|
import com.github.binarywang.wxpay.exception.WxPayException;
|
import lombok.Synchronized;
|
import org.apache.commons.lang3.StringUtils;
|
import org.checkerframework.checker.units.qual.C;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.CollectionUtils;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.util.*;
|
|
/**
|
* Service实现
|
* @author 江蹄蹄
|
* @date 2023/09/27 18:08
|
*/
|
@Service
|
public class WxBillServiceImpl implements WxBillService {
|
|
@Autowired
|
private WxBillMapper wxBillMapper;
|
@Autowired
|
private WxBillDetailMapper wxBillDetailMapper;
|
@Override
|
public String create(WxBill wxBill) {
|
wxBillMapper.insert(wxBill);
|
return wxBill.getId();
|
}
|
|
@Override
|
public void deleteById(String id) {
|
wxBillMapper.deleteById(id);
|
}
|
|
@Override
|
public void delete(WxBill wxBill) {
|
UpdateWrapper<WxBill> deleteWrapper = new UpdateWrapper<>(wxBill);
|
wxBillMapper.delete(deleteWrapper);
|
}
|
|
@Override
|
public void deleteByIdInBatch(List<String> ids) {
|
if (CollectionUtils.isEmpty(ids)) {
|
return;
|
}
|
wxBillMapper.deleteBatchIds(ids);
|
}
|
|
@Override
|
public void updateById(WxBill wxBill) {
|
wxBillMapper.updateById(wxBill);
|
}
|
|
@Override
|
public void updateByIdInBatch(List<WxBill> wxBills) {
|
if (CollectionUtils.isEmpty(wxBills)) {
|
return;
|
}
|
for (WxBill wxBill: wxBills) {
|
this.updateById(wxBill);
|
}
|
}
|
|
@Override
|
public WxBill findById(String id) {
|
return wxBillMapper.selectById(id);
|
}
|
|
@Override
|
public WxBill findOne(WxBill wxBill) {
|
QueryWrapper<WxBill> wrapper = new QueryWrapper<>(wxBill);
|
return wxBillMapper.selectOne(wrapper.last(" limit 1"));
|
}
|
|
@Override
|
public List<WxBill> findList(WxBill wxBill) {
|
QueryWrapper<WxBill> wrapper = new QueryWrapper<>(wxBill);
|
return wxBillMapper.selectList(wrapper);
|
}
|
@Override
|
public List<WxBill> getTotalBill(WxBill param) {
|
//获取汇总统计
|
WxBill bill = getTotalDataByDate(param);
|
WxBill bill1 = initBillData();//记录交易实收统计数据
|
bill1.setSumBill(bill.getSumBill());//订单数量
|
bill1.setSumTotalFee(bill.getSumTotalFee());//交易金额
|
bill1.setSumCmmsAmt(bill.getSumCmmsAmt());//交易手续费
|
bill1.setSumSuccessFee(bill.getSumSuccessFee());//成功交易金额
|
|
WxBill bill2 = initBillData();//记录退款统计数据
|
bill2.setSumRefundBill(bill.getSumRefundBill());//退款笔数
|
bill2.setSumRefundCmmsAmt(bill.getSumRefundCmmsAmt());//退款手续费
|
bill2.setSumRefundFee(bill.getSumRefundFee());//退款金额
|
|
WxBill bill3 = initBillData();
|
bill3.setSumBill(bill.getSumBill());
|
bill3.setSumSuccessFee(bill.getSumSuccessFee());
|
bill3.setSumCmmsAmt(bill.getSumCmmsAmt());
|
bill3.setSumTotalFee(bill.getSumTotalFee());
|
bill3.setSumRefundBill(bill.getSumRefundBill());//退款笔数
|
bill3.setSumRefundCmmsAmt(Constants.formatDecimalNum(bill.getSumRefundCmmsAmt()).add(Constants.formatDecimalNum(bill.getSumCmmsAmt())));//手续费
|
bill3.setSumRefundFee(bill.getSumRefundFee());//退款金额
|
bill3.setTotal(bill.getTotal());
|
bill3.setBikeFee(bill.getBikeFee());
|
|
QueryWrapper<WxBillDetail> queryWrapper = new QueryWrapper<>();
|
queryWrapper.lambda().ge(param.getStartDate() !=null,WxBillDetail::getPid,DateUtil.getShortDateStr(param.getStartDate()));
|
queryWrapper.lambda().le(param.getEndDate() !=null,WxBillDetail::getPid,DateUtil.getShortDateStr(param.getEndDate()));
|
queryWrapper.lambda().ne(WxBillDetail::getAppid, WxMiniConfig.wxPayV2Service.getConfig().getSubAppId());//非自行车收入统计
|
queryWrapper.lambda().groupBy(WxBillDetail::getBillStatus);
|
queryWrapper.select( "count(id) as sum_bill"
|
,"sum(settlement_total_fee) as settlement_total_fee"
|
,"sum(refund_fee) as refund_fee"
|
,"sum(cmms_amt) as cmms_amt" ,"bill_status");
|
List<WxBillDetail> detailList = wxBillDetailMapper.selectList(queryWrapper);
|
WxBill bill4 = initBillData();//记录交易实收统计数据
|
if(detailList!=null){
|
for(WxBillDetail detail : detailList){
|
if(StringUtils.equals(detail.getBillStatus(), "SUCCESS")){
|
//实收数据
|
bill4.setSumBill( detail.getSumBill());//交易笔数
|
bill4.setSumSuccessFee(Constants.formatDecimalNum(detail.getSettlementTotalFee()));//交易金额
|
bill4.setSumCmmsAmt(Constants.formatDecimalNum(detail.getCmmsAmt()));//交易手续费
|
} else if(StringUtils.equals(detail.getBillStatus(), "REFUND") || StringUtils.equals(detail.getBillStatus(), "REVOKED")){
|
//退款数据
|
bill4.setSumRefundBill(Constants.formatIntegerNum(bill4.getSumRefundBill())+detail.getSumBill());//退款笔数
|
bill4.setSumRefundFee(Constants.formatDecimalNum(bill4.getSumRefundFee()).add(Constants.formatDecimalNum(detail.getRefundFee())));
|
bill4.setSumRefundCmmsAmt(Constants.formatDecimalNum(bill4.getSumRefundCmmsAmt()).add(Constants.formatDecimalNum(Constants.formatDecimalNum(detail.getCmmsAmt()))));//退款手续费
|
}
|
}
|
//结算金额
|
bill4.setTotal(bill4.getSumSuccessFee()
|
.subtract(bill4.getSumRefundFee())
|
.subtract(bill4.getSumCmmsAmt())
|
.subtract(bill4.getSumRefundCmmsAmt()));
|
}
|
|
List<WxBill> list = new ArrayList<>();
|
list.add(bill1);//实收交易
|
list.add(bill2);//退款汇总
|
list.add(bill3);//实收退款总计
|
list.add(bill4);//非自行车收入
|
return list;
|
}
|
|
@Override
|
public PageData<WxBill> findPage(PageWrap<WxBill> pageWrap) {
|
IPage<WxBill> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
|
QueryWrapper<WxBill> queryWrapper = new QueryWrapper<>();
|
Utils.MP.blankToNull(pageWrap.getModel());
|
if (pageWrap.getModel().getId() != null) {
|
queryWrapper.lambda().eq(WxBill::getId, pageWrap.getModel().getId());
|
}
|
if (pageWrap.getModel().getSumBill() != null) {
|
queryWrapper.lambda().eq(WxBill::getSumBill, pageWrap.getModel().getSumBill());
|
}
|
if (pageWrap.getModel().getSumRefundBill() != null) {
|
queryWrapper.lambda().eq(WxBill::getSumRefundBill, pageWrap.getModel().getSumRefundBill());
|
}
|
if (pageWrap.getModel().getSumSuccessFee() != null) {
|
queryWrapper.lambda().eq(WxBill::getSumSuccessFee, pageWrap.getModel().getSumSuccessFee());
|
}
|
if (pageWrap.getModel().getSumRefundFee() != null) {
|
queryWrapper.lambda().eq(WxBill::getSumRefundFee, pageWrap.getModel().getSumRefundFee());
|
}
|
if (pageWrap.getModel().getSumCouponRefundFee() != null) {
|
queryWrapper.lambda().eq(WxBill::getSumCouponRefundFee, pageWrap.getModel().getSumCouponRefundFee());
|
}
|
if (pageWrap.getModel().getSumCmmsAmt() != null) {
|
queryWrapper.lambda().eq(WxBill::getSumCmmsAmt, pageWrap.getModel().getSumCmmsAmt());
|
}
|
if (pageWrap.getModel().getSumTotalFee() != null) {
|
queryWrapper.lambda().eq(WxBill::getSumTotalFee, pageWrap.getModel().getSumTotalFee());
|
}
|
if (pageWrap.getModel().getSumApplyRefundFee() != null) {
|
queryWrapper.lambda().eq(WxBill::getSumApplyRefundFee, pageWrap.getModel().getSumApplyRefundFee());
|
}
|
if (pageWrap.getModel().getSumRefundCmmsAmt() != null) {
|
queryWrapper.lambda().eq(WxBill::getSumRefundCmmsAmt, pageWrap.getModel().getSumRefundCmmsAmt());
|
}
|
if (pageWrap.getModel().getTotal() != null) {
|
queryWrapper.lambda().eq(WxBill::getTotal, pageWrap.getModel().getTotal());
|
}
|
if (pageWrap.getModel().getBikeFee() != null) {
|
queryWrapper.lambda().eq(WxBill::getBikeFee, pageWrap.getModel().getBikeFee());
|
}
|
queryWrapper.lambda().ge(pageWrap.getModel().getStartDate() !=null,WxBill::getId,DateUtil.getShortDateStr(pageWrap.getModel().getStartDate()));
|
queryWrapper.lambda().le(pageWrap.getModel().getEndDate() !=null,WxBill::getId,DateUtil.getShortDateStr(pageWrap.getModel().getEndDate()));
|
//按照时间升序显示
|
queryWrapper.lambda().orderByAsc(WxBill::getId);
|
/* for(PageWrap.SortData sortData: pageWrap.getSorts()) {
|
if (sortData.getDirection().equalsIgnoreCase(PageWrap.DESC)) {
|
queryWrapper.orderByDesc(sortData.getProperty());
|
} else {
|
queryWrapper.orderByAsc(sortData.getProperty());
|
}
|
}*/
|
return PageData.from(wxBillMapper.selectPage(page, queryWrapper),getTotalDataByDate(pageWrap.getModel()));
|
}
|
|
private WxBill getTotalDataByDate(WxBill model) {
|
QueryWrapper<WxBill> param = new QueryWrapper<>();
|
param.lambda().ge(model.getStartDate() !=null,WxBill::getId,DateUtil.getShortDateStr(model.getStartDate()));
|
param.lambda().le(model.getEndDate() !=null,WxBill::getId,DateUtil.getShortDateStr(model.getEndDate()));
|
param.select("sum(sum_bill) as sum_bill"
|
,"sum(sum_refund_bill) as sum_refund_bill"
|
,"sum(sum_success_fee) as sum_success_fee"
|
,"sum(sum_refund_fee) as sum_refund_fee"
|
,"sum(sum_cmms_amt) as sum_cmms_amt"
|
,"sum(sum_total_fee) as sum_total_fee"
|
,"sum(sum_apply_refund_fee) as sum_apply_refund_fee"
|
,"sum(sum_total_fee) as sum_total_fee"
|
,"sum(total) as total"
|
,"sum(sum_refund_cmms_amt) as sum_refund_cmms_amt"
|
,"sum(bike_fee) as bike_fee"
|
);
|
WxBill bill = wxBillMapper.selectOne(param.last("limit 1"));
|
if(bill == null){
|
bill = initBillData();
|
|
}
|
return bill;
|
}
|
|
public static WxBill initBillData(){
|
WxBill bill = new WxBill();
|
bill.setSumBill(0);
|
bill.setSumTotalFee(new BigDecimal(0.00));
|
bill.setSumSuccessFee(new BigDecimal(0.00));
|
bill.setSumRefundFee(new BigDecimal(0.00));
|
bill.setSumCouponRefundFee(new BigDecimal(0.00));
|
bill.setSumApplyRefundFee(new BigDecimal(0.00));
|
bill.setSumCmmsAmt(new BigDecimal(0.00));
|
bill.setSumRefundBill(0);
|
bill.setSumRefundCmmsAmt(new BigDecimal(0.00));
|
bill.setTotal(new BigDecimal(0.00));
|
bill.setBikeFee(new BigDecimal(0.00));
|
return bill;
|
}
|
@Override
|
public long count(WxBill wxBill) {
|
QueryWrapper<WxBill> wrapper = new QueryWrapper<>(wxBill);
|
return wxBillMapper.selectCount(wrapper);
|
}
|
@Override
|
@Transactional(rollbackFor = {BusinessException.class,Exception.class})
|
@Synchronized//单例执行
|
public void getWxBill(Date ydate ) {
|
isValidDate(ydate);
|
// 获取交易账单数据
|
WxPayDownloadBillRequest request = new WxPayDownloadBillRequest();
|
String billDate = DateUtil.getShortDateStr(ydate);
|
// Date ydate = DateUtil.addDaysToDate(new Date(), -1);
|
request.setBillDate(billDate);
|
request.setBillType("SUCCESS");
|
request.setSubMchId(WxMiniConfig.wxProperties.getSubMchId());
|
|
WxPayBillResult response = null;
|
try {
|
response = WxMiniConfig.wxPayV2Service.downloadBill(request);
|
}catch (WxPayException e){
|
|
}
|
request.setBillType("REFUND");
|
//请求退款单交易记录汇总数据
|
WxPayBillResult responseRefund = null;
|
try {
|
responseRefund = WxMiniConfig.wxPayV2Service.downloadBill(request);
|
}catch (WxPayException e){
|
|
}
|
WxBill bill = initBillData();
|
//日期作为主键
|
bill.setId(billDate);
|
List<WxBillDetail> detailList = new ArrayList<>();
|
if(response !=null){
|
// List<WxPayBillInfo> detailList = response.getBillInfoList();
|
int totalRefund = 0;
|
BigDecimal totalRefundAmt = new BigDecimal(0.00);
|
bill.setSumBill(Integer.parseInt(response.getTotalRecord()));
|
//订单总金额
|
bill.setSumTotalFee(formatStringToDecimal(response.getTotalAmount()));
|
//应结订单总金额
|
bill.setSumSuccessFee(formatStringToDecimal(response.getTotalFee()));
|
//交易总手续费金额
|
bill.setSumCmmsAmt(formatStringToDecimal(response.getTotalPoundageFee()));
|
detailList.addAll(getDetialModelByInfo(bill,response.getBillInfoList()));
|
}
|
if(responseRefund != null){
|
//退款单总数累计进入
|
// bill.setSumBill(bill.getSumBill()+(Integer.parseInt(response.getTotalRecord()));
|
bill.setSumRefundBill(Integer.parseInt(responseRefund.getTotalRecord()));//退款的订单数
|
//退款总金额
|
bill.setSumRefundFee(formatStringToDecimal(responseRefund.getTotalRefundFee()));
|
//退款总金额
|
bill.setSumApplyRefundFee(formatStringToDecimal(responseRefund.getTotalAppliedRefundFee()));
|
bill.setSumRefundCmmsAmt(formatStringToDecimal(responseRefund.getTotalPoundageFee()));//退款总手续费
|
bill.setSumCouponRefundFee(formatStringToDecimal(responseRefund.getTotalCouponFee()));//退款总金额
|
detailList.addAll(getDetialModelByInfo(bill,responseRefund.getBillInfoList()));
|
}
|
wxBillMapper.delete(new UpdateWrapper<WxBill>().lambda().eq( WxBill::getId, bill.getId()));
|
wxBillDetailMapper.delete(new UpdateWrapper<WxBillDetail>().lambda().eq( WxBillDetail::getPid, bill.getId()));
|
|
// getTotalAndIncome(bill,ydate);//统计结算金额和自行车收入
|
//总结算金额(收款金额-收款手续费-退款金额-退款手续费(负数))
|
bill.setTotal(bill.getSumSuccessFee().subtract(bill.getSumCmmsAmt()).subtract(bill.getSumRefundFee()).subtract(bill.getSumRefundCmmsAmt()));
|
// //自行车收入(收款金额-收款手续费-退款金额-退款手续费(负数))
|
// bill.setBikeFee(bill.getSumSuccessFee().subtract(bill.getSumRefundFee()));
|
wxBillMapper.insert(bill);
|
if(detailList.size()>0){
|
int sublistSize = 500;
|
|
int startIndex = 0;
|
int endIndex = sublistSize;
|
|
while (startIndex < detailList.size()) {
|
if (endIndex > detailList.size()) {
|
endIndex = detailList.size();
|
}
|
|
List<WxBillDetail> sublist = detailList.subList(startIndex, endIndex);
|
if(sublist.size()>0){
|
wxBillDetailMapper.insertBatch(sublist);
|
}
|
startIndex = endIndex;
|
endIndex += sublistSize;
|
}
|
}
|
}
|
|
private boolean isValidDate(Date ydate) {
|
if(ydate == null ){
|
//时间不能为空
|
throw new BusinessException(ResponseStatus.BAD_REQUEST);
|
}
|
int days = DateUtil.daysBetweenDates(new Date(),ydate);
|
if(days< 1){
|
//只能同步昨天之前的数据
|
throw new BusinessException(ResponseStatus.BAD_REQUEST);
|
}
|
if( days == 1){
|
//只能同步昨天10之前的数据
|
Calendar caln = Calendar.getInstance();
|
caln.setTime(ydate);
|
if(caln.get(Calendar.HOUR_OF_DAY) > 10){
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"对不起,最近同步时间只能截止到昨天10点前!");
|
}
|
}
|
return true;
|
}
|
|
private void getTotalAndIncome(WxBill bill,Date date) {
|
QueryWrapper<Goodsorder> queryWrapper = new QueryWrapper<>();
|
queryWrapper.apply("to_char(create_date, 'yyyy-MM-dd') = {0}", date);
|
queryWrapper.lambda().eq(Goodsorder::getIsdeleted, Constants.ZERO);
|
queryWrapper.lambda().eq(Goodsorder::getStatus, Constants.goodsorderStatus.over);//已結算
|
queryWrapper.select("sum(money) as totalMoney","sum(close_money) as totalCloseMoney");
|
}
|
|
private List<WxBillDetail> getDetialModelByInfo(WxBill bill, List<WxPayBillInfo> billInfoList) {
|
List<WxBillDetail> detailList = new ArrayList<>();
|
if(billInfoList!=null){
|
for (int i = 0; i <billInfoList.size(); i++) {
|
WxPayBillInfo info =billInfoList.get(i);
|
if((StringUtils.equals(info.getTradeType(),"REFUND" )||StringUtils.equals(info.getTradeType(),"REVOKED" )) && !StringUtils.equals(info.getRefundState(),"SUCCESS" )){
|
//如果是非成功的退款数据,不进行同步
|
continue;
|
}
|
WxBillDetail detail = new WxBillDetail();
|
detail.setId(UUID.randomUUID().toString());
|
detail.setPid(bill.getId());
|
detail.setBillDate(DateUtil.getDateFromString2(info.getTradeTime()));//交易时间
|
detail.setAppid(info.getAppId());//公众账号ID
|
detail.setMchId(info.getMchId());//商户号
|
detail.setSubMchid(info.getSubMchId());//特约商户号
|
detail.setDeviceInfo(info.getDeviceInfo());//设备
|
|
detail.setTransactionId(info.getTransactionId());//微信订单号
|
detail.setOutTradeNo(info.getOutTradeNo());//商户订单号
|
detail.setOpenid(info.getOpenId());//用户标识
|
detail.setBillType(info.getTradeType());//交易类型
|
detail.setBillStatus(info.getTradeState());//交易状态
|
detail.setBankType(info.getBankType());//付款银行
|
detail.setFeeType(info.getFeeType());//货币种类
|
detail.setSettlementTotalFee(formatStringToDecimal(info.getTotalFee()));//应结订单金额
|
detail.setCouponFee(formatStringToDecimal(info.getCouponFee()));//代金券金额
|
detail.setRefundId(info.getRefundId());//微信退款单号
|
detail.setOutRefundNo(info.getOutRefundNo());//商户退款单号
|
detail.setRefundFee(formatStringToDecimal(info.getSettlementRefundFee()));//退款金额
|
detail.setCouponRefundFee(formatStringToDecimal(info.getCouponRefundFee()));//充值券退款金额
|
detail.setRefundType(info.getRefundChannel());//退款类型
|
detail.setRefundSuccessStatus(info.getRefundState());//退款状态
|
detail.setBody(info.getBody());//商品名称
|
detail.setAttach(info.getAttach());//商户数据包
|
detail.setCmmsAmt(formatStringToDecimal(info.getPoundage()));//手续费
|
detail.setRate(formatStringToDecimal(info.getPoundageRate().replace("%", "")));//费率
|
detail.setTotalFee(formatStringToDecimal(info.getTotalAmount()));//订单金额
|
detail.setApplyRefundFee(formatStringToDecimal(info.getAppliedRefundAmount()));//申请退款金额
|
detail.setRateRemark(info.getFeeRemark());//费率备注
|
detail.setRefundSuccessDate(DateUtil.getDateFromString2(info.getRefundSuccessTime()));//成功退款时间
|
detail.setRefundApplyDate(DateUtil.getDateFromString2(info.getRefundTime())); //申请退款时间
|
//计算自行车收入,匹配来自自行车小程序的所有支付成功和退款成功的金额,作为自行车收入(累计收款金额-累计退款成功金额)
|
if(StringUtils.equals(detail.getAppid(), WxMiniConfig.wxPayV2Service.getConfig().getSubAppId())){
|
//自行车收入累计收款金额(支付成功总金额-退款总金额)
|
if(StringUtils.equals(info.getTradeState(),"SUCCESS")){
|
//如果是交易(包含手续费)
|
bill.setBikeFee(bill.getBikeFee().add(detail.getSettlementTotalFee()));
|
// bill.setBikeFee(bill.getBikeFee().subtract(detail.getCmmsAmt()) );
|
}else if(StringUtils.equals(info.getTradeState(),"REFUND" ) || StringUtils.equals(info.getTradeState(),"REVOKED" )){
|
//如果退款成功,扣除退款金额(包含手续费)
|
bill.setBikeFee(bill.getBikeFee().subtract(detail.getRefundFee()) );
|
// bill.setBikeFee(bill.getBikeFee().subtract(detail.getCmmsAmt()) );
|
}
|
}
|
detailList.add(detail);
|
}
|
}
|
return detailList;
|
}
|
|
public static BigDecimal formatStringToDecimal(String str){
|
if(str == null){
|
return new BigDecimal(0.00);
|
}
|
return new BigDecimal(Double.parseDouble(str));
|
}
|
}
|