Browse Source

thêm báo cáo mới cho cms

student 1 tháng trước cách đây
mục cha
commit
b172eb9f46

+ 102 - 26
Kitty_Fall/Kitty_Fall/Kitty_Fall.Cms/Controllers/MonthlyRewardPayoutReportController.cs

@@ -1,4 +1,5 @@
 using System.Globalization;
+using Common;
 using Database.Database;
 using Kitty_Fall.Cms.Helpers;
 using Kitty_Fall.Cms.Models;
@@ -12,6 +13,8 @@ public class MonthlyRewardPayoutReportController : CmsAuthorizedController
     private const int PageSize = 20;
     private const decimal DataToMmkRate = 0.665m;
     private const decimal LoyaltyToMmkRate = 1.33m;
+    private const string RewardExpenseDescriptionPrefix = "Exchange expense ";
+    private const string RewardExpenseSeparator = " - ";
     private readonly ModelContext _db;
 
     public MonthlyRewardPayoutReportController(ModelContext db)
@@ -61,36 +64,59 @@ public class MonthlyRewardPayoutReportController : CmsAuthorizedController
             .Distinct()
             .ToListAsync();
 
-        var payouts = await _db.GameRewardLogs
+        var chargeLogs = await _db.ChargeLogs
             .AsNoTracking()
-            .Where(x => x.Status == 2
-                && x.CreatedTime >= monthStart
-                && x.CreatedTime < monthEnd
-                && (x.RewardType == "DATA" || x.RewardType == "LOYALTY"))
-            .GroupBy(x => new { PayoutDate = x.CreatedTime.Date, x.RewardType, x.RewardValue, x.RewardUnit })
+            .Where(x => x.Status == CommonConstants.UNCHARGE_STATUS
+                && x.Description != null
+                && x.Description.StartsWith(RewardExpenseDescriptionPrefix)
+                && ((x.ChargeTime.HasValue
+                        && x.ChargeTime.Value >= monthStart
+                        && x.ChargeTime.Value < monthEnd)
+                    || (!x.ChargeTime.HasValue
+                        && x.InsertTime.HasValue
+                        && x.InsertTime.Value >= monthStart
+                        && x.InsertTime.Value < monthEnd)))
             .Select(x => new
             {
-                x.Key.PayoutDate,
-                x.Key.RewardType,
-                x.Key.RewardValue,
-                x.Key.RewardUnit,
-                Count = x.Count()
+                PayoutTime = x.ChargeTime ?? x.InsertTime,
+                x.Fee,
+                x.Description
             })
             .ToListAsync();
 
