198 lines
6.0 KiB
Go
198 lines
6.0 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/global"
|
|
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/dto"
|
|
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/mysqldao"
|
|
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/mysqlmodel"
|
|
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/errcode"
|
|
)
|
|
|
|
// OrderService 订单与退款管理服务。
|
|
type OrderService struct {
|
|
orderDao *mysqldao.OrderDao
|
|
refundDao *mysqldao.RefundDao
|
|
}
|
|
|
|
// NewOrderService 创建订单服务。
|
|
func NewOrderService() *OrderService {
|
|
return &OrderService{
|
|
orderDao: mysqldao.NewOrderDao(),
|
|
refundDao: mysqldao.NewRefundDao(),
|
|
}
|
|
}
|
|
|
|
// List 分页查询订单。
|
|
func (s *OrderService) List(ctx context.Context, request *dto.OrderListRequest) (*dto.OrderListResponse, *errcode.Error) {
|
|
ctx, span := global.Tracer.Start(ctx, "svc.AdminOrderList")
|
|
defer span.End()
|
|
|
|
page, pageSize := normalizePage(request.Page, request.PageSize)
|
|
|
|
list, total, err := s.orderDao.OrderList(ctx, mysqldao.OrderListParams{
|
|
OrderNo: strings.TrimSpace(request.OrderNo),
|
|
TransactionID: strings.TrimSpace(request.TransactionID),
|
|
UserID: request.UserID,
|
|
Status: request.Status,
|
|
Page: page,
|
|
Size: pageSize,
|
|
})
|
|
if err != nil {
|
|
return nil, errcode.DatabaseError
|
|
}
|
|
|
|
items := make([]dto.OrderItem, 0, len(list))
|
|
for i := range list {
|
|
items = append(items, buildOrderItem(&list[i]))
|
|
}
|
|
return &dto.OrderListResponse{
|
|
PageResponse: dto.PageResponse{Total: total, Page: page, PageSize: pageSize},
|
|
List: items,
|
|
}, nil
|
|
}
|
|
|
|
// Get 订单详情。
|
|
func (s *OrderService) Get(ctx context.Context, orderNo string) (*dto.OrderItem, *errcode.Error) {
|
|
ctx, span := global.Tracer.Start(ctx, "svc.AdminOrderGet")
|
|
defer span.End()
|
|
|
|
order, err := s.orderDao.OrderGetByOrderNo(ctx, orderNo)
|
|
if err != nil {
|
|
if isNotFound(err) {
|
|
return nil, errcode.OrderNotFound
|
|
}
|
|
return nil, errcode.DatabaseError
|
|
}
|
|
item := buildOrderItem(order)
|
|
return &item, nil
|
|
}
|
|
|
|
// RefundList 分页查询退款单。
|
|
func (s *OrderService) RefundList(ctx context.Context, request *dto.RefundListRequest) (*dto.RefundListResponse, *errcode.Error) {
|
|
ctx, span := global.Tracer.Start(ctx, "svc.AdminRefundList")
|
|
defer span.End()
|
|
|
|
page, pageSize := normalizePage(request.Page, request.PageSize)
|
|
|
|
// status 未传时 query 绑定为 nil,与「待处理=0」天然区分。
|
|
withStatus := request.Status != nil
|
|
var status int8
|
|
if withStatus {
|
|
status = *request.Status
|
|
}
|
|
|
|
list, total, err := s.refundDao.RefundList(ctx, mysqldao.RefundListParams{
|
|
Status: status,
|
|
WithStatus: withStatus,
|
|
OrderNo: strings.TrimSpace(request.OrderNo),
|
|
Page: page,
|
|
Size: pageSize,
|
|
})
|
|
if err != nil {
|
|
return nil, errcode.DatabaseError
|
|
}
|
|
|
|
items := make([]dto.RefundItem, 0, len(list))
|
|
for i := range list {
|
|
items = append(items, buildRefundItem(&list[i]))
|
|
}
|
|
return &dto.RefundListResponse{
|
|
PageResponse: dto.PageResponse{Total: total, Page: page, PageSize: pageSize},
|
|
List: items,
|
|
}, nil
|
|
}
|
|
|
|
// RefundApprove 审核通过:待处理(0) → 退款中(1)。
|
|
// 实际打款由运营在微信商户平台人工完成,业务服务退款回调负责后续「成功(2)」流转与权益回收。
|
|
func (s *OrderService) RefundApprove(ctx context.Context, adminID int64, refundNo string, request *dto.RefundAuditRequest) *errcode.Error {
|
|
ctx, span := global.Tracer.Start(ctx, "svc.AdminRefundApprove")
|
|
defer span.End()
|
|
|
|
if _, err := s.refundDao.RefundGetByRefundNo(ctx, refundNo); err != nil {
|
|
if isNotFound(err) {
|
|
return errcode.RefundNotFound
|
|
}
|
|
return errcode.DatabaseError
|
|
}
|
|
|
|
ok, err := s.refundDao.RefundTransition(ctx, refundNo, RefundStatusPending, RefundStatusProcessing, "")
|
|
if err != nil {
|
|
return errcode.DatabaseError
|
|
}
|
|
if !ok {
|
|
return errcode.RefundStatusInvalid.WithDetails("仅待处理状态的退款单可审核")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RefundReject 审核驳回:待处理(0) → 失败(3),记录驳回原因。
|
|
func (s *OrderService) RefundReject(ctx context.Context, adminID int64, refundNo string, request *dto.RefundAuditRequest) *errcode.Error {
|
|
ctx, span := global.Tracer.Start(ctx, "svc.AdminRefundReject")
|
|
defer span.End()
|
|
|
|
if _, err := s.refundDao.RefundGetByRefundNo(ctx, refundNo); err != nil {
|
|
if isNotFound(err) {
|
|
return errcode.RefundNotFound
|
|
}
|
|
return errcode.DatabaseError
|
|
}
|
|
|
|
ok, err := s.refundDao.RefundTransition(ctx, refundNo, RefundStatusPending, RefundStatusFailed, strings.TrimSpace(request.Reason))
|
|
if err != nil {
|
|
return errcode.DatabaseError
|
|
}
|
|
if !ok {
|
|
return errcode.RefundStatusInvalid.WithDetails("仅待处理状态的退款单可审核")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// buildOrderItem 订单模型 → 响应。
|
|
func buildOrderItem(o *mysqlmodel.Order) dto.OrderItem {
|
|
return dto.OrderItem{
|
|
OrderNo: o.OrderNo,
|
|
UserID: o.UserID,
|
|
GoodsID: o.GoodsID,
|
|
GoodsName: o.GoodsName,
|
|
UnitPrice: o.UnitPrice,
|
|
TotalAmount: o.TotalAmount,
|
|
PayAmount: o.PayAmount,
|
|
PayChannel: o.PayChannel,
|
|
OrderStatus: o.OrderStatus,
|
|
TransactionID: o.TransactionID,
|
|
MemberDays: o.MemberDays,
|
|
UploadQuota: o.CosQuota,
|
|
AIRecommendQuota: o.AIRecommendQuota,
|
|
ClosetShareQuota: o.ClosetShareQuota,
|
|
OutfitShareQuota: o.OutfitShareQuota,
|
|
ExpireTime: o.ExpireTime,
|
|
PayTime: o.PayTime,
|
|
RefundTime: o.RefundTime,
|
|
RefundAmount: o.RefundAmount,
|
|
Remark: o.Remark,
|
|
XPayProductID: o.XPayProductID,
|
|
XPayPlatform: o.XPayPlatform,
|
|
XPayEnv: o.XPayEnv,
|
|
CreatedAt: o.CreatedAt,
|
|
}
|
|
}
|
|
|
|
// buildRefundItem 退款单模型 → 响应。
|
|
func buildRefundItem(r *mysqlmodel.RefundFlowLog) dto.RefundItem {
|
|
return dto.RefundItem{
|
|
RefundNo: r.RefundNo,
|
|
OrderNo: r.OrderNo,
|
|
UserID: r.UserID,
|
|
RefundAmount: r.RefundAmount,
|
|
RefundReason: r.RefundReason,
|
|
Status: r.Status,
|
|
ApplyTime: r.ApplyTime,
|
|
SuccessTime: r.SuccessTime,
|
|
FailReason: r.FailReason,
|
|
CreatedAt: r.CreatedAt,
|
|
}
|
|
}
|