diff --git a/backend/internal/modules/order/admin_actions.go b/backend/internal/modules/order/admin_actions.go index b1b8940..5602190 100644 --- a/backend/internal/modules/order/admin_actions.go +++ b/backend/internal/modules/order/admin_actions.go @@ -26,16 +26,16 @@ func (r *Repository) AdminClose(adminID uint64, orderID uint64, req AdminActionR beforeListingStatus := listing.Status beforeAccountStatus := account.Status now := time.Now() - order.Status = "closed" - order.HandoffStatus = "admin_closed" - order.SettlementStatus = "closed" + order.Status = orderStatusClosed + order.HandoffStatus = handoffStatusAdminClosed + order.SettlementStatus = settlementStatusClosed order.SettledAt = &now - listing.Status = "offline" + listing.Status = listingStatusOffline listing.InTransaction = false - account.Status = "offline" - if beforeOrderStatus != "pending_payment" { + account.Status = accountStatusOffline + if beforeOrderStatus != orderStatusPendingPayment { totalCent := order.RentAmountCent + order.DepositAmountCent - action, err := r.prepareRefund(order, totalCent, "admin_close_refund", "客服关闭订单原路退款") + action, err := r.prepareRefund(order, totalCent, refundBizAdminClose, "客服关闭订单原路退款") if err != nil { return err } @@ -108,11 +108,11 @@ func (r *Repository) AdminMarkAbnormal(adminID uint64, orderID uint64, req Admin beforeHandoffStatus := order.HandoffStatus beforeListingStatus := listing.Status beforeAccountStatus := account.Status - order.Status = "abnormal" - order.HandoffStatus = "admin_abnormal" - listing.Status = "abnormal" + order.Status = orderStatusAbnormal + order.HandoffStatus = handoffStatusAdminAbnormal + listing.Status = listingStatusAbnormal listing.InTransaction = false - account.Status = "abnormal" + account.Status = accountStatusAbnormal if err := notification.Append(tx, notification.Entry{ UserID: order.RenterID, @@ -166,7 +166,7 @@ func (r *Repository) AdminRefund(orderID uint64) (*RefundStatusDTO, error) { if err := r.db.First(&order, orderID).Error; err != nil { return nil, err } - if order.RefundStatus == "refunded" { + if order.RefundStatus == refundStatusRefunded { return r.buildRefundStatusDTO(&order), nil } if r.refundFunc == nil { @@ -176,7 +176,7 @@ func (r *Repository) AdminRefund(orderID uint64) (*RefundStatusDTO, error) { if totalCent <= 0 { return nil, ErrInvalidCheckoutAmount } - status, err := r.refundFunc(orderID, totalCent, "admin_refund", "后台人工退款") + status, err := r.refundFunc(orderID, totalCent, refundBizAdmin, "后台人工退款") if err != nil { return nil, err } @@ -228,5 +228,5 @@ func (r *Repository) findOrderAssetsForAdminUpdate(tx *gorm.DB, orderID uint64) } func isTerminalStatus(status string) bool { - return status == "completed" || status == "cancelled" || status == "closed" + return status == orderStatusCompleted || status == orderStatusCancelled || status == orderStatusClosed } diff --git a/backend/internal/modules/order/checkout.go b/backend/internal/modules/order/checkout.go index 00c32cc..65c5fae 100644 --- a/backend/internal/modules/order/checkout.go +++ b/backend/internal/modules/order/checkout.go @@ -21,7 +21,7 @@ func (r *Repository) SubmitCheckout(userID uint64, orderID uint64, req SubmitChe if order.RenterID != userID { return ErrPermissionDenied } - if (order.Status != "renting" && order.Status != "overdue") || (order.HandoffStatus != "received" && order.HandoffStatus != "return_overdue") { + if (order.Status != orderStatusRenting && order.Status != orderStatusOverdue) || (order.HandoffStatus != handoffStatusReceived && order.HandoffStatus != handoffStatusReturnOverdue) { return ErrCheckoutCannotSubmit } hasOpen, err := hasOpenCheckout(tx, order.ID) @@ -41,16 +41,16 @@ func (r *Repository) SubmitCheckout(userID uint64, orderID uint64, req SubmitChe if err := tx.Create(&record).Error; err != nil { return err } - checkout, err := buildCheckout(order, order.RenterID, "submitted", req.Content, req.EvidenceURLS, req.ConsumableAmountCent, req.CoinConsumedM, req.OtherAmountCent, 0, false) + checkout, err := buildCheckout(order, order.RenterID, checkoutStatusSubmitted, req.Content, req.EvidenceURLS, req.ConsumableAmountCent, req.CoinConsumedM, req.OtherAmountCent, 0, false) if err != nil { return err } if err := tx.Create(&checkout).Error; err != nil { return err } - order.Status = "pending_checkout_confirm" - order.HandoffStatus = "pending_owner_checkout" - order.SettlementStatus = "pending" + order.Status = orderStatusPendingCheckoutConfirm + order.HandoffStatus = handoffStatusPendingOwnerCheckout + order.SettlementStatus = settlementStatusPending orderID := order.ID if err := notification.Append(tx, notification.Entry{ UserID: order.OwnerID, @@ -88,12 +88,12 @@ func (r *Repository) ConfirmCheckout(userID uint64, orderID uint64) error { if order.OwnerID != userID { return ErrPermissionDenied } - if order.Status != "pending_checkout_confirm" || order.HandoffStatus != "pending_owner_checkout" { + if order.Status != orderStatusPendingCheckoutConfirm || order.HandoffStatus != handoffStatusPendingOwnerCheckout { return ErrCheckoutCannotConfirm } var checkout model.OrderCheckout if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}). - Where("order_id = ? AND status = ?", order.ID, "submitted"). + Where("order_id = ? AND status = ?", order.ID, checkoutStatusSubmitted). Order("id DESC"). First(&checkout).Error; err != nil { return err @@ -104,7 +104,7 @@ func (r *Repository) ConfirmCheckout(userID uint64, orderID uint64) error { Update("confirmed_by_owner_at", now).Error; err != nil { return err } - checkout.Status = "accepted" + checkout.Status = checkoutStatusAccepted checkout.OwnerAdjustedAt = &now action, err := r.finalizeCheckout(tx, &order, &checkout, "号主已确认结账,订单完成。") refund = action @@ -127,22 +127,22 @@ func (r *Repository) CounterCheckout(userID uint64, orderID uint64, req CounterC if order.OwnerID != userID { return ErrPermissionDenied } - if order.Status != "pending_checkout_confirm" || order.HandoffStatus != "pending_owner_checkout" { + if order.Status != orderStatusPendingCheckoutConfirm || order.HandoffStatus != handoffStatusPendingOwnerCheckout { return ErrCheckoutCannotCounter } var checkout model.OrderCheckout if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}). - Where("order_id = ? AND status = ?", order.ID, "submitted"). + Where("order_id = ? AND status = ?", order.ID, checkoutStatusSubmitted). Order("id DESC"). First(&checkout).Error; err != nil { return err } - next, err := buildCheckout(order, checkout.InitiatedBy, "countered", checkout.Content, req.EvidenceURLS, req.ConsumableAmountCent, req.CoinConsumedM, req.OtherAmountCent, req.DepositDeductAmountCent, true) + next, err := buildCheckout(order, checkout.InitiatedBy, checkoutStatusCountered, checkout.Content, req.EvidenceURLS, req.ConsumableAmountCent, req.CoinConsumedM, req.OtherAmountCent, req.DepositDeductAmountCent, true) if err != nil { return err } now := time.Now() - checkout.Status = "countered" + checkout.Status = checkoutStatusCountered checkout.RentAmountCent = next.RentAmountCent checkout.OwnerRentAmountCent = next.OwnerRentAmountCent checkout.PlatformFeeCent = next.PlatformFeeCent @@ -156,9 +156,9 @@ func (r *Repository) CounterCheckout(userID uint64, orderID uint64, req CounterC checkout.OwnerAdjustmentReason = req.Reason checkout.OwnerAdjustedAt = &now checkout.EvidenceURLS = next.EvidenceURLS - order.Status = "pending_checkout_accept" - order.HandoffStatus = "pending_renter_checkout" - order.SettlementStatus = "pending" + order.Status = orderStatusPendingCheckoutAccept + order.HandoffStatus = handoffStatusPendingRenterCheckout + order.SettlementStatus = settlementStatusPending orderID := order.ID if err := notification.Append(tx, notification.Entry{ UserID: order.RenterID, @@ -205,18 +205,18 @@ func (r *Repository) AcceptCheckout(userID uint64, orderID uint64) error { if order.RenterID != userID { return ErrPermissionDenied } - if order.Status != "pending_checkout_accept" || order.HandoffStatus != "pending_renter_checkout" { + if order.Status != orderStatusPendingCheckoutAccept || order.HandoffStatus != handoffStatusPendingRenterCheckout { return ErrCheckoutCannotConfirm } var checkout model.OrderCheckout if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}). - Where("order_id = ? AND status = ?", order.ID, "countered"). + Where("order_id = ? AND status = ?", order.ID, checkoutStatusCountered). Order("id DESC"). First(&checkout).Error; err != nil { return err } now := time.Now() - checkout.Status = "accepted" + checkout.Status = checkoutStatusAccepted checkout.RenterConfirmedAt = &now action, err := r.finalizeCheckout(tx, &order, &checkout, "租客已确认修正结账,订单完成。") refund = action @@ -239,9 +239,9 @@ func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, che return nil, err } now := time.Now() - order.Status = "completed" - order.HandoffStatus = "returned" - order.SettlementStatus = "settled" + order.Status = orderStatusCompleted + order.HandoffStatus = handoffStatusReturned + order.SettlementStatus = settlementStatusSettled order.SettledAt = &now order.OwnerSettledAt = &now archiveListingAfterCheckout(&listing, &account) @@ -257,7 +257,7 @@ func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, che Direction: "in", AmountCent: settlement.OwnerRentIncomeCent, BalanceType: "available", - BizType: "owner_income", + BizType: walletBizOwnerIncome, BizNo: order.OrderNo, Remark: "订单结账租金收入", }) @@ -269,7 +269,7 @@ func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, che Direction: "in", AmountCent: settlement.DepositCompensationCent, BalanceType: "available", - BizType: "deposit_compensation", + BizType: walletBizDepositCompensation, BizNo: order.OrderNo, Remark: "订单结账押金赔付", }) @@ -283,7 +283,7 @@ func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, che var refund *refundAction renterRefundTotalCent := settlement.RentRefundCent + settlement.DepositRefundCent if renterRefundTotalCent > 0 { - action, err := r.prepareRefund(order, renterRefundTotalCent, "checkout_refund", "结账退款原路退还") + action, err := r.prepareRefund(order, renterRefundTotalCent, refundBizCheckout, "结账退款原路退还") if err != nil { return nil, err } @@ -332,16 +332,16 @@ func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, che // 完成后的账号先下架,避免已完成订单对应的账号重新出现在公开首页。 func archiveListingAfterCheckout(listing *model.RentalListing, account *model.GameAccount) { - listing.Status = "offline" + listing.Status = listingStatusOffline listing.InTransaction = false listing.PublishedAt = nil - account.Status = "offline" + account.Status = accountStatusOffline } func hasOpenCheckout(tx *gorm.DB, orderID uint64) (bool, error) { var count int64 err := tx.Model(&model.OrderCheckout{}). - Where("order_id = ? AND status IN ?", orderID, []string{"submitted", "countered", "accepted", "disputed"}). + Where("order_id = ? AND status IN ?", orderID, []string{checkoutStatusSubmitted, checkoutStatusCountered, checkoutStatusAccepted, checkoutStatusDisputed}). Count(&count).Error return count > 0, err } diff --git a/backend/internal/modules/order/constants.go b/backend/internal/modules/order/constants.go new file mode 100644 index 0000000..bffce7a --- /dev/null +++ b/backend/internal/modules/order/constants.go @@ -0,0 +1,60 @@ +package order + +const ( + orderStatusPendingPayment = "pending_payment" + orderStatusPendingHandoff = "pending_handoff" + orderStatusRenting = "renting" + orderStatusOverdue = "overdue" + orderStatusPendingCheckoutConfirm = "pending_checkout_confirm" + orderStatusPendingCheckoutAccept = "pending_checkout_accept" + orderStatusCheckoutDisputing = "checkout_disputing" + orderStatusCompleted = "completed" + orderStatusCancelled = "cancelled" + orderStatusClosed = "closed" + orderStatusAbnormal = "abnormal" + + handoffStatusNone = "none" + handoffStatusPendingOwner = "pending_owner" + handoffStatusPendingRenterConfirm = "pending_renter_confirm" + handoffStatusReceived = "received" + handoffStatusReturnOverdue = "return_overdue" + handoffStatusPendingOwnerCheckout = "pending_owner_checkout" + handoffStatusPendingRenterCheckout = "pending_renter_checkout" + handoffStatusReturned = "returned" + handoffStatusCancelled = "cancelled" + handoffStatusAdminClosed = "admin_closed" + handoffStatusAdminAbnormal = "admin_abnormal" + + settlementStatusUnsettled = "unsettled" + settlementStatusPending = "pending" + settlementStatusSettled = "settled" + settlementStatusClosed = "closed" + + checkoutStatusSubmitted = "submitted" + checkoutStatusCountered = "countered" + checkoutStatusAccepted = "accepted" + checkoutStatusDisputed = "disputed" + + refundStatusPending = "pending" + refundStatusRefunded = "refunded" + + listingReviewStatusApproved = "approved" + + listingStatusPublished = "published" + listingStatusRented = "rented" + listingStatusOffline = "offline" + listingStatusAbnormal = "abnormal" + + accountStatusPublished = "published" + accountStatusRented = "rented" + accountStatusOffline = "offline" + accountStatusAbnormal = "abnormal" + + walletBizOwnerIncome = "owner_income" + walletBizDepositCompensation = "deposit_compensation" + + refundBizCancel = "cancel_refund" + refundBizAdminClose = "admin_close_refund" + refundBizAdmin = "admin_refund" + refundBizCheckout = "checkout_refund" +) diff --git a/backend/internal/modules/order/handoff.go b/backend/internal/modules/order/handoff.go index c4f935e..740e95d 100644 --- a/backend/internal/modules/order/handoff.go +++ b/backend/internal/modules/order/handoff.go @@ -18,7 +18,7 @@ func (r *Repository) SubmitHandoff(userID uint64, orderID uint64, req SubmitHand if order.OwnerID != userID { return ErrPermissionDenied } - if order.Status != "pending_handoff" || order.HandoffStatus != "pending_owner" { + if order.Status != orderStatusPendingHandoff || order.HandoffStatus != handoffStatusPendingOwner { return ErrOrderCannotHandoff } record := model.HandoffRecord{ @@ -31,7 +31,7 @@ func (r *Repository) SubmitHandoff(userID uint64, orderID uint64, req SubmitHand if err := tx.Create(&record).Error; err != nil { return err } - order.HandoffStatus = "pending_renter_confirm" + order.HandoffStatus = handoffStatusPendingRenterConfirm orderID := order.ID if err := notification.Append(tx, notification.Entry{ UserID: order.RenterID, diff --git a/backend/internal/modules/order/lifecycle.go b/backend/internal/modules/order/lifecycle.go index 07e81fe..21c4184 100644 --- a/backend/internal/modules/order/lifecycle.go +++ b/backend/internal/modules/order/lifecycle.go @@ -18,7 +18,7 @@ func (r *Repository) Create(renterID uint64, req CreateRequest) (*OrderDTO, erro if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&listing, req.ListingID).Error; err != nil { return err } - if listing.Status != "published" || listing.ReviewStatus != "approved" || listing.InTransaction { + if listing.Status != listingStatusPublished || listing.ReviewStatus != listingReviewStatusApproved || listing.InTransaction { return ErrListingUnavailable } if listing.OwnerID == renterID { @@ -58,9 +58,9 @@ func (r *Repository) Create(renterID uint64, req CreateRequest) (*OrderDTO, erro DepositWaivedAmountCent: waivedDepositAmountCent, PlatformFeeCent: pricing.PlatformFeeCent, AccountSnapshot: snapshot, - Status: "pending_payment", - HandoffStatus: "none", - SettlementStatus: "unsettled", + Status: orderStatusPendingPayment, + HandoffStatus: handoffStatusNone, + SettlementStatus: settlementStatusUnsettled, } if err := tx.Create(&order).Error; err != nil { return err @@ -112,7 +112,7 @@ func activeDepositFreeUsed(tx *gorm.DB, renterID uint64) (int64, error) { err := tx.Model(&model.RentalOrder{}). Where("renter_id = ? AND status NOT IN ?", renterID, - []string{"completed", "cancelled", "closed"}, + []string{orderStatusCompleted, orderStatusCancelled, orderStatusClosed}, ). Select("COALESCE(SUM(deposit_waived_amount_cent), 0)"). Scan(&used).Error @@ -139,10 +139,10 @@ func (r *Repository) ConfirmPaidFromChannel(orderID uint64, providerBizNo string if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&order, orderID).Error; err != nil { return err } - if order.Status == "pending_handoff" || order.Status == "renting" { + if order.Status == orderStatusPendingHandoff || order.Status == orderStatusRenting { return nil } - if order.Status != "pending_payment" { + if order.Status != orderStatusPendingPayment { return ErrOrderCannotPay } @@ -150,7 +150,7 @@ func (r *Repository) ConfirmPaidFromChannel(orderID uint64, providerBizNo string if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&listing, order.ListingID).Error; err != nil { return err } - if listing.Status != "published" || listing.ReviewStatus != "approved" || !listing.InTransaction { + if listing.Status != listingStatusPublished || listing.ReviewStatus != listingReviewStatusApproved || !listing.InTransaction { return ErrListingUnavailable } var account model.GameAccount @@ -160,10 +160,10 @@ func (r *Repository) ConfirmPaidFromChannel(orderID uint64, providerBizNo string // 租客已通过外部渠道付款,这里不写租客钱包流水。 orderID := order.ID - order.Status = "pending_handoff" - order.HandoffStatus = "pending_owner" - listing.Status = "rented" - account.Status = "rented" + order.Status = orderStatusPendingHandoff + order.HandoffStatus = handoffStatusPendingOwner + listing.Status = listingStatusRented + account.Status = accountStatusRented conv, err := chat.EnsureOrderConversation(tx, order) if err != nil { return err @@ -215,7 +215,7 @@ func (r *Repository) Cancel(userID uint64, orderID uint64) error { First(&order).Error; err != nil { return err } - if order.Status != "pending_payment" && order.Status != "pending_handoff" { + if order.Status != orderStatusPendingPayment && order.Status != orderStatusPendingHandoff { return ErrOrderCannotCancel } var listing model.RentalListing @@ -228,12 +228,12 @@ func (r *Repository) Cancel(userID uint64, orderID uint64) error { } beforeStatus := order.Status - order.Status = "cancelled" - order.HandoffStatus = "cancelled" + order.Status = orderStatusCancelled + order.HandoffStatus = handoffStatusCancelled orderID := order.ID - if beforeStatus == "pending_handoff" { + if beforeStatus == orderStatusPendingHandoff { totalCent := order.RentAmountCent + order.DepositAmountCent - action, err := r.prepareRefund(&order, totalCent, "cancel_refund", "取消订单原路退款") + action, err := r.prepareRefund(&order, totalCent, refundBizCancel, "取消订单原路退款") if err != nil { return err } @@ -259,9 +259,9 @@ func (r *Repository) Cancel(userID uint64, orderID uint64) error { ); err != nil { return err } - listing.Status = "published" + listing.Status = listingStatusPublished listing.InTransaction = false - account.Status = "published" + account.Status = accountStatusPublished if err := tx.Save(&order).Error; err != nil { return err } @@ -286,7 +286,7 @@ func (r *Repository) ConfirmReceive(userID uint64, orderID uint64) error { if order.RenterID != userID { return ErrPermissionDenied } - if order.Status != "pending_handoff" || order.HandoffStatus != "pending_renter_confirm" { + if order.Status != orderStatusPendingHandoff || order.HandoffStatus != handoffStatusPendingRenterConfirm { return ErrOrderCannotReceive } now := time.Now() @@ -295,8 +295,8 @@ func (r *Repository) ConfirmReceive(userID uint64, orderID uint64) error { Update("confirmed_by_renter_at", now).Error; err != nil { return err } - order.Status = "renting" - order.HandoffStatus = "received" + order.Status = orderStatusRenting + order.HandoffStatus = handoffStatusReceived durationHours := orderDurationHours(order) order.EstimatedDurationHours = durationHours order.RentedAt = &now diff --git a/backend/internal/modules/order/queries.go b/backend/internal/modules/order/queries.go index fa47d49..91e1494 100644 --- a/backend/internal/modules/order/queries.go +++ b/backend/internal/modules/order/queries.go @@ -102,7 +102,7 @@ func pendingPaymentTimeoutMinutes(tx *gorm.DB) int { } func applyPaymentDeadline(dto *OrderDTO, order model.RentalOrder, timeoutMinutes int) { - if dto == nil || order.Status != "pending_payment" || timeoutMinutes <= 0 { + if dto == nil || order.Status != orderStatusPendingPayment || timeoutMinutes <= 0 { return } deadline := order.CreatedAt.Add(time.Duration(timeoutMinutes) * time.Minute) @@ -120,7 +120,7 @@ func (r *Repository) latestCheckoutAdminDTO(orderID uint64) *CheckoutDTO { func shouldAttachCheckout(status string) bool { switch status { - case "pending_checkout_confirm", "pending_checkout_accept", "checkout_disputing", "completed": + case orderStatusPendingCheckoutConfirm, orderStatusPendingCheckoutAccept, orderStatusCheckoutDisputing, orderStatusCompleted: return true default: return false diff --git a/backend/internal/modules/order/refund.go b/backend/internal/modules/order/refund.go index 5e4c2e0..9537476 100644 --- a/backend/internal/modules/order/refund.go +++ b/backend/internal/modules/order/refund.go @@ -13,7 +13,7 @@ func (r *Repository) prepareRefund(order *model.RentalOrder, amountCent int64, b if r.refundFunc == nil { return nil, ErrDependencyUnavailable } - order.RefundStatus = "pending" + order.RefundStatus = refundStatusPending order.RefundAmountCent = amountCent order.RefundedAt = nil return &refundAction{