-        var items = payouts
-            .Where(payout => rewardOptions.Any(option =>
-                option.RewardType == payout.RewardType
-                && option.RewardValue == payout.RewardValue
-                && option.RewardUnit == payout.RewardUnit))
-            .Select(payout => new MonthlyRewardPayoutItemViewModel
+        var rewardCharges = chargeLogs
+            .Select(x => ParseRewardCharge(x.PayoutTime, x.Fee, x.Description))
+            .Where(x => x != null)
+            .Select(x => x!)
+            .ToList();
+
+        var items = rewardCharges
+            .GroupBy(x => new
+            {
+                PayoutDate = x.PayoutTime.Date,
+                x.RewardType,
+                x.RewardValue
+            })
+            .Select(group =>
             {
-                PayoutDate = payout.PayoutDate,
-                RewardType = payout.RewardType,
-                RewardValue = payout.RewardValue,
-                RewardUnit = payout.RewardUnit,
-                PayoutCount = payout.Count,
-                MmkRate = GetMmkRate(payout.RewardType)
+                var rewardUnits = rewardOptions
+                    .Where(option => option.RewardType == group.Key.RewardType
+                        && option.RewardValue == group.Key.RewardValue)
+                    .Select(option => option.RewardUnit)
+                    .Where(x => !string.IsNullOrWhiteSpace(x))
+                    .Distinct(StringComparer.OrdinalIgnoreCase)
+                    .OrderBy(x => x)
+                    .ToList();
+
+                return new MonthlyRewardPayoutItemViewModel
+                {
+                    PayoutDate = group.Key.PayoutDate,
+                    RewardType = group.Key.RewardType,
+                    RewardValue = group.Key.RewardValue,
+                    RewardUnit = rewardUnits.Count == 0 ? string.Empty : string.Join(" / ", rewardUnits),
+                    PayoutCount = group.Count(),
+                    MmkRate = GetMmkRate(group.Key.RewardType)
+                };
             })
             .OrderByDescending(x => x.PayoutDate)
             .ThenBy(x => x.RewardType)
@@ -103,7 +129,7 @@ public class MonthlyRewardPayoutReportController : CmsAuthorizedController
         if (model.IsMonthlySummary)
         {
             var monthlyItems = items
-                .GroupBy(x => x.RewardType, StringComparer.OrdinalIgnoreCase)
+                .GroupBy(x => new { x.RewardType, x.RewardValue })
                 .Select(group =>
                 {
                     var rewardUnits = group
@@ -116,14 +142,17 @@ public class MonthlyRewardPayoutReportController : CmsAuthorizedController
                     return new MonthlyRewardPayoutSummaryItemViewModel
                     {
                         Month = monthStart,
-                        RewardType = group.Key,
+                        RewardType = group.Key.RewardType,
+                        RewardPackage = $"{group.Key.RewardType}_{FormatRewardValue(group.Key.RewardValue)}",
+                        RewardValue = group.Key.RewardValue,
                         RewardUnit = rewardUnits.Count == 0 ? string.Empty : string.Join(" / ", rewardUnits),
                         PayoutCount = group.Sum(x => x.PayoutCount),
                         TotalRewardValue = group.Sum(x => x.TotalRewardValue),
-                        MmkRate = GetMmkRate(group.Key)
+                        MmkRate = GetMmkRate(group.Key.RewardType)
                     };
                 })
                 .OrderBy(x => x.RewardType)
+                .ThenBy(x => x.RewardValue)
                 .ToList();
 
             model.TotalRows = monthlyItems.Count;
@@ -160,4 +189,51 @@ public class MonthlyRewardPayoutReportController : CmsAuthorizedController
                 ? LoyaltyToMmkRate
                 : 0;
     }
+
+    private static string FormatRewardValue(decimal value)
+    {
+        return value % 1 == 0
+            ? value.ToString("0", CultureInfo.InvariantCulture)
+            : value.ToString("0.##", CultureInfo.InvariantCulture);
+    }
+
+    private static RewardChargeRecord? ParseRewardCharge(
+        DateTime? payoutTime,
+        decimal? fee,
+        string? description)
+    {
+        if (!payoutTime.HasValue || !fee.HasValue || string.IsNullOrWhiteSpace(description)) return null;
+
+        var descriptionText = description.Trim();
+        if (!descriptionText.StartsWith(RewardExpenseDescriptionPrefix, StringComparison.OrdinalIgnoreCase)) return null;
+
+        var separatorIndex = descriptionText.IndexOf(
+            RewardExpenseSeparator,
+            RewardExpenseDescriptionPrefix.Length,
+            StringComparison.Ordinal);
+        if (separatorIndex < 0) return null;
+
+        var rewardType = descriptionText[
+            RewardExpenseDescriptionPrefix.Length..separatorIndex].Trim().ToUpperInvariant();
+        if (rewardType != "DATA" && rewardType != "LOYALTY") return null;
+
+        var rewardPackage = descriptionText[(separatorIndex + RewardExpenseSeparator.Length)..].Trim();
+        if (!rewardPackage.StartsWith($"{rewardType}_", StringComparison.OrdinalIgnoreCase)) return null;
+
+        return new RewardChargeRecord
+        {
+            PayoutTime = payoutTime.Value,
+            RewardType = rewardType,
+            RewardValue = Math.Abs(fee.Value)
+        };
+    }
+
+    private sealed class RewardChargeRecord
+    {
+        public DateTime PayoutTime { get; init; }
+
+        public string RewardType { get; init; } = string.Empty;
+
+        public decimal RewardValue { get; init; }
+    }
 }

+ 4 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Cms/Models/MonthlyRewardPayoutReportViewModel.cs

@@ -37,6 +37,10 @@ public class MonthlyRewardPayoutSummaryItemViewModel
 
     public string RewardType { get; set; } = string.Empty;
 
+    public string RewardPackage { get; set; } = string.Empty;
+
+    public decimal RewardValue { get; set; }
+
     public string RewardUnit { get; set; } = string.Empty;
 
     public decimal PayoutCount { get; set; }

+ 2 - 2
Kitty_Fall/Kitty_Fall/Kitty_Fall.Cms/Views/MonthlyRewardPayoutReport/Index.cshtml

@@ -60,7 +60,7 @@
                                 <thead class="bg-gray-50">
                                     <tr class="text-left text-xs font-bold uppercase tracking-wider text-gray-500">
                                         <th class="px-4 py-3">Month</th>
-                                        <th class="px-4 py-3">Reward type</th>
+                                        <th class="px-4 py-3">Reward package</th>
                                         <th class="px-4 py-3">Paid count</th>
                                         <th class="px-4 py-3">Total reward</th>
                                         <th class="px-4 py-3">MMK / unit</th>
@@ -72,7 +72,7 @@
                                     {
                                         <tr>
                                             <td class="whitespace-nowrap px-4 py-4 font-semibold text-gray-900">@item.Month.ToString("MM/yyyy")</td>
-                                            <td class="px-4 py-4"><span class="rounded-full px-3 py-1 text-xs font-bold @(item.RewardType == "DATA" ? "bg-blue-50 text-blue-700" : "bg-amber-50 text-amber-700")">@item.RewardType</span></td>
+                                            <td class="px-4 py-4"><span class="rounded-full px-3 py-1 text-xs font-bold @(item.RewardType == "DATA" ? "bg-blue-50 text-blue-700" : "bg-amber-50 text-amber-700")">@item.RewardPackage</span></td>
                                             <td class="whitespace-nowrap px-4 py-4">@Number(item.PayoutCount)</td>
                                             <td class="whitespace-nowrap px-4 py-4 font-semibold text-gray-900">@Number(item.TotalRewardValue) @item.RewardUnit</td>
                                             <td class="whitespace-nowrap px-4 py-4">@Number(item.MmkRate)</td>