package com.tcm.training.admin.points.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.app.notice.service.AppSystemNoticeDispatchCommand;
|
import com.tcm.training.admin.app.notice.service.AppSystemNoticeDispatchService;
|
import com.tcm.training.admin.app.notice.service.AppSystemNoticeType;
|
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.points.dto.ExchangeShipRequest;
|
import com.tcm.training.admin.points.entity.PointsExchangeOrder;
|
import com.tcm.training.admin.points.entity.PointsExchangeOrderItem;
|
import com.tcm.training.admin.points.excel.PointsExchangeItemExcelRow;
|
import com.tcm.training.admin.points.excel.PointsExchangeOrderExcelRow;
|
import com.tcm.training.admin.points.mapper.PointsExchangeOrderItemMapper;
|
import com.tcm.training.admin.points.mapper.PointsExchangeOrderMapper;
|
import com.tcm.training.admin.points.row.PointsExchangeItemRow;
|
import com.tcm.training.admin.points.row.PointsExchangeOrderRow;
|
import com.tcm.training.admin.points.vo.PointsExchangeItemDetailVO;
|
import com.tcm.training.admin.points.vo.PointsExchangeItemListItemVO;
|
import com.tcm.training.admin.points.vo.PointsExchangeOrderListItemVO;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import javax.servlet.http.HttpServletResponse;
|
import java.io.IOException;
|
import java.net.URLEncoder;
|
import java.time.LocalDateTime;
|
import java.util.ArrayList;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
@Service
|
public class PointsExchangeAppService {
|
|
private final PointsExchangeOrderMapper pointsExchangeOrderMapper;
|
private final PointsExchangeOrderItemMapper pointsExchangeOrderItemMapper;
|
private final AppSystemNoticeDispatchService appSystemNoticeDispatchService;
|
|
public PointsExchangeAppService(PointsExchangeOrderMapper pointsExchangeOrderMapper,
|
PointsExchangeOrderItemMapper pointsExchangeOrderItemMapper,
|
AppSystemNoticeDispatchService appSystemNoticeDispatchService) {
|
this.pointsExchangeOrderMapper = pointsExchangeOrderMapper;
|
this.pointsExchangeOrderItemMapper = pointsExchangeOrderItemMapper;
|
this.appSystemNoticeDispatchService = appSystemNoticeDispatchService;
|
}
|
|
public PageResponse<PointsExchangeOrderListItemVO> pageOrders(int page,
|
int pageSize,
|
String giftName,
|
String receiverPhone,
|
Integer status,
|
LocalDateTime createdFrom,
|
LocalDateTime createdTo) {
|
IPage<PointsExchangeOrderRow> result = pointsExchangeOrderMapper.selectOrderPage(
|
new Page<PointsExchangeOrderRow>(page, pageSize),
|
trimToNull(giftName),
|
trimToNull(receiverPhone),
|
status,
|
createdFrom,
|
createdTo
|
);
|
return PageResponse.of(toOrderList(result.getRecords()), result.getTotal(), result.getCurrent(), result.getSize());
|
}
|
|
public PageResponse<PointsExchangeItemListItemVO> pageItems(int page,
|
int pageSize,
|
Long orderId,
|
String orderNo,
|
String buyerPhone,
|
String giftName,
|
String receiverPhone,
|
Integer status,
|
LocalDateTime createdFrom,
|
LocalDateTime createdTo) {
|
IPage<PointsExchangeItemRow> result = pointsExchangeOrderItemMapper.selectItemPage(
|
new Page<PointsExchangeItemRow>(page, pageSize),
|
orderId,
|
trimToNull(orderNo),
|
trimToNull(buyerPhone),
|
trimToNull(giftName),
|
trimToNull(receiverPhone),
|
status,
|
createdFrom,
|
createdTo
|
);
|
return PageResponse.of(toItemList(result.getRecords()), result.getTotal(), result.getCurrent(), result.getSize());
|
}
|
|
public PointsExchangeItemDetailVO itemDetail(Long id) {
|
PointsExchangeItemRow row = pointsExchangeOrderItemMapper.selectItemDetail(id);
|
if (row == null) {
|
throw new IllegalArgumentException("兑换明细不存在");
|
}
|
PointsExchangeItemDetailVO vo = new PointsExchangeItemDetailVO();
|
vo.setId(row.getId());
|
vo.setOrderId(row.getOrderId());
|
vo.setOrderNo(row.getOrderNo());
|
vo.setStatus(row.getStatus());
|
vo.setTrackingNo(row.getTrackingNo());
|
vo.setShippedAt(row.getShippedAt());
|
vo.setCompletedAt(row.getCompletedAt());
|
vo.setCancelledAt(row.getCancelledAt());
|
vo.setCreatedAt(row.getCreatedAt());
|
|
PointsExchangeItemDetailVO.BuyerVO buyer = new PointsExchangeItemDetailVO.BuyerVO();
|
buyer.setUserId(row.getAppUserId());
|
buyer.setNickname(row.getBuyerNickname());
|
buyer.setPhone(row.getBuyerPhone());
|
buyer.setClinicName(row.getClinicName());
|
buyer.setSettledPoints(row.getSettledPoints());
|
buyer.setCreatedAt(row.getBuyerCreatedAt());
|
vo.setBuyer(buyer);
|
|
PointsExchangeItemDetailVO.ReceiverVO receiver = new PointsExchangeItemDetailVO.ReceiverVO();
|
receiver.setName(row.getReceiverName());
|
receiver.setPhone(row.getReceiverPhone());
|
receiver.setAddress(row.getReceiverAddress());
|
vo.setReceiver(receiver);
|
|
PointsExchangeItemDetailVO.GiftVO gift = new PointsExchangeItemDetailVO.GiftVO();
|
gift.setCover(row.getGiftCover());
|
gift.setName(row.getGiftName());
|
gift.setRequiredPoints(row.getRequiredPoints());
|
gift.setActivityStartAt(row.getActivityStartAt());
|
gift.setActivityEndAt(row.getActivityEndAt());
|
vo.setGift(gift);
|
return vo;
|
}
|
|
@Transactional
|
public void shipOrder(Long id, ExchangeShipRequest request) {
|
PointsExchangeOrder order = requireOrder(id);
|
validatePendingStatus(order.getStatus());
|
LocalDateTime now = LocalDateTime.now();
|
List<PointsExchangeOrderItem> items = pointsExchangeOrderItemMapper.selectList(new LambdaQueryWrapper<PointsExchangeOrderItem>()
|
.eq(PointsExchangeOrderItem::getDeleted, 0)
|
.eq(PointsExchangeOrderItem::getOrderId, id));
|
for (PointsExchangeOrderItem item : items) {
|
if (item.getStatus() != null && item.getStatus() == 0) {
|
item.setStatus(1);
|
item.setTrackingNo(request.getTrackingNo().trim());
|
item.setShippedAt(now);
|
pointsExchangeOrderItemMapper.updateById(item);
|
}
|
}
|
order.setStatus(1);
|
order.setTrackingNo(request.getTrackingNo().trim());
|
order.setShippedAt(now);
|
pointsExchangeOrderMapper.updateById(order);
|
dispatchOrderShippedNotice(order);
|
}
|
|
@Transactional
|
public void shipItem(Long id, ExchangeShipRequest request) {
|
PointsExchangeOrderItem item = requireItem(id);
|
validatePendingStatus(item.getStatus());
|
LocalDateTime now = LocalDateTime.now();
|
item.setStatus(1);
|
item.setTrackingNo(request.getTrackingNo().trim());
|
item.setShippedAt(now);
|
pointsExchangeOrderItemMapper.updateById(item);
|
refreshOrderStatus(item.getOrderId(), request.getTrackingNo().trim(), now);
|
dispatchOrderShippedNotice(requireOrder(item.getOrderId()));
|
}
|
|
/**
|
* 在订单发货后为诊所用户发送订单状态更新通知。
|
*/
|
private void dispatchOrderShippedNotice(PointsExchangeOrder order) {
|
if (order == null || order.getId() == null || order.getClinicAppUserId() == null) {
|
return;
|
}
|
AppSystemNoticeDispatchCommand command = new AppSystemNoticeDispatchCommand();
|
command.setAppUserId(order.getClinicAppUserId());
|
command.setNoticeTypeCode(AppSystemNoticeType.ORDER_STATUS_UPDATE);
|
command.setTitle("订单状态更新");
|
command.setContent("您的礼品兑换订单已发货");
|
command.setReferenceType("POINTS_EXCHANGE_ORDER_SHIPPED");
|
command.setReferenceId(order.getId());
|
command.setRequireUserSetting(Boolean.TRUE);
|
Map<String, String> payload = new LinkedHashMap<String, String>();
|
payload.put("orderId", String.valueOf(order.getId()));
|
payload.put("orderNo", defaultText(order.getOrderNo()));
|
payload.put("trackingNo", defaultText(order.getTrackingNo()));
|
command.setPayload(payload);
|
appSystemNoticeDispatchService.createAndPush(command);
|
}
|
|
@Transactional
|
public void deleteOrder(Long id) {
|
PointsExchangeOrder order = requireOrder(id);
|
if (order.getCancelledAt() == null) {
|
throw new IllegalArgumentException("当前状态不允许删除");
|
}
|
List<PointsExchangeOrderItem> items = pointsExchangeOrderItemMapper.selectList(new LambdaQueryWrapper<PointsExchangeOrderItem>()
|
.eq(PointsExchangeOrderItem::getDeleted, 0)
|
.eq(PointsExchangeOrderItem::getOrderId, id));
|
for (PointsExchangeOrderItem item : items) {
|
pointsExchangeOrderItemMapper.deleteById(item.getId());
|
}
|
pointsExchangeOrderMapper.deleteById(id);
|
}
|
|
@Transactional
|
public void deleteItem(Long id) {
|
PointsExchangeOrderItem item = requireItem(id);
|
if (item.getCancelledAt() == null) {
|
throw new IllegalArgumentException("当前状态不允许删除");
|
}
|
Long orderId = item.getOrderId();
|
pointsExchangeOrderItemMapper.deleteById(id);
|
if (orderId != null) {
|
refreshOrderStatus(orderId, null, null);
|
}
|
}
|
|
public void exportOrders(HttpServletResponse response,
|
String giftName,
|
String receiverPhone,
|
Integer 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<PointsExchangeOrderRow> rows = pointsExchangeOrderMapper.selectOrderList(
|
trimToNull(giftName),
|
trimToNull(receiverPhone),
|
status,
|
createdFrom,
|
createdTo
|
);
|
List<PointsExchangeOrderExcelRow> exports = new ArrayList<PointsExchangeOrderExcelRow>();
|
for (int i = 0; i < rows.size(); i++) {
|
PointsExchangeOrderRow row = rows.get(i);
|
PointsExchangeOrderExcelRow export = new PointsExchangeOrderExcelRow();
|
export.setSerialNo(i + 1);
|
export.setOrderNo(row.getOrderNo());
|
export.setGiftName(defaultText(row.getGiftName()));
|
export.setRequiredPoints(row.getRequiredPoints());
|
export.setActivityRange(formatRange(row.getActivityStartAt(), row.getActivityEndAt()));
|
export.setClinicName(defaultText(row.getClinicName()));
|
export.setReceiverClinicName(defaultText(row.getReceiverClinicName()));
|
export.setReceiverPhone(PhoneMasker.mask(row.getReceiverPhone()));
|
export.setReceiverAddress(defaultText(row.getReceiverAddress()));
|
export.setItemCount(row.getItemCount());
|
export.setTotalPoints(row.getTotalPoints());
|
export.setStatus(orderStatusText(row.getStatus()));
|
export.setTrackingNo(defaultText(row.getTrackingNo()));
|
export.setCreatedAt(DateTimes.format(row.getCreatedAt()));
|
exports.add(export);
|
}
|
FastExcel.write(response.getOutputStream(), PointsExchangeOrderExcelRow.class)
|
.sheet("积分兑换汇总订单")
|
.doWrite(exports);
|
}
|
|
public void exportItems(HttpServletResponse response,
|
Long orderId,
|
String orderNo,
|
String buyerPhone,
|
String giftName,
|
String receiverPhone,
|
Integer 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<PointsExchangeItemRow> rows = pointsExchangeOrderItemMapper.selectItemList(
|
orderId,
|
trimToNull(orderNo),
|
trimToNull(buyerPhone),
|
trimToNull(giftName),
|
trimToNull(receiverPhone),
|
status,
|
createdFrom,
|
createdTo
|
);
|
List<PointsExchangeItemExcelRow> exports = new ArrayList<PointsExchangeItemExcelRow>();
|
for (int i = 0; i < rows.size(); i++) {
|
PointsExchangeItemRow row = rows.get(i);
|
PointsExchangeItemExcelRow export = new PointsExchangeItemExcelRow();
|
export.setSerialNo(i + 1);
|
export.setOrderNo(row.getOrderNo());
|
export.setBuyerNickname(defaultText(row.getBuyerNickname()));
|
export.setBuyerPhone(PhoneMasker.mask(row.getBuyerPhone()));
|
export.setGiftName(defaultText(row.getGiftName()));
|
export.setSettledPoints(row.getSettledPoints());
|
export.setReceiverName(defaultText(row.getReceiverName()));
|
export.setReceiverPhone(PhoneMasker.mask(row.getReceiverPhone()));
|
export.setReceiverAddress(defaultText(row.getReceiverAddress()));
|
export.setStatus(itemStatusText(row.getStatus()));
|
export.setTrackingNo(defaultText(row.getTrackingNo()));
|
export.setCreatedAt(DateTimes.format(row.getCreatedAt()));
|
exports.add(export);
|
}
|
FastExcel.write(response.getOutputStream(), PointsExchangeItemExcelRow.class)
|
.sheet("积分兑换明细订单")
|
.doWrite(exports);
|
}
|
|
private void refreshOrderStatus(Long orderId, String trackingNo, LocalDateTime shippedAt) {
|
if (orderId == null) {
|
return;
|
}
|
PointsExchangeOrder order = requireOrder(orderId);
|
List<PointsExchangeOrderItem> items = pointsExchangeOrderItemMapper.selectList(new LambdaQueryWrapper<PointsExchangeOrderItem>()
|
.eq(PointsExchangeOrderItem::getDeleted, 0)
|
.eq(PointsExchangeOrderItem::getOrderId, orderId));
|
if (items.isEmpty()) {
|
pointsExchangeOrderMapper.deleteById(orderId);
|
return;
|
}
|
boolean allCompleted = true;
|
boolean anyShipped = false;
|
for (PointsExchangeOrderItem item : items) {
|
int status = item.getStatus() == null ? 0 : item.getStatus();
|
if (status != 2) {
|
allCompleted = false;
|
}
|
if (status == 1 || status == 2) {
|
anyShipped = true;
|
}
|
}
|
if (allCompleted) {
|
order.setStatus(2);
|
} else if (anyShipped) {
|
order.setStatus(1);
|
if (trackingNo != null) {
|
order.setTrackingNo(trackingNo);
|
}
|
if (shippedAt != null) {
|
order.setShippedAt(shippedAt);
|
}
|
} else {
|
order.setStatus(0);
|
}
|
pointsExchangeOrderMapper.updateById(order);
|
}
|
|
private PointsExchangeOrder requireOrder(Long id) {
|
PointsExchangeOrder order = pointsExchangeOrderMapper.selectOne(new LambdaQueryWrapper<PointsExchangeOrder>()
|
.eq(PointsExchangeOrder::getId, id)
|
.eq(PointsExchangeOrder::getDeleted, 0)
|
.last("limit 1"));
|
if (order == null) {
|
throw new IllegalArgumentException("汇总订单不存在");
|
}
|
return order;
|
}
|
|
private PointsExchangeOrderItem requireItem(Long id) {
|
PointsExchangeOrderItem item = pointsExchangeOrderItemMapper.selectOne(new LambdaQueryWrapper<PointsExchangeOrderItem>()
|
.eq(PointsExchangeOrderItem::getId, id)
|
.eq(PointsExchangeOrderItem::getDeleted, 0)
|
.last("limit 1"));
|
if (item == null) {
|
throw new IllegalArgumentException("兑换明细不存在");
|
}
|
return item;
|
}
|
|
private void validatePendingStatus(Integer status) {
|
if (status == null || status != 0) {
|
throw new IllegalArgumentException("当前订单状态不允许发货");
|
}
|
}
|
|
private List<PointsExchangeOrderListItemVO> toOrderList(List<PointsExchangeOrderRow> rows) {
|
List<PointsExchangeOrderListItemVO> list = new ArrayList<PointsExchangeOrderListItemVO>();
|
for (PointsExchangeOrderRow row : rows) {
|
PointsExchangeOrderListItemVO item = new PointsExchangeOrderListItemVO();
|
item.setId(row.getId());
|
item.setOrderNo(row.getOrderNo());
|
item.setGiftName(row.getGiftName());
|
item.setRequiredPoints(row.getRequiredPoints());
|
item.setActivityStartAt(row.getActivityStartAt());
|
item.setActivityEndAt(row.getActivityEndAt());
|
item.setClinicName(row.getClinicName());
|
item.setReceiverClinicName(row.getReceiverClinicName());
|
item.setReceiverPhone(PhoneMasker.mask(row.getReceiverPhone()));
|
item.setReceiverAddress(row.getReceiverAddress());
|
item.setItemCount(row.getItemCount());
|
item.setTotalPoints(row.getTotalPoints());
|
item.setStatus(row.getStatus());
|
item.setTrackingNo(row.getTrackingNo());
|
item.setShippedAt(row.getShippedAt());
|
item.setCreatedAt(row.getCreatedAt());
|
list.add(item);
|
}
|
return list;
|
}
|
|
private List<PointsExchangeItemListItemVO> toItemList(List<PointsExchangeItemRow> rows) {
|
List<PointsExchangeItemListItemVO> list = new ArrayList<PointsExchangeItemListItemVO>();
|
for (PointsExchangeItemRow row : rows) {
|
PointsExchangeItemListItemVO item = new PointsExchangeItemListItemVO();
|
item.setId(row.getId());
|
item.setOrderId(row.getOrderId());
|
item.setOrderNo(row.getOrderNo());
|
item.setBuyerNickname(row.getBuyerNickname());
|
item.setBuyerPhone(PhoneMasker.mask(row.getBuyerPhone()));
|
item.setClinicName(row.getClinicName());
|
item.setSettledPoints(row.getSettledPoints());
|
item.setGiftName(row.getGiftName());
|
item.setRequiredPoints(row.getRequiredPoints());
|
item.setReceiverName(row.getReceiverName());
|
item.setReceiverPhone(PhoneMasker.mask(row.getReceiverPhone()));
|
item.setReceiverAddress(row.getReceiverAddress());
|
item.setStatus(row.getStatus());
|
item.setTrackingNo(row.getTrackingNo());
|
item.setShippedAt(row.getShippedAt());
|
item.setCreatedAt(row.getCreatedAt());
|
list.add(item);
|
}
|
return list;
|
}
|
|
private String trimToNull(String text) {
|
if (text == null) {
|
return null;
|
}
|
String value = text.trim();
|
return value.isEmpty() ? null : value;
|
}
|
|
private String formatRange(LocalDateTime start, LocalDateTime end) {
|
return defaultText(DateTimes.format(start)) + " - " + defaultText(DateTimes.format(end));
|
}
|
|
private String orderStatusText(Integer status) {
|
if (status == null) {
|
return "-";
|
}
|
if (status == 0) {
|
return "待发货";
|
}
|
if (status == 1) {
|
return "已发货";
|
}
|
if (status == 2) {
|
return "已收货";
|
}
|
return "-";
|
}
|
|
private String itemStatusText(Integer status) {
|
if (status == null) {
|
return "-";
|
}
|
if (status == 0) {
|
return "待发货";
|
}
|
if (status == 1) {
|
return "待取货";
|
}
|
if (status == 2) {
|
return "兑换完成";
|
}
|
return "-";
|
}
|
|
private String defaultText(String text) {
|
if (text == null || text.trim().isEmpty()) {
|
return "-";
|
}
|
return text;
|
}
|
}
|