拆分订单仓储模块
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
package order
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"hfb_sys/backend/internal/model"
|
||||
"hfb_sys/backend/internal/modules/notification"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
func (r *Repository) AdminClose(adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
|
||||
var refund *refundAction
|
||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
||||
order, listing, account, err := r.findOrderAssetsForAdminUpdate(tx, orderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isTerminalStatus(order.Status) {
|
||||
return ErrOrderCannotComplete
|
||||
}
|
||||
beforeOrderStatus := order.Status
|
||||
beforeHandoffStatus := order.HandoffStatus
|
||||
beforeSettlementStatus := order.SettlementStatus
|
||||
beforeListingStatus := listing.Status
|
||||
beforeAccountStatus := account.Status
|
||||
now := time.Now()
|
||||
order.Status = "closed"
|
||||
order.HandoffStatus = "admin_closed"
|
||||
order.SettlementStatus = "closed"
|
||||
order.SettledAt = &now
|
||||
listing.Status = "offline"
|
||||
listing.InTransaction = false
|
||||
account.Status = "offline"
|
||||
if beforeOrderStatus != "pending_payment" {
|
||||
totalCent := order.RentAmountCent + order.DepositAmountCent
|
||||
action, err := r.prepareRefund(order, totalCent, "admin_close_refund", "客服关闭订单原路退款")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refund = action
|
||||
}
|
||||
if err := notification.Append(tx,
|
||||
notification.Entry{
|
||||
UserID: order.RenterID,
|
||||
Type: "order_admin",
|
||||
Title: "订单已由客服关闭",
|
||||
Content: "客服已关闭订单,退款将原路退回您的支付账户。原因:" + req.Reason,
|
||||
BizType: "order",
|
||||
BizID: &order.ID,
|
||||
},
|
||||
notification.Entry{
|
||||
UserID: order.OwnerID,
|
||||
Type: "order_admin",
|
||||
Title: "订单已由客服关闭",
|
||||
Content: "客服已关闭订单,关联商品已下架。原因:" + req.Reason,
|
||||
BizType: "order",
|
||||
BizID: &order.ID,
|
||||
},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := appendAuditLog(tx, adminID, "order.admin_close", "order", order.ID, meta, map[string]any{
|
||||
"order_id": order.ID,
|
||||
"order_no": order.OrderNo,
|
||||
"listing_id": order.ListingID,
|
||||
"account_id": order.AccountID,
|
||||
"reason": req.Reason,
|
||||
"before_order_status": beforeOrderStatus,
|
||||
"after_order_status": order.Status,
|
||||
"before_handoff_status": beforeHandoffStatus,
|
||||
"after_handoff_status": order.HandoffStatus,
|
||||
"before_settlement_status": beforeSettlementStatus,
|
||||
"after_settlement_status": order.SettlementStatus,
|
||||
"before_listing_status": beforeListingStatus,
|
||||
"after_listing_status": listing.Status,
|
||||
"before_account_status": beforeAccountStatus,
|
||||
"after_account_status": account.Status,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Save(order).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Save(listing).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Save(account).Error
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.startRefundBestEffort(refund)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) AdminMarkAbnormal(adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
|
||||
return r.db.Transaction(func(tx *gorm.DB) error {
|
||||
order, listing, account, err := r.findOrderAssetsForAdminUpdate(tx, orderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isTerminalStatus(order.Status) {
|
||||
return ErrOrderCannotComplete
|
||||
}
|
||||
beforeOrderStatus := order.Status
|
||||
beforeHandoffStatus := order.HandoffStatus
|
||||
beforeListingStatus := listing.Status
|
||||
beforeAccountStatus := account.Status
|
||||
order.Status = "abnormal"
|
||||
order.HandoffStatus = "admin_abnormal"
|
||||
listing.Status = "abnormal"
|
||||
listing.InTransaction = false
|
||||
account.Status = "abnormal"
|
||||
if err := notification.Append(tx,
|
||||
notification.Entry{
|
||||
UserID: order.RenterID,
|
||||
Type: "order_admin",
|
||||
Title: "订单已被标记异常",
|
||||
Content: "客服已将订单标记为异常,请等待进一步处理。原因:" + req.Reason,
|
||||
BizType: "order",
|
||||
BizID: &order.ID,
|
||||
},
|
||||
notification.Entry{
|
||||
UserID: order.OwnerID,
|
||||
Type: "order_admin",
|
||||
Title: "订单已被标记异常",
|
||||
Content: "客服已将订单标记为异常,关联商品暂不可出租。原因:" + req.Reason,
|
||||
BizType: "order",
|
||||
BizID: &order.ID,
|
||||
},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := appendAuditLog(tx, adminID, "order.mark_abnormal", "order", order.ID, meta, map[string]any{
|
||||
"order_id": order.ID,
|
||||
"order_no": order.OrderNo,
|
||||
"listing_id": order.ListingID,
|
||||
"account_id": order.AccountID,
|
||||
"reason": req.Reason,
|
||||
"before_order_status": beforeOrderStatus,
|
||||
"after_order_status": order.Status,
|
||||
"before_handoff_status": beforeHandoffStatus,
|
||||
"after_handoff_status": order.HandoffStatus,
|
||||
"before_listing_status": beforeListingStatus,
|
||||
"after_listing_status": listing.Status,
|
||||
"before_account_status": beforeAccountStatus,
|
||||
"after_account_status": account.Status,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Save(order).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Save(listing).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Save(account).Error
|
||||
})
|
||||
}
|
||||
|
||||
// AdminRefund 触发后台人工退款,退款由 payment 模块走渠道原路退回。
|
||||
func (r *Repository) AdminRefund(orderID uint64) (*RefundStatusDTO, error) {
|
||||
var order model.RentalOrder
|
||||
if err := r.db.First(&order, orderID).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if order.RefundStatus == "refunded" {
|
||||
return r.buildRefundStatusDTO(&order), nil
|
||||
}
|
||||
if r.refundFunc == nil {
|
||||
return nil, ErrDependencyUnavailable
|
||||
}
|
||||
totalCent := order.RentAmountCent + order.DepositAmountCent
|
||||
if totalCent <= 0 {
|
||||
return nil, ErrInvalidCheckoutAmount
|
||||
}
|
||||
status, err := r.refundFunc(orderID, totalCent, "admin_refund", "后台人工退款")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 重新读取订单,拿到 payment 模块更新后的退款字段。
|
||||
if err := r.db.First(&order, orderID).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dto := r.buildRefundStatusDTO(&order)
|
||||
if status != "" {
|
||||
dto.RefundStatus = status
|
||||
}
|
||||
return dto, nil
|
||||
}
|
||||
|
||||
// AdminRefundStatus 查询订单退款状态。
|
||||
func (r *Repository) AdminRefundStatus(orderID uint64) (*RefundStatusDTO, error) {
|
||||
var order model.RentalOrder
|
||||
if err := r.db.First(&order, orderID).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.buildRefundStatusDTO(&order), nil
|
||||
}
|
||||
|
||||
func (r *Repository) buildRefundStatusDTO(order *model.RentalOrder) *RefundStatusDTO {
|
||||
return &RefundStatusDTO{
|
||||
OrderID: order.ID,
|
||||
OrderNo: order.OrderNo,
|
||||
RefundStatus: order.RefundStatus,
|
||||
RefundAmountCent: order.RefundAmountCent,
|
||||
RefundedAt: order.RefundedAt,
|
||||
TotalAmountCent: order.RentAmountCent + order.DepositAmountCent,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Repository) findOrderAssetsForAdminUpdate(tx *gorm.DB, orderID uint64) (*model.RentalOrder, *model.RentalListing, *model.GameAccount, error) {
|
||||
var order model.RentalOrder
|
||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&order, orderID).Error; err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
var listing model.RentalListing
|
||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&listing, order.ListingID).Error; err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
var account model.GameAccount
|
||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&account, order.AccountID).Error; err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return &order, &listing, &account, nil
|
||||
}
|
||||
|
||||
func isTerminalStatus(status string) bool {
|
||||
return status == "completed" || status == "cancelled" || status == "closed"
|
||||
}
|
||||
Reference in New Issue
Block a user