593 lines
20 KiB
Go
593 lines
20 KiB
Go
package order
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"hfb_sys/backend/internal/model"
|
|
"hfb_sys/backend/internal/modules/notification"
|
|
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
func (r *Repository) AdminClose(ctx context.Context, adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
|
|
var refund *refundAction
|
|
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
assets, err := r.lockOrderAssets(tx, orderID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
order := assets.Order
|
|
listing := assets.Listing
|
|
account := assets.Account
|
|
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 = orderStatusClosed
|
|
order.HandoffStatus = handoffStatusAdminClosed
|
|
order.SettlementStatus = settlementStatusClosed
|
|
order.SettledAt = &now
|
|
if err := archiveAssets(tx, listing, account); err != nil {
|
|
return err
|
|
}
|
|
if beforeOrderStatus != orderStatusPendingPayment {
|
|
totalCent := order.RentAmountCent + order.DepositAmountCent
|
|
// 押金暂扣:若订单已暂扣,拦截退款中的押金部分挂起不退,其余照常原路退。
|
|
refundAmountCent := order.ApplyDepositHold(totalCent, order.DepositAmountCent)
|
|
action, err := r.prepareRefund(order, refundAmountCent, refundBizAdminClose, "客服关闭订单原路退款")
|
|
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(ctx, refund)
|
|
return nil
|
|
}
|
|
|
|
func (r *Repository) AdminMarkAbnormal(ctx context.Context, adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
|
|
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
assets, err := r.lockOrderAssets(tx, orderID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
order := assets.Order
|
|
listing := assets.Listing
|
|
account := assets.Account
|
|
if isTerminalStatus(order.Status) {
|
|
return ErrOrderCannotComplete
|
|
}
|
|
beforeOrderStatus := order.Status
|
|
beforeHandoffStatus := order.HandoffStatus
|
|
beforeListingStatus := listing.Status
|
|
beforeAccountStatus := account.Status
|
|
order.Status = orderStatusAbnormal
|
|
order.HandoffStatus = handoffStatusAdminAbnormal
|
|
if err := markAssetsAbnormal(tx, listing, account); err != nil {
|
|
return err
|
|
}
|
|
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
|
|
})
|
|
}
|
|
|
|
type adminResetTarget struct {
|
|
OrderStatus string
|
|
HandoffStatus string
|
|
Label string
|
|
OwnerTitle string
|
|
OwnerContent string
|
|
RenterTitle string
|
|
RenterContent string
|
|
AuditAction string
|
|
RefreshStageTime bool
|
|
RecalculateEnd bool
|
|
}
|
|
|
|
// AdminResetHandoff 将超时卡住的订单恢复到对应待办阶段,并刷新阶段计时,
|
|
// 让客服可以给责任方再次处理机会,避免订单卡死在异常状态。
|
|
func (r *Repository) AdminResetHandoff(ctx context.Context, adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
|
|
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
var order model.RentalOrder
|
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&order, orderID).Error; err != nil {
|
|
return err
|
|
}
|
|
target, ok := resetTargetForOrder(order)
|
|
if !ok {
|
|
return ErrOrderCannotResetHandoff
|
|
}
|
|
beforeOrderStatus := order.Status
|
|
beforeHandoffStatus := order.HandoffStatus
|
|
now := time.Now()
|
|
order.Status = target.OrderStatus
|
|
order.HandoffStatus = target.HandoffStatus
|
|
if target.RefreshStageTime {
|
|
order.HandoffStartedAt = &now
|
|
}
|
|
if target.RecalculateEnd {
|
|
durationHours := estimateOrderDurationHours(order.AccountSnapshot)
|
|
if durationHours > 0 {
|
|
order.EstimatedDurationHours = durationHours
|
|
}
|
|
if order.RentedAt == nil {
|
|
order.RentedAt = &now
|
|
}
|
|
if order.RentedAt != nil {
|
|
estimatedEndAt := order.RentedAt.Add(time.Duration(order.EstimatedDurationHours) * time.Hour)
|
|
if !estimatedEndAt.After(now) {
|
|
order.RentedAt = &now
|
|
}
|
|
}
|
|
}
|
|
if err := notification.Append(tx,
|
|
notification.Entry{
|
|
UserID: order.OwnerID,
|
|
Type: "order_admin",
|
|
Title: target.OwnerTitle,
|
|
Content: target.OwnerContent + "原因:" + req.Reason,
|
|
BizType: "order",
|
|
BizID: &order.ID,
|
|
},
|
|
notification.Entry{
|
|
UserID: order.RenterID,
|
|
Type: "order_admin",
|
|
Title: target.RenterTitle,
|
|
Content: target.RenterContent + "原因:" + req.Reason,
|
|
BizType: "order",
|
|
BizID: &order.ID,
|
|
},
|
|
); err != nil {
|
|
return err
|
|
}
|
|
if err := appendAuditLog(tx, adminID, target.AuditAction, "order", order.ID, meta, map[string]any{
|
|
"order_id": order.ID,
|
|
"order_no": order.OrderNo,
|
|
"reason": req.Reason,
|
|
"before_order_status": beforeOrderStatus,
|
|
"after_order_status": order.Status,
|
|
"before_handoff_status": beforeHandoffStatus,
|
|
"after_handoff_status": order.HandoffStatus,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
return tx.Save(&order).Error
|
|
})
|
|
}
|
|
|
|
func resetTargetForOrder(order model.RentalOrder) (adminResetTarget, bool) {
|
|
if order.Status == orderStatusPendingHandoff && order.HandoffStatus == handoffStatusOwnerTimeout {
|
|
return adminResetTarget{
|
|
OrderStatus: orderStatusPendingHandoff,
|
|
HandoffStatus: handoffStatusPendingOwner,
|
|
Label: "重置交接",
|
|
OwnerTitle: "请重新提交交接说明",
|
|
OwnerContent: "客服已重置交接状态,请尽快提交交接说明,避免再次超时。",
|
|
RenterTitle: "订单交接已重置",
|
|
RenterContent: "客服已重置交接状态,正在等待号主重新提交交接说明。",
|
|
AuditAction: "order.reset_handoff",
|
|
RefreshStageTime: true,
|
|
}, true
|
|
}
|
|
if order.Status == orderStatusAbnormal && order.HandoffStatus == handoffStatusRenterConfirmTimeout {
|
|
return adminResetTarget{
|
|
OrderStatus: orderStatusPendingHandoff,
|
|
HandoffStatus: handoffStatusPendingRenterConfirm,
|
|
Label: "重置确认收号",
|
|
OwnerTitle: "订单确认收号已重置",
|
|
OwnerContent: "客服已重置确认收号状态,正在等待租客重新确认收号。",
|
|
RenterTitle: "请重新确认收号",
|
|
RenterContent: "客服已重置确认收号状态,请尽快检查账号并确认收号,避免再次超时。",
|
|
AuditAction: "order.reset_renter_confirm",
|
|
RefreshStageTime: true,
|
|
}, true
|
|
}
|
|
if order.Status == orderStatusAbnormal &&
|
|
(order.HandoffStatus == handoffStatusOwnerCheckoutConfirmTimeout ||
|
|
order.HandoffStatus == handoffStatusOwnerReturnConfirmTimeout) {
|
|
return adminResetTarget{
|
|
OrderStatus: orderStatusPendingCheckoutConfirm,
|
|
HandoffStatus: handoffStatusPendingOwnerCheckout,
|
|
Label: "重置结账确认",
|
|
OwnerTitle: "请重新确认结账",
|
|
OwnerContent: "客服已重置结账确认状态,请尽快核对账号和结账金额,避免再次超时。",
|
|
RenterTitle: "结账确认已重置",
|
|
RenterContent: "客服已重置结账确认状态,正在等待号主重新确认结账。",
|
|
AuditAction: "order.reset_checkout_confirm",
|
|
RefreshStageTime: true,
|
|
}, true
|
|
}
|
|
if order.Status == orderStatusOverdue && order.HandoffStatus == handoffStatusReturnOverdue {
|
|
return adminResetTarget{
|
|
OrderStatus: orderStatusRenting,
|
|
HandoffStatus: handoffStatusReceived,
|
|
Label: "重置归还逾期",
|
|
OwnerTitle: "订单归还逾期已重置",
|
|
OwnerContent: "客服已重置归还逾期状态,订单恢复为使用中。",
|
|
RenterTitle: "请及时发起结账",
|
|
RenterContent: "客服已重置归还逾期状态,请尽快发起结账。",
|
|
AuditAction: "order.reset_return_overdue",
|
|
RecalculateEnd: true,
|
|
}, true
|
|
}
|
|
return adminResetTarget{}, false
|
|
}
|
|
|
|
// AdminRefund 触发后台人工退款,退款由 payment 模块走渠道原路退回。
|
|
func (r *Repository) AdminRefund(ctx context.Context, orderID uint64) (*RefundStatusDTO, error) {
|
|
db := r.db.WithContext(ctx)
|
|
var refund *refundAction
|
|
err := db.Transaction(func(tx *gorm.DB) error {
|
|
var order model.RentalOrder
|
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&order, orderID).Error; err != nil {
|
|
return err
|
|
}
|
|
if order.RefundStatus == refundStatusRefunded {
|
|
return nil
|
|
}
|
|
totalCent := order.RentAmountCent + order.DepositAmountCent
|
|
if totalCent <= 0 {
|
|
return ErrInvalidCheckoutAmount
|
|
}
|
|
// 押金暂扣:人工退款也必须尊重暂扣状态,避免绕过押金挂起直接全额退款。
|
|
refundAmountCent := order.ApplyDepositHold(totalCent, order.DepositAmountCent)
|
|
if refundAmountCent <= 0 {
|
|
order.RefundStatus = "none"
|
|
order.RefundAmountCent = 0
|
|
return tx.Save(&order).Error
|
|
}
|
|
if r.refundStarter == nil {
|
|
return ErrDependencyUnavailable
|
|
}
|
|
action, err := r.prepareRefund(&order, refundAmountCent, refundBizAdmin, "后台人工退款")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
refund = action
|
|
return tx.Save(&order).Error
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
status := ""
|
|
if refund != nil {
|
|
var err error
|
|
status, err = r.refundStarter.StartRefund(ctx, refund.OrderID, refund.RefundAmountCent, refund.BizType, refund.Remark)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
// 重新读取订单,拿到 payment 模块更新后的退款字段。
|
|
var order model.RentalOrder
|
|
if err := 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(ctx context.Context, orderID uint64) (*RefundStatusDTO, error) {
|
|
var order model.RentalOrder
|
|
if err := r.db.WithContext(ctx).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,
|
|
}
|
|
}
|
|
|
|
// AdminApproveRefund 客服审核通过退款申请,触发渠道原路退款。
|
|
func (r *Repository) AdminApproveRefund(ctx context.Context, orderID uint64) error {
|
|
var refund *refundAction
|
|
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
var order model.RentalOrder
|
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&order, orderID).Error; err != nil {
|
|
return err
|
|
}
|
|
if order.RefundStatus != refundStatusPendingReview {
|
|
return errors.New("订单不处于待审核退款状态")
|
|
}
|
|
if order.RefundAmountCent <= 0 {
|
|
return errors.New("退款金额无效")
|
|
}
|
|
// 押金暂扣:若订单已暂扣,拦截退款中的押金部分挂起不退,其余照常原路退。
|
|
refundAmountCent := order.ApplyDepositHold(order.RefundAmountCent, order.DepositAmountCent)
|
|
if refundAmountCent <= 0 {
|
|
// 全部押金被暂扣且无其他可退金额,直接标记为已处理,等待后续手动退押金。
|
|
order.RefundStatus = "none"
|
|
order.RefundAmountCent = 0
|
|
return tx.Save(&order).Error
|
|
}
|
|
action, err := r.prepareRefund(&order, refundAmountCent, refundBizCancel, "取消订单原路退款(客服审核通过)")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
refund = action
|
|
return tx.Save(&order).Error
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r.startRefundBestEffort(ctx, refund)
|
|
return nil
|
|
}
|
|
|
|
// AdminRejectRefund 客服驳回退款申请。
|
|
// action: "restore" 恢复订单至待交接继续流转;"close" 关闭订单并归档商品。
|
|
func (r *Repository) AdminRejectRefund(ctx context.Context, orderID uint64, action string) error {
|
|
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
assets, err := r.lockOrderAssets(tx, orderID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
order := assets.Order
|
|
listing := assets.Listing
|
|
account := assets.Account
|
|
|
|
if order.RefundStatus != refundStatusPendingReview {
|
|
return errors.New("订单不处于待审核退款状态")
|
|
}
|
|
|
|
order.RefundStatus = "none"
|
|
order.RefundAmountCent = 0
|
|
|
|
switch action {
|
|
case "restore":
|
|
if order.Status != orderStatusCancelled {
|
|
return errors.New("仅已取消的订单可以恢复")
|
|
}
|
|
active, err := hasActiveSiblingOrder(tx, order)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if active {
|
|
return ErrListingUnavailable
|
|
}
|
|
order.Status = orderStatusPendingHandoff
|
|
if order.HandoffStatus == handoffStatusCancelled || order.HandoffStatus == handoffStatusRenterConfirmTimeout {
|
|
order.HandoffStatus = handoffStatusPendingOwner
|
|
}
|
|
order.SettlementStatus = settlementStatusUnsettled
|
|
order.SettledAt = nil
|
|
reserveListingForOrder(listing)
|
|
if err := markAssetsRented(tx, listing, account); err != nil {
|
|
return err
|
|
}
|
|
|
|
case "close":
|
|
now := time.Now()
|
|
order.Status = orderStatusClosed
|
|
order.HandoffStatus = handoffStatusAdminClosed
|
|
order.SettlementStatus = settlementStatusClosed
|
|
order.SettledAt = &now
|
|
if err := archiveAssets(tx, listing, account); err != nil {
|
|
return err
|
|
}
|
|
|
|
default:
|
|
return errors.New("无效的驳回操作,可选 restore 或 close")
|
|
}
|
|
|
|
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
|
|
})
|
|
}
|
|
|
|
// AdminSeal 客服封存订单:关闭订单并全额原路退款,将关联商品/账号置为终态 sealed
|
|
// (号主不可再编辑、提审、上架),同时在同一事务内解散关联群聊。
|
|
// 适用于号主失联、无法继续交接,需要终止并永久封存该商品的场景。
|
|
func (r *Repository) AdminSeal(ctx context.Context, adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
|
|
var refund *refundAction
|
|
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
assets, err := r.lockOrderAssets(tx, orderID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
order := assets.Order
|
|
listing := assets.Listing
|
|
account := assets.Account
|
|
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 = orderStatusClosed
|
|
order.HandoffStatus = handoffStatusAdminClosed
|
|
order.SettlementStatus = settlementStatusClosed
|
|
order.SettledAt = &now
|
|
if err := sealAssets(tx, listing, account); err != nil {
|
|
return err
|
|
}
|
|
if beforeOrderStatus != orderStatusPendingPayment {
|
|
totalCent := order.RentAmountCent + order.DepositAmountCent
|
|
// 押金暂扣:若订单已暂扣,拦截退款中的押金部分挂起不退,其余照常原路退。
|
|
refundAmountCent := order.ApplyDepositHold(totalCent, order.DepositAmountCent)
|
|
action, err := r.prepareRefund(order, refundAmountCent, refundBizAdminSeal, "客服封存订单原路退款")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
refund = action
|
|
}
|
|
if r.chatArchiver != nil {
|
|
if err := r.chatArchiver.ArchiveListingConversation(tx, listing.ID, req.Reason); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
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_seal", "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(ctx, refund)
|
|
return nil
|
|
}
|
|
|
|
func isTerminalStatus(status string) bool {
|
|
return status == orderStatusCompleted || status == orderStatusCancelled || status == orderStatusClosed
|
|
}
|