feat(aftersale): per-line refund/return flow with ledger-backed completion (add-aftersale-refunds)

This commit is contained in:
Chengdong Zhang
2026-09-23 16:56:30 +08:00
parent 93e5a05d48
commit 2c2b54c21c
43 changed files with 4889 additions and 32 deletions
+32
View File
@@ -173,6 +173,8 @@ pub struct Order {
pub total_minor: i64,
/// Realized coupon discount, converted to the order currency server-side.
pub discount_minor: i64,
/// Authoritative sum of completed after-sale refunds.
pub refund_total_minor: i64,
/// The coupon this order redeemed, if any.
pub coupon_id: Option<Uuid>,
/// Group-buying activity this order joined, if any.
@@ -198,6 +200,36 @@ pub struct OrderItem {
pub flash_sale_item_id: Option<Uuid>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
#[sqlx(type_name = "aftersale_kind", rename_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum AftersaleKind {
RefundOnly,
ReturnRefund,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
#[sqlx(type_name = "aftersale_status", rename_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum AftersaleStatus {
Pending,
Approved,
Rejected,
BuyerShipping,
MerchantConfirmed,
Refunded,
Cancelled,
}
impl AftersaleStatus {
pub fn is_terminal(self) -> bool {
matches!(
self,
AftersaleStatus::Refunded | AftersaleStatus::Rejected | AftersaleStatus::Cancelled
)
}
}
#[derive(Debug, Clone, Serialize, sqlx::FromRow)]
pub struct Shipment {
pub id: Uuid,