package com.tcm.training.admin.live.service;
|
|
import cn.idev.excel.FastExcel;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
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.live.dto.CoursePurchaseOrderRefundRequest;
|
import com.tcm.training.admin.live.entity.CoursePurchaseOrder;
|
import com.tcm.training.admin.live.excel.CoursePurchaseOrderExcelRow;
|
import com.tcm.training.admin.live.mapper.CoursePurchaseOrderMapper;
|
import com.tcm.training.admin.live.vo.CoursePurchaseOrderListItemVO;
|
import com.tcm.training.admin.live.vo.CoursePurchaseOrderListRow;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
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 CoursePurchaseOrderAppService {
|
|
private static final String COURSE_TYPE_HEALTH = "HEALTH_COURSE";
|
private static final String STATUS_PAID = "PAID";
|
private static final String STATUS_REFUNDED = "REFUNDED";
|
private static final String STATUS_WAITING_PAYMENT = "WAITING_PAYMENT";
|
private static final String STATUS_CANCELLED = "CANCELLED";
|
private static final String PAYMENT_METHOD_WECHAT = "WECHAT";
|
private static final String PAYMENT_METHOD_ALIPAY = "ALIPAY";
|
|
private final CoursePurchaseOrderMapper coursePurchaseOrderMapper;
|
|
public CoursePurchaseOrderAppService(CoursePurchaseOrderMapper coursePurchaseOrderMapper) {
|
this.coursePurchaseOrderMapper = coursePurchaseOrderMapper;
|
}
|
|
public PageResponse<CoursePurchaseOrderListItemVO> page(int page,
|
int pageSize,
|
String orderNo,
|
String userPhone,
|
String productName,
|
String paymentMethod,
|
String status,
|
LocalDateTime createdFrom,
|
LocalDateTime createdTo) {
|
IPage<CoursePurchaseOrderListRow> result = coursePurchaseOrderMapper.selectOrderPage(
|
new Page<CoursePurchaseOrderListRow>(page, pageSize),
|
trimToNull(orderNo),
|
trimToNull(userPhone),
|
trimToNull(productName),
|
trimToNull(paymentMethod),
|
normalizeStatus(status),
|
createdFrom,
|
createdTo
|
);
|
return PageResponse.of(toList(result.getRecords()), result.getTotal(), result.getCurrent(), result.getSize());
|
}
|
|
public void export(HttpServletResponse response,
|
String orderNo,
|
String userPhone,
|
String productName,
|
String paymentMethod,
|
String status,
|
LocalDateTime createdFrom,
|
LocalDateTime createdTo) throws IOException {
|
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<CoursePurchaseOrderListRow> rows = coursePurchaseOrderMapper.selectOrderList(
|
trimToNull(orderNo),
|
trimToNull(userPhone),
|
trimToNull(productName),
|
trimToNull(paymentMethod),
|
normalizeStatus(status),
|
createdFrom,
|
createdTo
|
);
|
List<CoursePurchaseOrderExcelRow> exports = new ArrayList<CoursePurchaseOrderExcelRow>();
|
for (CoursePurchaseOrderListRow row : rows) {
|
CoursePurchaseOrderExcelRow export = new CoursePurchaseOrderExcelRow();
|
export.setOrderNo(row.getOrderNo());
|
export.setUserNickname(defaultText(row.getUserNickname()));
|
export.setUserPhone(PhoneMasker.mask(row.getUserPhone()));
|
export.setProductName(defaultText(row.getProductName()));
|
export.setOrderAmount(row.getOrderAmount());
|
export.setPaymentMethod(paymentMethodText(row.getPaymentMethod()));
|
export.setStatus(statusText(row.getStatus()));
|
export.setRefundAmount(resolveRefundAmount(row.getStatus(), row.getOrderAmount(), row.getRefundAmount()));
|
export.setRefundRemark(defaultText(row.getRefundRemark()));
|
export.setCreatedAt(DateTimes.format(row.getCreatedAt()));
|
exports.add(export);
|
}
|
FastExcel.write(response.getOutputStream(), CoursePurchaseOrderExcelRow.class)
|
.sheet("养生课程购买订单")
|
.doWrite(exports);
|
}
|
|
public void refund(Long id, CoursePurchaseOrderRefundRequest request) {
|
CoursePurchaseOrder order = requireOrder(id);
|
if (!STATUS_PAID.equals(order.getStatus())) {
|
throw new IllegalArgumentException("仅已支付订单允许退款");
|
}
|
if (request.getRefundAmount().compareTo(order.getOrderAmount()) > 0) {
|
throw new IllegalArgumentException("退款金额不能超过用户实付金额");
|
}
|
// TODO: 支付方案确认后,在这里接入真实退款流程并在退款成功后更新订单状态与退款时间。
|
throw new IllegalArgumentException("退款功能待支付方案确认后接入");
|
}
|
|
@Transactional
|
public void delete(Long id) {
|
CoursePurchaseOrder order = requireOrder(id);
|
if (!STATUS_REFUNDED.equals(order.getStatus())) {
|
throw new IllegalArgumentException("仅已退款订单允许删除");
|
}
|
coursePurchaseOrderMapper.deleteById(id);
|
}
|
|
private CoursePurchaseOrder requireOrder(Long id) {
|
CoursePurchaseOrder order = coursePurchaseOrderMapper.selectOne(new LambdaQueryWrapper<CoursePurchaseOrder>()
|
.eq(CoursePurchaseOrder::getId, id)
|
.eq(CoursePurchaseOrder::getCourseType, COURSE_TYPE_HEALTH)
|
.eq(CoursePurchaseOrder::getDeleted, 0)
|
.last("limit 1"));
|
if (order == null) {
|
throw new IllegalArgumentException("养生课程购买订单不存在");
|
}
|
return order;
|
}
|
|
private List<CoursePurchaseOrderListItemVO> toList(List<CoursePurchaseOrderListRow> rows) {
|
List<CoursePurchaseOrderListItemVO> list = new ArrayList<CoursePurchaseOrderListItemVO>();
|
for (CoursePurchaseOrderListRow row : rows) {
|
CoursePurchaseOrderListItemVO item = new CoursePurchaseOrderListItemVO();
|
item.setId(row.getId());
|
item.setOrderNo(row.getOrderNo());
|
item.setUserNickname(row.getUserNickname());
|
item.setUserPhone(PhoneMasker.mask(row.getUserPhone()));
|
item.setProductName(row.getProductName());
|
item.setOrderAmount(row.getOrderAmount());
|
item.setPaymentMethod(row.getPaymentMethod());
|
item.setRefundAmount(resolveRefundAmount(row.getStatus(), row.getOrderAmount(), row.getRefundAmount()));
|
item.setRefundRemark(row.getRefundRemark());
|
item.setStatus(row.getStatus());
|
item.setCreatedAt(row.getCreatedAt());
|
list.add(item);
|
}
|
return list;
|
}
|
|
private BigDecimal resolveRefundAmount(String status, BigDecimal orderAmount, BigDecimal refundAmount) {
|
if (!STATUS_REFUNDED.equals(status)) {
|
return null;
|
}
|
return refundAmount == null ? orderAmount : refundAmount;
|
}
|
|
private String normalizeStatus(String status) {
|
String normalized = trimToNull(status);
|
if (normalized == null) {
|
return null;
|
}
|
if (STATUS_PAID.equals(normalized) || STATUS_REFUNDED.equals(normalized)) {
|
return normalized;
|
}
|
return null;
|
}
|
|
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 paymentMethodText(String paymentMethod) {
|
if (PAYMENT_METHOD_WECHAT.equals(paymentMethod)) {
|
return "微信支付";
|
}
|
if (PAYMENT_METHOD_ALIPAY.equals(paymentMethod)) {
|
return "支付宝支付";
|
}
|
return "-";
|
}
|
|
private String statusText(String status) {
|
if (STATUS_WAITING_PAYMENT.equals(status)) {
|
return "待支付";
|
}
|
if (STATUS_PAID.equals(status)) {
|
return "已支付";
|
}
|
if (STATUS_REFUNDED.equals(status)) {
|
return "已退款";
|
}
|
if (STATUS_CANCELLED.equals(status)) {
|
return "已取消";
|
}
|
return "-";
|
}
|
}
|