using System.Text.Json; namespace Tiku.Application.Commerce; public sealed record CommerceActor(Guid TenantId, Guid UserId); public sealed record CreateCommerceOrderCommand( Guid PlanId, int Quantity, string? PayMethod, string? PayProvider, Guid? RegionId, string? CouponCode, Guid? CouponRedemptionId); public sealed record CommerceOrderQuery(int? Limit = null, string? Status = null); public sealed record CreateCommercePaymentCommand( string OrderNo, string Provider, string Method, string? OpenId, string? ReturnUrl, string? QuitUrl); public sealed record CommerceOrderItem( Guid Id, string OrderNo, string Status, Guid? PlanId, Guid? RegionId, string? ProductType, string? ProductName, int AmountCents, string Price, string? PayMethod, string? PayProvider, string? TradeNo, int? Days, DateTimeOffset? PaidAt, DateTimeOffset CreatedAt, JsonElement RawPayload); public sealed record CommerceOrderList(IReadOnlyCollection Items); public sealed record CommercePaymentItem( Guid Id, Guid OrderId, string OrderNo, string Provider, string? Method, string Status, int AmountCents, string Price, string? ProviderTradeNo, DateTimeOffset? PaidAt, JsonElement ClientPayload, JsonElement RawPayload); public sealed record CurrentEntitlementItem( bool IsActive, string EntitlementType, DateTimeOffset? StartsAt, DateTimeOffset? ExpiresAt, string Status, int? DaysLeft); public sealed record CommerceCouponQuery(int? Limit = null, string? Status = null); public sealed record ClaimCommerceCouponCommand(string CouponCode); public sealed record CheckCommerceCouponCommand(string? CouponCode, Guid? CouponRedemptionId, Guid PlanId, int Quantity, Guid? RegionId); public sealed record CommerceCouponItem( Guid Id, Guid? CouponId, string CouponCode, string Status, Guid? PlanId, Guid? RegionId, string? DiscountType, decimal? DiscountValue, int? DiscountPreviewCents, string? DiscountPreview, DateTimeOffset? ValidFrom, DateTimeOffset? ValidTo, DateTimeOffset? ClaimedAt, DateTimeOffset? UsedAt); public sealed record CommerceCouponList(IReadOnlyCollection Items); public sealed record CommerceCouponCheckResult( bool Valid, string? ReasonCode, Guid? CouponId, Guid? CouponRedemptionId, string? CouponCode, int OriginalAmountCents, int DiscountCents, int PayableAmountCents, string PayablePrice); public sealed record PaymentNotificationProcessResult( string Provider, string EventId, string OrderNo, string Status, bool Idempotent); public interface ICommerceService { Task CreateOrderAsync( CommerceActor actor, CreateCommerceOrderCommand command, CancellationToken cancellationToken = default); Task GetOrdersAsync( CommerceActor actor, CommerceOrderQuery query, CancellationToken cancellationToken = default); Task GetOrderAsync( CommerceActor actor, string orderNo, CancellationToken cancellationToken = default); Task CreatePaymentAsync( CommerceActor actor, CreateCommercePaymentCommand command, CancellationToken cancellationToken = default); Task GetCurrentEntitlementAsync( CommerceActor actor, CancellationToken cancellationToken = default); Task ClaimCouponAsync( CommerceActor actor, ClaimCommerceCouponCommand command, CancellationToken cancellationToken = default); Task GetCouponsAsync( CommerceActor actor, CommerceCouponQuery query, CancellationToken cancellationToken = default); Task CheckCouponAsync( CommerceActor actor, CheckCommerceCouponCommand command, CancellationToken cancellationToken = default); Task ProcessPaymentNotificationAsync( Guid tenantId, string provider, IReadOnlyDictionary headers, string rawBody, JsonElement body, CancellationToken cancellationToken = default); } public sealed class CommerceException(string message, string code) : Exception(message) { public string Code { get; } = code; }