| | |
| | | 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.app.auth.service.AppAuthSessionService; |
| | | import com.tcm.training.admin.app.course.vo.AppCoursePurchaseOrderDetailVO; |
| | | import com.tcm.training.admin.app.course.vo.AppCoursePurchaseOrderItemVO; |
| | | import com.tcm.training.admin.common.DateTimes; |
| | | import com.tcm.training.admin.common.PageResponse; |
| | | import com.tcm.training.admin.common.PhoneMasker; |
| | |
| | | private static final String PAYMENT_METHOD_ALIPAY = "ALIPAY"; |
| | | |
| | | private final CoursePurchaseOrderMapper coursePurchaseOrderMapper; |
| | | private final AppAuthSessionService appAuthSessionService; |
| | | |
| | | public CoursePurchaseOrderAppService(CoursePurchaseOrderMapper coursePurchaseOrderMapper) { |
| | | /** |
| | | * 注入养生课程购买订单服务依赖。 |
| | | */ |
| | | public CoursePurchaseOrderAppService(CoursePurchaseOrderMapper coursePurchaseOrderMapper, |
| | | AppAuthSessionService appAuthSessionService) { |
| | | this.coursePurchaseOrderMapper = coursePurchaseOrderMapper; |
| | | this.appAuthSessionService = appAuthSessionService; |
| | | } |
| | | |
| | | /** |
| | | * 分页查询后台养生课程购买订单。 |
| | | */ |
| | | public PageResponse<CoursePurchaseOrderListItemVO> page(int page, |
| | | int pageSize, |
| | | String orderNo, |
| | |
| | | return PageResponse.of(toList(result.getRecords()), result.getTotal(), result.getCurrent(), result.getSize()); |
| | | } |
| | | |
| | | /** |
| | | * 分页查询当前登录用户的 APP 购课记录。 |
| | | */ |
| | | public PageResponse<AppCoursePurchaseOrderItemVO> appUserPage(int page, int pageSize, String productName) { |
| | | Long userId = appAuthSessionService.requireLoginUserId(); |
| | | IPage<CoursePurchaseOrderListRow> result = coursePurchaseOrderMapper.selectAppUserOrderPage( |
| | | new Page<CoursePurchaseOrderListRow>(page, pageSize), |
| | | userId, |
| | | trimToNull(productName) |
| | | ); |
| | | return PageResponse.of(toAppList(result.getRecords()), result.getTotal(), result.getCurrent(), result.getSize()); |
| | | } |
| | | |
| | | /** |
| | | * 获取当前登录用户的 APP 购课记录详情。 |
| | | */ |
| | | public AppCoursePurchaseOrderDetailVO appUserDetail(String orderNo) { |
| | | Long userId = appAuthSessionService.requireLoginUserId(); |
| | | CoursePurchaseOrderListRow row = coursePurchaseOrderMapper.selectAppUserOrderDetail(userId, trimToNull(orderNo)); |
| | | if (row == null) { |
| | | throw new IllegalArgumentException("购课记录不存在"); |
| | | } |
| | | return toAppDetail(row); |
| | | } |
| | | |
| | | /** |
| | | * 导出后台养生课程购买订单。 |
| | | */ |
| | | public void export(HttpServletResponse response, |
| | | String orderNo, |
| | | String userPhone, |
| | |
| | | throw new IllegalArgumentException("退款功能待支付方案确认后接入"); |
| | | } |
| | | |
| | | /** |
| | | * 删除后台已退款养生课程购买订单。 |
| | | */ |
| | | @Transactional |
| | | public void delete(Long id) { |
| | | CoursePurchaseOrder order = requireOrder(id); |
| | |
| | | coursePurchaseOrderMapper.deleteById(id); |
| | | } |
| | | |
| | | /** |
| | | * 校验养生课程购买订单存在。 |
| | | */ |
| | | private CoursePurchaseOrder requireOrder(Long id) { |
| | | CoursePurchaseOrder order = coursePurchaseOrderMapper.selectOne(new LambdaQueryWrapper<CoursePurchaseOrder>() |
| | | .eq(CoursePurchaseOrder::getId, id) |
| | |
| | | return order; |
| | | } |
| | | |
| | | /** |
| | | * 将后台订单查询结果转换为后台列表响应。 |
| | | */ |
| | | private List<CoursePurchaseOrderListItemVO> toList(List<CoursePurchaseOrderListRow> rows) { |
| | | List<CoursePurchaseOrderListItemVO> list = new ArrayList<CoursePurchaseOrderListItemVO>(); |
| | | for (CoursePurchaseOrderListRow row : rows) { |
| | |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * 将订单查询结果转换为 APP 购课记录列表响应。 |
| | | */ |
| | | private List<AppCoursePurchaseOrderItemVO> toAppList(List<CoursePurchaseOrderListRow> rows) { |
| | | List<AppCoursePurchaseOrderItemVO> list = new ArrayList<AppCoursePurchaseOrderItemVO>(); |
| | | for (CoursePurchaseOrderListRow row : rows) { |
| | | AppCoursePurchaseOrderItemVO item = new AppCoursePurchaseOrderItemVO(); |
| | | item.setId(row.getId()); |
| | | item.setOrderNo(row.getOrderNo()); |
| | | item.setCourseId(row.getCourseId()); |
| | | item.setCourseVideoId(row.getCourseVideoId()); |
| | | item.setProductName(row.getProductName()); |
| | | item.setCourseTitle(row.getCourseTitle()); |
| | | item.setChapterName(row.getChapterName()); |
| | | item.setCoverImage(row.getCoverImage()); |
| | | item.setOrderAmount(row.getOrderAmount()); |
| | | item.setPaymentMethod(row.getPaymentMethod()); |
| | | item.setPaymentMethodText(paymentMethodText(row.getPaymentMethod())); |
| | | item.setStatus(row.getStatus()); |
| | | // APP 购课记录页只需标记是否退款,避免前端重复判断订单状态。 |
| | | item.setShowRefundTag(Boolean.valueOf(STATUS_REFUNDED.equals(row.getStatus()))); |
| | | item.setPaidAt(row.getPaidAt()); |
| | | list.add(item); |
| | | } |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * 将订单详情查询结果转换为 APP 购课记录详情响应。 |
| | | */ |
| | | private AppCoursePurchaseOrderDetailVO toAppDetail(CoursePurchaseOrderListRow row) { |
| | | AppCoursePurchaseOrderDetailVO detail = new AppCoursePurchaseOrderDetailVO(); |
| | | detail.setId(row.getId()); |
| | | detail.setOrderNo(row.getOrderNo()); |
| | | detail.setCourseId(row.getCourseId()); |
| | | detail.setCourseVideoId(row.getCourseVideoId()); |
| | | detail.setProductName(row.getProductName()); |
| | | detail.setCourseTitle(row.getCourseTitle()); |
| | | detail.setChapterName(row.getChapterName()); |
| | | detail.setCoverImage(row.getCoverImage()); |
| | | detail.setOrderAmount(row.getOrderAmount()); |
| | | detail.setPaymentMethod(row.getPaymentMethod()); |
| | | detail.setPaymentMethodText(paymentMethodText(row.getPaymentMethod())); |
| | | detail.setStatus(row.getStatus()); |
| | | // 详情页退款信息直接由后端归一化,避免前端重复拼装退款状态。 |
| | | detail.setRefundAmount(resolveRefundAmount(row.getStatus(), row.getOrderAmount(), row.getRefundAmount())); |
| | | detail.setShowRefundTag(Boolean.valueOf(STATUS_REFUNDED.equals(row.getStatus()))); |
| | | detail.setCreatedAt(row.getCreatedAt()); |
| | | detail.setPaidAt(row.getPaidAt()); |
| | | detail.setRefundedAt(row.getRefundedAt()); |
| | | return detail; |
| | | } |
| | | |
| | | /** |
| | | * 解析订单应展示的退款金额。 |
| | | */ |
| | | 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; |
| | | } |
| | | |
| | | /** |
| | | * 将空白字符串归一化为 null。 |
| | | */ |
| | | private String trimToNull(String value) { |
| | | if (value == null) { |
| | | return null; |
| | |
| | | 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 "微信支付"; |
| | |
| | | return "-"; |
| | | } |
| | | |
| | | /** |
| | | * 解析订单状态展示文案。 |
| | | */ |
| | | private String statusText(String status) { |
| | | if (STATUS_WAITING_PAYMENT.equals(status)) { |
| | | return "待支付"; |