package com.tcm.training.admin.trade.service;
|
|
import cn.idev.excel.FastExcel;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.tcm.training.admin.common.DateTimes;
|
import com.tcm.training.admin.common.PageResponse;
|
import com.tcm.training.admin.common.PhoneMasker;
|
import com.tcm.training.admin.trade.entity.PaymentFlow;
|
import com.tcm.training.admin.trade.excel.PaymentFlowExcelRow;
|
import com.tcm.training.admin.trade.excel.RefundFlowExcelRow;
|
import com.tcm.training.admin.trade.mapper.PaymentFlowMapper;
|
import com.tcm.training.admin.trade.row.PaymentFlowRow;
|
import com.tcm.training.admin.trade.row.PaymentFlowSyncRow;
|
import com.tcm.training.admin.trade.vo.PaymentFlowListItemVO;
|
import org.springframework.dao.DuplicateKeyException;
|
import org.springframework.stereotype.Service;
|
|
import javax.servlet.http.HttpServletResponse;
|
import java.io.IOException;
|
import java.math.BigDecimal;
|
import java.net.URLEncoder;
|
import java.time.LocalDateTime;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
@Service
|
public class PaymentFlowAppService {
|
|
private static final String BUSINESS_TYPE_COURSE_PURCHASE = "COURSE_PURCHASE";
|
private static final String BUSINESS_TYPE_MEMBER_PURCHASE = "MEMBER_PURCHASE";
|
private static final String FLOW_TYPE_PAYMENT = "PAYMENT";
|
private static final String FLOW_TYPE_REFUND = "REFUND";
|
private static final String TRADE_STATUS_SUCCESS = "SUCCESS";
|
private static final String TRADE_STATUS_REFUNDED = "REFUNDED";
|
private static final String SOURCE_TYPE_COURSE_PAYMENT = "COURSE_PAYMENT";
|
private static final String SOURCE_TYPE_COURSE_REFUND = "COURSE_REFUND";
|
private static final String SOURCE_TYPE_MEMBER_PAYMENT = "MEMBER_PAYMENT";
|
private static final String SOURCE_TYPE_MEMBER_REFUND = "MEMBER_REFUND";
|
private static final String PAYMENT_METHOD_WECHAT = "WECHAT";
|
private static final String PAYMENT_METHOD_ALIPAY = "ALIPAY";
|
|
private final PaymentFlowMapper paymentFlowMapper;
|
|
public PaymentFlowAppService(PaymentFlowMapper paymentFlowMapper) {
|
this.paymentFlowMapper = paymentFlowMapper;
|
}
|
|
public PageResponse<PaymentFlowListItemVO> pagePaymentFlows(int page,
|
int pageSize,
|
String flowNo,
|
String businessOrderNo,
|
String userPhone,
|
String productKeyword,
|
String businessType,
|
String paymentMethod,
|
LocalDateTime tradeFrom,
|
LocalDateTime tradeTo) {
|
syncFlows();
|
IPage<PaymentFlowRow> result = queryFlowPage(page, pageSize, flowNo, businessOrderNo, userPhone, productKeyword,
|
businessType, FLOW_TYPE_PAYMENT, paymentMethod, TRADE_STATUS_SUCCESS, tradeFrom, tradeTo);
|
return PageResponse.of(toList(result.getRecords()), result.getTotal(), result.getCurrent(), result.getSize());
|
}
|
|
public PageResponse<PaymentFlowListItemVO> pageRefundFlows(int page,
|
int pageSize,
|
String flowNo,
|
String businessOrderNo,
|
String userPhone,
|
String productKeyword,
|
String businessType,
|
String paymentMethod,
|
LocalDateTime tradeFrom,
|
LocalDateTime tradeTo) {
|
syncFlows();
|
IPage<PaymentFlowRow> result = queryFlowPage(page, pageSize, flowNo, businessOrderNo, userPhone, productKeyword,
|
businessType, FLOW_TYPE_REFUND, paymentMethod, TRADE_STATUS_REFUNDED, tradeFrom, tradeTo);
|
return PageResponse.of(toList(result.getRecords()), result.getTotal(), result.getCurrent(), result.getSize());
|
}
|
|
public void exportPaymentFlows(HttpServletResponse response,
|
String flowNo,
|
String businessOrderNo,
|
String userPhone,
|
String productKeyword,
|
String businessType,
|
String paymentMethod,
|
LocalDateTime tradeFrom,
|
LocalDateTime tradeTo) throws IOException {
|
syncFlows();
|
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
response.setCharacterEncoding("utf-8");
|
String filename = URLEncoder.encode("支付流水", "UTF-8").replace("+", "%20");
|
response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + filename + ".xlsx");
|
|
List<PaymentFlowRow> rows = queryFlowList(flowNo, businessOrderNo, userPhone, productKeyword, businessType,
|
FLOW_TYPE_PAYMENT, paymentMethod, TRADE_STATUS_SUCCESS, tradeFrom, tradeTo);
|
List<PaymentFlowExcelRow> exports = new ArrayList<PaymentFlowExcelRow>();
|
for (int i = 0; i < rows.size(); i++) {
|
PaymentFlowRow row = rows.get(i);
|
PaymentFlowExcelRow export = new PaymentFlowExcelRow();
|
export.setSerialNo(i + 1);
|
export.setBusinessOrderNo(defaultText(row.getBusinessOrderNo()));
|
export.setFlowNo(defaultText(row.getFlowNo()));
|
export.setUserNickname(defaultText(row.getUserNickname()));
|
export.setUserPhone(PhoneMasker.mask(row.getUserPhone()));
|
export.setBusinessType(orderSourceText(row.getBusinessType()));
|
export.setProductNameSnapshot(defaultText(row.getProductNameSnapshot()));
|
export.setPaymentMethod(paymentMethodText(row.getPaymentMethod()));
|
export.setTransactionAmount(formatAmount(row.getTransactionAmount()));
|
export.setTradeTime(DateTimes.format(row.getTradeTime()));
|
exports.add(export);
|
}
|
FastExcel.write(response.getOutputStream(), PaymentFlowExcelRow.class)
|
.sheet("支付流水")
|
.doWrite(exports);
|
}
|
|
public void exportRefundFlows(HttpServletResponse response,
|
String flowNo,
|
String businessOrderNo,
|
String userPhone,
|
String productKeyword,
|
String businessType,
|
String paymentMethod,
|
LocalDateTime tradeFrom,
|
LocalDateTime tradeTo) throws IOException {
|
syncFlows();
|
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
response.setCharacterEncoding("utf-8");
|
String filename = URLEncoder.encode("退费流水", "UTF-8").replace("+", "%20");
|
response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + filename + ".xlsx");
|
|
List<PaymentFlowRow> rows = queryFlowList(flowNo, businessOrderNo, userPhone, productKeyword, businessType,
|
FLOW_TYPE_REFUND, paymentMethod, TRADE_STATUS_REFUNDED, tradeFrom, tradeTo);
|
List<RefundFlowExcelRow> exports = new ArrayList<RefundFlowExcelRow>();
|
for (int i = 0; i < rows.size(); i++) {
|
PaymentFlowRow row = rows.get(i);
|
RefundFlowExcelRow export = new RefundFlowExcelRow();
|
export.setSerialNo(i + 1);
|
export.setBusinessOrderNo(defaultText(row.getBusinessOrderNo()));
|
export.setFlowNo(defaultText(row.getFlowNo()));
|
export.setUserNickname(defaultText(row.getUserNickname()));
|
export.setUserPhone(PhoneMasker.mask(row.getUserPhone()));
|
export.setBusinessType(orderSourceText(row.getBusinessType()));
|
export.setProductNameSnapshot(defaultText(row.getProductNameSnapshot()));
|
export.setPaymentMethod(paymentMethodText(row.getPaymentMethod()));
|
export.setTransactionAmount(formatAmount(row.getTransactionAmount()));
|
export.setTradeTime(DateTimes.format(row.getTradeTime()));
|
exports.add(export);
|
}
|
FastExcel.write(response.getOutputStream(), RefundFlowExcelRow.class)
|
.sheet("退费流水")
|
.doWrite(exports);
|
}
|
|
public void syncFlows() {
|
syncMissingFlows(paymentFlowMapper.selectMissingCoursePaymentRows(), BUSINESS_TYPE_COURSE_PURCHASE, FLOW_TYPE_PAYMENT,
|
TRADE_STATUS_SUCCESS, SOURCE_TYPE_COURSE_PAYMENT);
|
syncMissingFlows(paymentFlowMapper.selectMissingCourseRefundRows(), BUSINESS_TYPE_COURSE_PURCHASE, FLOW_TYPE_REFUND,
|
TRADE_STATUS_REFUNDED, SOURCE_TYPE_COURSE_REFUND);
|
syncMissingFlows(paymentFlowMapper.selectMissingMemberPaymentRows(), BUSINESS_TYPE_MEMBER_PURCHASE, FLOW_TYPE_PAYMENT,
|
TRADE_STATUS_SUCCESS, SOURCE_TYPE_MEMBER_PAYMENT);
|
syncMissingFlows(paymentFlowMapper.selectMissingMemberRefundRows(), BUSINESS_TYPE_MEMBER_PURCHASE, FLOW_TYPE_REFUND,
|
TRADE_STATUS_REFUNDED, SOURCE_TYPE_MEMBER_REFUND);
|
}
|
|
private void syncMissingFlows(List<PaymentFlowSyncRow> rows,
|
String businessType,
|
String flowType,
|
String tradeStatus,
|
String sourceType) {
|
for (PaymentFlowSyncRow row : rows) {
|
PaymentFlow flow = new PaymentFlow();
|
flow.setFlowNo(buildFlowNo(businessType, flowType, row.getBusinessOrderNo()));
|
flow.setBusinessType(businessType);
|
flow.setBusinessOrderId(row.getBusinessOrderId());
|
flow.setBusinessOrderNo(row.getBusinessOrderNo());
|
flow.setFlowType(flowType);
|
flow.setTradeStatus(tradeStatus);
|
flow.setAppUserId(row.getAppUserId());
|
flow.setUserNickname(row.getUserNickname());
|
flow.setUserPhone(row.getUserPhone());
|
flow.setProductNameSnapshot(row.getProductNameSnapshot());
|
flow.setPaymentMethod(row.getPaymentMethod());
|
flow.setTransactionAmount(defaultAmount(row.getTransactionAmount()));
|
flow.setRemark(trimToNull(row.getRemark()));
|
flow.setTradeTime(row.getTradeTime());
|
flow.setSourceType(sourceType);
|
flow.setSourceId(row.getSourceId());
|
try {
|
paymentFlowMapper.insert(flow);
|
} catch (DuplicateKeyException ignored) {
|
}
|
}
|
}
|
|
private IPage<PaymentFlowRow> queryFlowPage(int page,
|
int pageSize,
|
String flowNo,
|
String businessOrderNo,
|
String userPhone,
|
String productKeyword,
|
String businessType,
|
String flowType,
|
String paymentMethod,
|
String tradeStatus,
|
LocalDateTime tradeFrom,
|
LocalDateTime tradeTo) {
|
return paymentFlowMapper.selectPaymentFlowPage(
|
new Page<PaymentFlowRow>(page, pageSize),
|
trimToNull(flowNo),
|
trimToNull(businessOrderNo),
|
trimToNull(userPhone),
|
trimToNull(productKeyword),
|
trimToNull(businessType),
|
flowType,
|
trimToNull(paymentMethod),
|
tradeStatus,
|
tradeFrom,
|
tradeTo
|
);
|
}
|
|
private List<PaymentFlowRow> queryFlowList(String flowNo,
|
String businessOrderNo,
|
String userPhone,
|
String productKeyword,
|
String businessType,
|
String flowType,
|
String paymentMethod,
|
String tradeStatus,
|
LocalDateTime tradeFrom,
|
LocalDateTime tradeTo) {
|
return paymentFlowMapper.selectPaymentFlowList(
|
trimToNull(flowNo),
|
trimToNull(businessOrderNo),
|
trimToNull(userPhone),
|
trimToNull(productKeyword),
|
trimToNull(businessType),
|
flowType,
|
trimToNull(paymentMethod),
|
tradeStatus,
|
tradeFrom,
|
tradeTo
|
);
|
}
|
|
private List<PaymentFlowListItemVO> toList(List<PaymentFlowRow> rows) {
|
List<PaymentFlowListItemVO> list = new ArrayList<PaymentFlowListItemVO>();
|
for (PaymentFlowRow row : rows) {
|
PaymentFlowListItemVO item = new PaymentFlowListItemVO();
|
item.setId(row.getId());
|
item.setFlowNo(row.getFlowNo());
|
item.setBusinessType(row.getBusinessType());
|
item.setBusinessOrderId(row.getBusinessOrderId());
|
item.setBusinessOrderNo(row.getBusinessOrderNo());
|
item.setFlowType(row.getFlowType());
|
item.setTradeStatus(row.getTradeStatus());
|
item.setUserNickname(row.getUserNickname());
|
item.setUserPhone(PhoneMasker.mask(row.getUserPhone()));
|
item.setProductNameSnapshot(row.getProductNameSnapshot());
|
item.setPaymentMethod(row.getPaymentMethod());
|
item.setTransactionAmount(row.getTransactionAmount());
|
item.setThirdPartyNo(row.getThirdPartyNo());
|
item.setRemark(row.getRemark());
|
item.setTradeTime(row.getTradeTime());
|
list.add(item);
|
}
|
return list;
|
}
|
|
private String buildFlowNo(String businessType, String flowType, String businessOrderNo) {
|
String businessPrefix = BUSINESS_TYPE_COURSE_PURCHASE.equals(businessType) ? "COURSE" : "MEMBER";
|
String flowPrefix = FLOW_TYPE_PAYMENT.equals(flowType) ? "PAY" : "REFUND";
|
return flowPrefix + "-" + businessPrefix + "-" + businessOrderNo;
|
}
|
|
private BigDecimal defaultAmount(BigDecimal amount) {
|
return amount == null ? BigDecimal.ZERO : amount;
|
}
|
|
private String trimToNull(String value) {
|
if (value == null) {
|
return null;
|
}
|
String trimmed = value.trim();
|
return trimmed.isEmpty() ? null : trimmed;
|
}
|
|
private String defaultText(String value) {
|
return value == null || value.trim().isEmpty() ? "-" : value.trim();
|
}
|
|
private String formatAmount(BigDecimal value) {
|
BigDecimal amount = value == null ? BigDecimal.ZERO : value;
|
return amount.stripTrailingZeros().toPlainString();
|
}
|
|
private String orderSourceText(String value) {
|
if (BUSINESS_TYPE_COURSE_PURCHASE.equals(value)) {
|
return "养生课程";
|
}
|
if (BUSINESS_TYPE_MEMBER_PURCHASE.equals(value)) {
|
return "会员";
|
}
|
return "-";
|
}
|
|
public String paymentMethodText(String value) {
|
if (PAYMENT_METHOD_WECHAT.equals(value)) {
|
return "微信支付";
|
}
|
if (PAYMENT_METHOD_ALIPAY.equals(value)) {
|
return "支付宝支付";
|
}
|
return "-";
|
}
|
|
}
|