feat(v2): RefundStore(建单/求和/条件翻转/人工待办)+ Order 退款态机(PaidAttempt/ApplyRefundToOrder)
This commit is contained in:
@@ -62,3 +62,35 @@ func (s *OrderStore) ExpirePendingAttempts(outTradeNo string) (int64, error) {
|
||||
}
|
||||
return res.RowsAffected, nil
|
||||
}
|
||||
|
||||
// PaidAttempt returns the settled (paid) attempt of an order — the payment a
|
||||
// refund reverses (channel + provider_ref for the original transaction).
|
||||
func (s *OrderStore) PaidAttempt(outTradeNo string) (*model.Attempt, error) {
|
||||
var a model.Attempt
|
||||
err := s.db.Where("out_trade_no = ? AND status = ?", outTradeNo, model.AttemptPaid).First(&a).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrAttemptNotFound
|
||||
}
|
||||
return nil, fmt.Errorf("store.PaidAttempt: %w", err)
|
||||
}
|
||||
return &a, nil
|
||||
}
|
||||
|
||||
// ApplyRefundToOrder advances a settled order's status per cumulative refunds:
|
||||
// fully refunded → refunded, else → partially_refunded. Guard: only from a
|
||||
// post-paid, non-fully-refunded state (paid / partially_refunded / refunding).
|
||||
func (s *OrderStore) ApplyRefundToOrder(outTradeNo string, fully bool) (bool, error) {
|
||||
next := model.OrderPartRefundedV2
|
||||
if fully {
|
||||
next = model.OrderRefundedV2
|
||||
}
|
||||
res := s.db.Model(&model.OrderV2{}).
|
||||
Where("out_trade_no = ? AND status IN ?", outTradeNo,
|
||||
[]model.OrderStatusV2{model.OrderPaidV2, model.OrderPartRefundedV2, model.OrderRefundingV2}).
|
||||
Update("status", next)
|
||||
if res.Error != nil {
|
||||
return false, fmt.Errorf("store.ApplyRefundToOrder: %w", res.Error)
|
||||
}
|
||||
return res.RowsAffected > 0, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user