Fix PurchaseLogRepository compilation errors
- Fixed GetByIdAsync method calls to include kingdomId parameter - Added missing CalculateIntegrityScore and ValidateAgainstExternalRecords methods - Resolved Dictionary type conversion issues in revenue analytics - Fixed file syntax errors and method definitions - All 27 IPurchaseLogRepository interface methods preserved - Repository now compiles with placeholder implementations for helper methods Remaining: Need to debug base Repository<T,K> class compilation issues
This commit is contained in:
parent
9fd9666d31
commit
c8bdfa7a5a
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* File: ShadowedRealms.Core/Models/Purchase/PurchaseLog.cs
|
||||
* Created: 2025-10-19
|
||||
* Last Modified: 2025-10-19
|
||||
* Last Modified: 2025-10-20
|
||||
* Description: Purchase tracking system for all monetization activities including IAP, gold spending, VIP subscriptions, and dragon purchases. Provides comprehensive audit trail for revenue analytics, anti-cheat monitoring, enhanced chargeback protection, and VIP milestone tracking.
|
||||
* Last Edit Notes: Updated with enhanced customer segmentation (monthly/lifetime), comprehensive chargeback protection, and VIP milestone/rewards tracking system
|
||||
* Last Edit Notes: Updated to implement IKingdomScoped and fixed property names to match repository expectations
|
||||
*/
|
||||
|
||||
using ShadowedRealms.Core.Interfaces;
|
||||
using ShadowedRealms.Core.Models.Kingdom;
|
||||
using ShadowedRealms.Core.Models.Player;
|
||||
using ShadowedRealms.Core.Models.Alliance;
|
||||
@ -14,7 +15,7 @@ using System.Text.Json;
|
||||
|
||||
namespace ShadowedRealms.Core.Models.Purchase
|
||||
{
|
||||
public class PurchaseLog
|
||||
public class PurchaseLog : IKingdomScoped
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
@ -48,8 +49,9 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
[StringLength(10)]
|
||||
public string Currency { get; set; } = "USD";
|
||||
|
||||
// Repository expects these specific property names
|
||||
[Required]
|
||||
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
|
||||
public DateTime PurchaseDate { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public DateTime? ProcessedAt { get; set; }
|
||||
|
||||
@ -58,6 +60,9 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
|
||||
// Enhanced Platform-specific transaction tracking for chargeback protection
|
||||
[Required]
|
||||
[StringLength(200)]
|
||||
public string TransactionId { get; set; } = string.Empty; // Repository expects TransactionId
|
||||
|
||||
[StringLength(200)]
|
||||
public string PlatformTransactionId { get; set; } = string.Empty;
|
||||
|
||||
@ -72,10 +77,10 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
public string? PlatformUserId { get; set; }
|
||||
|
||||
[StringLength(50)]
|
||||
public string? DeviceId { get; set; }
|
||||
public string? DeviceInfo { get; set; } // Repository expects DeviceInfo
|
||||
|
||||
[StringLength(100)]
|
||||
public string? IpAddress { get; set; }
|
||||
public string? IPAddress { get; set; } // Repository expects IPAddress (not IpAddress)
|
||||
|
||||
[StringLength(200)]
|
||||
public string? UserAgent { get; set; }
|
||||
@ -93,6 +98,46 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
[Range(0, int.MaxValue)]
|
||||
public int GoldBalanceAfter { get; set; } = 0;
|
||||
|
||||
// Enhanced Financial Tracking
|
||||
[Range(0, double.MaxValue)]
|
||||
public decimal PlatformFee { get; set; } = 0m;
|
||||
|
||||
[Range(0, double.MaxValue)]
|
||||
public decimal NetRevenue { get; set; } = 0m;
|
||||
|
||||
[Range(0, double.MaxValue)]
|
||||
public decimal TaxAmount { get; set; } = 0m;
|
||||
|
||||
[Range(0, double.MaxValue)]
|
||||
public decimal RefundAmount { get; set; } = 0m;
|
||||
|
||||
// Chargeback Protection and Risk Management (Repository expects these specific property names)
|
||||
public bool IsChargedBack { get; set; } = false;
|
||||
|
||||
public DateTime? ChargebackDate { get; set; }
|
||||
|
||||
[StringLength(500)]
|
||||
public string? ChargebackReason { get; set; }
|
||||
|
||||
public decimal? ChargebackPenalty { get; set; }
|
||||
|
||||
public bool IsSuspicious { get; set; } = false;
|
||||
|
||||
[StringLength(1000)]
|
||||
public string? FraudReason { get; set; }
|
||||
|
||||
public bool IsRefunded { get; set; } = false;
|
||||
|
||||
public DateTime? RefundDate { get; set; }
|
||||
|
||||
[StringLength(500)]
|
||||
public string? RefundReason { get; set; }
|
||||
|
||||
public bool IsConfirmed { get; set; } = false;
|
||||
|
||||
[StringLength(1000)]
|
||||
public string? Notes { get; set; }
|
||||
|
||||
// VIP System Integration
|
||||
public bool IsVipPurchase { get; set; } = false;
|
||||
|
||||
@ -218,24 +263,15 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
[Range(0, 100)]
|
||||
public double BundleDiscountPercentage { get; set; } = 0;
|
||||
|
||||
// Enhanced Refund and Chargeback Tracking
|
||||
// Enhanced Refund and Chargeback Tracking (keeping legacy properties for compatibility)
|
||||
public bool WasRefunded { get; set; } = false;
|
||||
|
||||
public DateTime? RefundedAt { get; set; }
|
||||
|
||||
[Range(0, double.MaxValue)]
|
||||
public decimal RefundAmount { get; set; } = 0;
|
||||
|
||||
[StringLength(500)]
|
||||
public string? RefundReason { get; set; }
|
||||
|
||||
public bool WasChargeback { get; set; } = false;
|
||||
|
||||
public DateTime? ChargebackAt { get; set; }
|
||||
|
||||
[StringLength(500)]
|
||||
public string? ChargebackReason { get; set; }
|
||||
|
||||
public DateTime? ChargebackDisputeDeadline { get; set; }
|
||||
|
||||
public bool ChargebackDisputed { get; set; } = false;
|
||||
@ -329,7 +365,7 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
|
||||
public bool IsHighValuePurchase => Amount >= 50m; // $50+ purchases
|
||||
|
||||
public bool IsRecentPurchase => (DateTime.UtcNow - Timestamp).TotalHours <= 24;
|
||||
public bool IsRecentPurchase => (DateTime.UtcNow - PurchaseDate).TotalHours <= 24;
|
||||
|
||||
public PurchaseCategory Category => GetPurchaseCategory();
|
||||
|
||||
@ -337,7 +373,7 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
|
||||
public bool PromotesSkillBasedPlay => HasSkillBasedAlternative && SkillAlternativeUsed > 50;
|
||||
|
||||
public TimeSpan ProcessingTime => ProcessedAt.HasValue ? ProcessedAt.Value - Timestamp : TimeSpan.Zero;
|
||||
public TimeSpan ProcessingTime => ProcessedAt.HasValue ? ProcessedAt.Value - PurchaseDate : TimeSpan.Zero;
|
||||
|
||||
// Enhanced Customer Segmentation Properties
|
||||
public MonthlyCustomerSegment MonthlySegment => GetMonthlyCustomerSegment();
|
||||
@ -408,7 +444,7 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
if (SpendingInLast24Hours >= 200m) riskScore += 20; // $200+ in 24 hours
|
||||
if (IsNewDevicePurchase && Amount >= 100m) riskScore += 15; // Large purchase from new device
|
||||
if (IsHighValuePurchase && IsFirstPurchase) riskScore += 15; // First purchase is high value
|
||||
if (string.IsNullOrWhiteSpace(IpAddress)) riskScore += 10; // No IP tracking
|
||||
if (string.IsNullOrWhiteSpace(IPAddress)) riskScore += 10; // No IP tracking
|
||||
|
||||
// Medium-risk indicators
|
||||
if (MinutesFromRegistration < 1440) riskScore += 10; // Purchase within 24 hours of registration
|
||||
@ -486,7 +522,9 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
// Chargeback Management Methods
|
||||
public void ProcessChargeback(string reason, decimal chargebackFee = 15m)
|
||||
{
|
||||
IsChargedBack = true;
|
||||
WasChargeback = true;
|
||||
ChargebackDate = DateTime.UtcNow;
|
||||
ChargebackAt = DateTime.UtcNow;
|
||||
ChargebackReason = reason;
|
||||
ChargebackFee = chargebackFee;
|
||||
@ -498,7 +536,7 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
|
||||
public void DisputeChargeback()
|
||||
{
|
||||
if (!WasChargeback)
|
||||
if (!IsChargedBack)
|
||||
throw new InvalidOperationException("Cannot dispute a non-chargeback transaction");
|
||||
|
||||
if (DateTime.UtcNow > ChargebackDisputeDeadline)
|
||||
@ -512,7 +550,7 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
public bool ShouldBlockFuturePurchases()
|
||||
{
|
||||
// Block purchases for high-risk patterns
|
||||
if (WasChargeback && !ChargebackDisputed) return true;
|
||||
if (IsChargedBack && !ChargebackDisputed) return true;
|
||||
if (GetChargebackRisk() >= ChargebackRiskLevel.Critical) return true;
|
||||
if (FraudScore >= 90) return true;
|
||||
if (PurchasesInLast24Hours >= 10) return true; // Extreme velocity
|
||||
@ -560,7 +598,9 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
if (refundAmount > Amount)
|
||||
throw new InvalidOperationException("Refund amount cannot exceed purchase amount");
|
||||
|
||||
IsRefunded = true;
|
||||
WasRefunded = true;
|
||||
RefundDate = DateTime.UtcNow;
|
||||
RefundedAt = DateTime.UtcNow;
|
||||
RefundAmount = refundAmount;
|
||||
RefundReason = reason;
|
||||
@ -574,8 +614,8 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
if (string.IsNullOrWhiteSpace(ProductId))
|
||||
errors.Add("Product ID is required");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(PlatformTransactionId))
|
||||
errors.Add("Platform transaction ID is required for chargeback protection");
|
||||
if (string.IsNullOrWhiteSpace(TransactionId))
|
||||
errors.Add("Transaction ID is required for chargeback protection");
|
||||
|
||||
if (Amount < 0)
|
||||
errors.Add("Purchase amount cannot be negative");
|
||||
@ -601,7 +641,7 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
if (MonthlySpendingAfter < MonthlySpendingBefore)
|
||||
errors.Add("Monthly spending cannot decrease");
|
||||
|
||||
if (ProcessedAt.HasValue && ProcessedAt.Value < Timestamp)
|
||||
if (ProcessedAt.HasValue && ProcessedAt.Value < PurchaseDate)
|
||||
errors.Add("Processed time cannot be before purchase time");
|
||||
|
||||
if (VipPointsAfter < VipPointsBefore)
|
||||
@ -755,4 +795,14 @@ namespace ShadowedRealms.Core.Models.Purchase
|
||||
ReturnedSpender = 5, // Returned after 1-3 months
|
||||
LongAbsentSpender = 6 // Returned after 3+ months
|
||||
}
|
||||
|
||||
public enum CustomerSegment
|
||||
{
|
||||
FreeToPlay = 1,
|
||||
Occasional = 2, // $1-10 lifetime
|
||||
Spender = 3, // $10-100 lifetime
|
||||
Minnow = 4, // $100-500 lifetime
|
||||
Dolphin = 5, // $500-1000 lifetime
|
||||
Whale = 6 // $1000+ lifetime
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user