forked from xiongyuxing/tiku-backend.net
feat: add commerce refunds and reconciliation persistence
This commit is contained in:
@@ -55,6 +55,7 @@ public sealed class Order : AuditableTenantEntity
|
||||
public string? PayProvider { get; set; }
|
||||
public string? TradeNo { get; set; }
|
||||
public int? Days { get; set; }
|
||||
public int RefundedAmountCents { get; set; }
|
||||
public DateTimeOffset? PaidAt { get; set; }
|
||||
public JsonElement RawPayload { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
@@ -81,6 +82,7 @@ public sealed class Payment : AuditableTenantEntity
|
||||
public string? Method { get; set; }
|
||||
public PaymentStatus Status { get; set; } = PaymentStatus.Pending;
|
||||
public int AmountCents { get; set; }
|
||||
public int RefundedAmountCents { get; set; }
|
||||
public string? ProviderTradeNo { get; set; }
|
||||
public DateTimeOffset? PaidAt { get; set; }
|
||||
public JsonElement RawPayload { get; set; } = JsonDefaults.Object();
|
||||
@@ -113,6 +115,9 @@ public sealed class Entitlement : Entity
|
||||
public DateTimeOffset StartsAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public DateTimeOffset? ExpiresAt { get; set; }
|
||||
public EntitlementStatus Status { get; set; } = EntitlementStatus.Active;
|
||||
public DateTimeOffset? RevokedAt { get; set; }
|
||||
public Guid? RevokedBy { get; set; }
|
||||
public string? RevokedReason { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
@@ -218,9 +223,142 @@ public sealed class TenantUsageRecord : Entity
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class CommerceRefundRequest : AuditableTenantEntity
|
||||
{
|
||||
public Guid OrderId { get; set; }
|
||||
public Guid? PaymentId { get; set; }
|
||||
public Guid? RequestedBy { get; set; }
|
||||
public Guid? ReviewedBy { get; set; }
|
||||
public Guid? ProcessedBy { get; set; }
|
||||
public string RefundNo { get; set; } = string.Empty;
|
||||
public string? Provider { get; set; }
|
||||
public string? ProviderRefundNo { get; set; }
|
||||
public CommerceRefundStatus Status { get; set; } = CommerceRefundStatus.Requested;
|
||||
public int AmountCents { get; set; }
|
||||
public string? Reason { get; set; }
|
||||
public RefundEntitlementAction EntitlementAction { get; set; } = RefundEntitlementAction.RevokeOnSuccess;
|
||||
public DateTimeOffset RequestedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public DateTimeOffset? ReviewedAt { get; set; }
|
||||
public DateTimeOffset? ProcessedAt { get; set; }
|
||||
public DateTimeOffset? SucceededAt { get; set; }
|
||||
public DateTimeOffset? FailedAt { get; set; }
|
||||
public DateTimeOffset? CancelledAt { get; set; }
|
||||
public string? FailureReason { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class CommerceRefundEvent : Entity
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
public Guid RefundRequestId { get; set; }
|
||||
public CommerceRefundStatus? FromStatus { get; set; }
|
||||
public CommerceRefundStatus ToStatus { get; set; } = CommerceRefundStatus.Requested;
|
||||
public string EventType { get; set; } = string.Empty;
|
||||
public Guid? ActorUserId { get; set; }
|
||||
public JsonElement Details { get; set; } = JsonDefaults.Object();
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class CommerceReconciliationBatch : AuditableTenantEntity
|
||||
{
|
||||
public Guid? CreatedBy { get; set; }
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
public DateOnly BillDate { get; set; }
|
||||
public ReconciliationBillType BillType { get; set; } = ReconciliationBillType.Combined;
|
||||
public ReconciliationSource Source { get; set; } = ReconciliationSource.ManualUpload;
|
||||
public string? SourceName { get; set; }
|
||||
public string SourceHash { get; set; } = string.Empty;
|
||||
public ReconciliationBatchStatus Status { get; set; } = ReconciliationBatchStatus.Completed;
|
||||
public int TotalCount { get; set; }
|
||||
public int MatchedCount { get; set; }
|
||||
public int MismatchCount { get; set; }
|
||||
public int MissingLocalCount { get; set; }
|
||||
public int MissingProviderCount { get; set; }
|
||||
public int DuplicateCount { get; set; }
|
||||
public int IgnoredCount { get; set; }
|
||||
public int AmountCents { get; set; }
|
||||
public int RefundAmountCents { get; set; }
|
||||
public int FeeCents { get; set; }
|
||||
public DateTimeOffset? CompletedAt { get; set; }
|
||||
public string? Error { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class CommerceReconciliationItem : Entity
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
public Guid BatchId { get; set; }
|
||||
public Guid? OrderId { get; set; }
|
||||
public Guid? PaymentId { get; set; }
|
||||
public Guid? RefundRequestId { get; set; }
|
||||
public int RowNo { get; set; }
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
public ReconciliationTransactionType TransactionType { get; set; } = ReconciliationTransactionType.Payment;
|
||||
public string? ProviderTradeNo { get; set; }
|
||||
public string? ProviderRefundNo { get; set; }
|
||||
public string? OrderNo { get; set; }
|
||||
public string? RefundNo { get; set; }
|
||||
public int AmountCents { get; set; }
|
||||
public int RefundAmountCents { get; set; }
|
||||
public int FeeCents { get; set; }
|
||||
public DateTimeOffset? PaidAt { get; set; }
|
||||
public DateTimeOffset? RefundedAt { get; set; }
|
||||
public string? ProviderStatus { get; set; }
|
||||
public string? LocalStatus { get; set; }
|
||||
public ReconciliationMatchStatus MatchStatus { get; set; } = ReconciliationMatchStatus.Matched;
|
||||
public NotificationSeverity Severity { get; set; } = NotificationSeverity.Info;
|
||||
public string? IssueCode { get; set; }
|
||||
public JsonElement Details { get; set; } = JsonDefaults.Object();
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class CommerceReconciliationIssue : AuditableTenantEntity
|
||||
{
|
||||
public Guid? BatchId { get; set; }
|
||||
public Guid? ItemId { get; set; }
|
||||
public Guid? OrderId { get; set; }
|
||||
public Guid? PaymentId { get; set; }
|
||||
public Guid? RefundRequestId { get; set; }
|
||||
public Guid? AssignedTo { get; set; }
|
||||
public Guid? CreatedBy { get; set; }
|
||||
public Guid? ResolvedBy { get; set; }
|
||||
public string IssueNo { get; set; } = string.Empty;
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
public ReconciliationTransactionType TransactionType { get; set; } = ReconciliationTransactionType.Payment;
|
||||
public string? IssueCode { get; set; }
|
||||
public ReconciliationIssueMatchStatus MatchStatus { get; set; } = ReconciliationIssueMatchStatus.AmountMismatch;
|
||||
public NotificationSeverity Severity { get; set; } = NotificationSeverity.Warning;
|
||||
public ReconciliationIssueStatus Status { get; set; } = ReconciliationIssueStatus.Open;
|
||||
public ReconciliationResolutionType ResolutionType { get; set; } = ReconciliationResolutionType.None;
|
||||
public string? OrderNo { get; set; }
|
||||
public string? RefundNo { get; set; }
|
||||
public string? ProviderTradeNo { get; set; }
|
||||
public string? ProviderRefundNo { get; set; }
|
||||
public int AmountCents { get; set; }
|
||||
public int RefundAmountCents { get; set; }
|
||||
public DateTimeOffset? ResolvedAt { get; set; }
|
||||
public DateTimeOffset? DueAt { get; set; }
|
||||
public string? Summary { get; set; }
|
||||
public string? ResolutionNote { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class CommerceReconciliationIssueEvent : Entity
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
public Guid IssueId { get; set; }
|
||||
public ReconciliationIssueStatus? FromStatus { get; set; }
|
||||
public ReconciliationIssueStatus? ToStatus { get; set; }
|
||||
public string EventType { get; set; } = string.Empty;
|
||||
public Guid? ActorUserId { get; set; }
|
||||
public string? Note { get; set; }
|
||||
public JsonElement Details { get; set; } = JsonDefaults.Object();
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public enum ProductType { Material, Course, Service, Link, Other }
|
||||
public enum OrderStatus { Pending, Paid, Failed, Closed, Refunded }
|
||||
public enum PaymentStatus { Pending, Paid, Failed, Cancelled, Refunded }
|
||||
public enum OrderStatus { Pending, Paid, Failed, Closed, PartiallyRefunded, Refunded }
|
||||
public enum PaymentStatus { Pending, Paid, Failed, Cancelled, PartiallyRefunded, Refunded }
|
||||
public enum EntitlementScopeType { Tenant, Region, Module, Subject, QuestionBank }
|
||||
public enum EntitlementStatus { Active, Revoked, Expired }
|
||||
public enum DiscountType { Percent, Fixed }
|
||||
@@ -228,3 +366,14 @@ public enum CouponRedemptionStatus { Claimed, Used, Expired, Cancelled }
|
||||
public enum TenantPaymentMode { PlatformCollect, TenantCollect, ServiceProvider }
|
||||
public enum TenantPaymentAccountStatus { Active, Disabled, Pending }
|
||||
public enum TenantSubscriptionStatus { Trial, Active, PastDue, Cancelled }
|
||||
public enum CommerceRefundStatus { Requested, Approved, Processing, Succeeded, Failed, Rejected, Cancelled }
|
||||
public enum RefundEntitlementAction { None, RevokeOnSuccess }
|
||||
public enum ReconciliationBillType { Payment, Refund, Combined }
|
||||
public enum ReconciliationSource { ManualUpload, ProviderDownload, Api, Worker }
|
||||
public enum ReconciliationBatchStatus { Preview, Pending, Processing, Completed, CompletedWithIssues, Failed }
|
||||
public enum ReconciliationTransactionType { Payment, Refund }
|
||||
public enum ReconciliationMatchStatus { Matched, AmountMismatch, StatusMismatch, MissingLocal, MissingProvider, Duplicate, Ignored }
|
||||
public enum ReconciliationIssueMatchStatus { AmountMismatch, StatusMismatch, MissingLocal, MissingProvider, Duplicate }
|
||||
public enum NotificationSeverity { Info, Warning, Error, Critical }
|
||||
public enum ReconciliationIssueStatus { Open, Investigating, Resolved, Ignored, Escalated }
|
||||
public enum ReconciliationResolutionType { None, ProviderConfirmed, LocalCorrected, ManualAdjustment, FalsePositive, Duplicate, WriteOff }
|
||||
|
||||
Reference in New Issue
Block a user