更新 商铺统计利润算法

增加买手售后订单 增加备注
This commit is contained in:
chfei committed 2026-10-09 17:14:54 +08:00
1 parent 87e13e6544
commit 31b78e12b5
12 files changed
+208 -40

No files matched your search

@@ -1,4 +1,5 @@
using KJD_Web.Services.Buyer;
using KJD_Web.Requests.Buyers;
using KJD_Web.Services.Buyer;
using Store.Framework.Base;
using Store.Framework.Dtos;
using Store.Framework.Models;
@@ -36,5 +37,25 @@ public class BuyerController : ApiControllerBase
}
return Ok(ret);
}
/// <summary>
/// 更新买手订单售后备注
/// </summary>
/// <param name="request"></param>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost]
public IHttpActionResult UpdateBuyerAfterRemark(BuyerAfterOrderRequest request)
{
ApiResultBase ret;
try
{
var v = _buyerService.UpdateBuyerAfterRemark(request.UserName, request.id, request.Remark);
ret = ApiResult.Success(v);
}
catch (Exception ex)
{
ret = ApiResult.Fail("更新失败");
}
return Ok(ret);
}
}
+1
View File
@@ -220,6 +220,7 @@
<Compile Include="Model\WxModel\oms_wei_transfer_extra_package.cs" />
<Compile Include="Model\WxModel\ShopRevenueStatistics.cs" />
<Compile Include="Model\WxModel\yh_sync_logistics.cs" />
<Compile Include="Requests\Buyers\BuyerAfterOrderRequest.cs" />
<Compile Include="Requests\RequestBase.cs" />
<Compile Include="Requests\ShopRequest.cs" />
<Compile Include="Requests\Shops\ShopOrderDetailType.cs" />
@@ -1,4 +1,5 @@
using KJD_Web.Utils;
using KJD_Web.Services.Shops;
using KJD_Web.Utils;
using MySqlX.XDevAPI.Relational;
using Store.Contracts.Order.Entitys;
using System;
@@ -24,9 +25,16 @@ public class ShopRevenueStatistics
public string ShopName { get; set; }
/// <summary>
/// 外采金额(单位:分,整数存储)
/// 外采金额(单位:分,整数存储) 最后一次购买的商品金额
/// </summary>
public int OutAmount => BuyerOrders.Sum(a => a.OutAmount);
public int OutAmount
{
get
{
if (BuyerOrders == null || BuyerOrders.Count == 0) return 0;
return BuyerOrders.Last().OutAmount;
}
}
/// <summary>
/// 订单金额,单位为分,
/// </summary>
@@ -178,6 +186,8 @@ public class ShopRevenueStatistics
/// </summary>
public string RefundStatusText { get; set; }
public string Remark { get; set; }
public DateTime CreateTime { get; set; }
}
/// <summary>
@@ -0,0 +1,13 @@
using Store.Framework.Dtos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace KJD_Web.Requests.Buyers;
public class BuyerAfterOrderRequest : SignRequestBase
{
public int id { get; set; }
public string Remark { get; set; }
}
@@ -24,4 +24,8 @@ public enum ShopOrderDetailType
/// 买手未退回金额的订单:退款订单中买手款项还没退回的(对应统计里的未退回金额口径)
/// </summary>
BuyerUnrefunded = 3,
/// <summary>
/// 利润订单 有效订单+退款订单利润>0
/// </summary>
Profit = 4,
}
@@ -45,7 +45,17 @@ public class ShopOrderDetailResponse
public int OrderRefundAmount { get; set; }
/// <summary>
/// 外采金额(分),即该订单下所有买手订单的购买金额之和
/// 利润
/// </summary>
public long ProfitAmount { get; set; }
/// <summary>
/// 平台佣金
/// </summary>
public long PlatformFee { get; set; }
/// <summary>
/// 外采金额(分),即该订单下所有买手订单的最后一单的商品金额
/// </summary>
public int OutAmount { get; set; }
@@ -6,6 +6,7 @@ using Store.Contracts.User.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
namespace KJD_Web.Services.Buyer;
@@ -49,4 +50,30 @@ public class BuyerService : ITransientDependency
}
return false;
}
/// <summary>
/// 更新买手售后订单备注
/// </summary>
/// <param name="id"></param>
/// <param name="remark"></param>
public bool UpdateBuyerAfterRemark(string userName, long id, string remark)
{
var item = _freeSql.Select<OrderPddBuyerAfterSaleEntity>()
.Where(a => a.Id == id)
.First();
if (item == null) return false;
var shopId = _freeSql.Select<WeiOrderEntity>()
.Where(a => a.OrderId == item.WxOrderId)
.ToOne(a => a.ShopId);
var ret = _shopService.IsShopOwnedByUser(shopId, userName);
if (ret == true)
{
var affrows = _freeSql.Update<OrderPddBuyerAfterSaleEntity>()
.Set(a => a.Remark, remark)
.Where(a => a.Id == id)
.ExecuteAffrows();
return affrows == 1;
}
return false;
}
}
@@ -169,7 +169,11 @@ public class ShopRevenueStatisticsService : ITransientDependency
public List<ShopOrderDetailResponse> GetShopOrderDetails(DateTime startTime, DateTime endTime, ShopOrderDetailType orderType = ShopOrderDetailType.All, string userName = null, List<string> shopIds = null)
{
var result = new List<ShopOrderDetailResponse>();
startTime = startTime.Date;
endTime = endTime.Date.AddDays(1).AddSeconds(-1);
if (endTime < startTime) return result;
if (endTime > startTime.AddMonths(3))
throw new ArgumentException("时间范围不能超过3个月");
var ids = shopIds != null && shopIds.Count > 0 ? shopIds : getShopIdsByUserName(userName);
if (ids == null || ids.Count == 0) return result;
@@ -194,6 +198,7 @@ public class ShopRevenueStatisticsService : ITransientDependency
// 加载买手订单(直拍和中转仓都要查),并回填商铺订单的退款金额
LoadBuyerOrder(orders);
FillRefunds(orders);
CalcProfit(orders);
foreach (var order in orders)
{
@@ -215,6 +220,12 @@ public class ShopRevenueStatisticsService : ITransientDependency
case ShopOrderDetailType.BuyerUnrefunded: // 买手未退回金额的订单
if (!hasRefund || unrefundedAmount <= 0) continue;
break;
case ShopOrderDetailType.Profit: //利润订单 有效订单+ 退款订单利润大于>0
if (hasRefund)
{
if (order.Profit <= 0) continue;
}
break;
}
@@ -226,6 +237,8 @@ public class ShopRevenueStatisticsService : ITransientDependency
CreateTime = order.CreateTime,
OrderPrice = order.OrderPrice,
OrderRefundAmount = order.Items.Sum(a => a.RefundAmount),
ProfitAmount = order.Profit,
PlatformFee = order.HasRefund ? 0 : order.PredictCommissionFee,
OutAmount = order.OutAmount,
UnrefundedAmount = unrefundedAmount,
BuyerOrders = buyerOrders,
@@ -427,11 +440,12 @@ public class ShopRevenueStatisticsService : ITransientDependency
{
ShopDailyStats(item.Key, item.Value);
}
string log = $"更新统计:{item.Key.ToString("yyyy/MM/dd")} {item.Value.Count}条商铺";
_logger.Info(log);
Debug.WriteLine(log);
}
string log = $"更新统计:{dict.Count}天数据";
_logger.Info(log);
Debug.WriteLine(log);
}
}
@@ -541,6 +555,7 @@ public class ShopRevenueStatisticsService : ITransientDependency
SkuId = a.OrderSkuId,
OutOrderSn = a.OutOrderNo,
OutAmount = a.OutAmount ?? 0,
CreateTime = a.CreatedTime ?? DateTime.MinValue
}));
}
}
@@ -564,6 +579,7 @@ public class ShopRevenueStatisticsService : ITransientDependency
SkuId = a.WxSkuId,
OutOrderSn = a.OrderSn,
OutAmount = a.OrderAmount ?? 0,
CreateTime = a.AddTime,
}));
}
@@ -600,7 +616,8 @@ public class ShopRevenueStatisticsService : ITransientDependency
OutOrderSn = a.OrderSn,
OutAmount = a.OrderAmount ?? 0,
RefundAmount = a.RefundAmount ?? (a.OrderAmount ?? 0),
RefundStatusText = a.StatusText
RefundStatusText = a.StatusText,
Remark = a.Remark
}));
}
@@ -616,6 +633,7 @@ public class ShopRevenueStatisticsService : ITransientDependency
buyerOrder.RefundId = r.RefundId;
buyerOrder.RefundAmount = r.RefundAmount;
buyerOrder.RefundStatusText = r.RefundStatusText;
buyerOrder.Remark = r.Remark;
}
else
{
@@ -624,7 +642,7 @@ public class ShopRevenueStatisticsService : ITransientDependency
}
}
orders.Sort((a, b) => a.CreateTime.CompareTo(b.CreateTime));
//移除未购买的订单
for (int i = orders.Count - 1; i >= 0; i--)
{
@@ -680,11 +698,26 @@ public class ShopRevenueStatisticsService : ITransientDependency
/// <param name="orders"></param>
private static void CalcProfit(List<OrderInfo> orders)
{
long count = 0;
foreach (var order in orders)
{
order.Profit = order.HasRefund
? order.OrderPrice - order.Items.Sum(a => a.RefundAmount)
: order.OrderPrice - order.OutAmount - order.PredictCommissionFee - order.CommissionAmount;
if (order.HasRefund)
{
order.Profit = order.OrderPrice - order.Items.Sum(a => a.RefundAmount);
count += order.Profit;
if (order.Profit != 0)
{
Debug.WriteLine($"运费利润 :{order.OrderId} {order.Profit}");
}
}
else
{
order.Profit = order.OrderPrice - order.OutAmount - order.PredictCommissionFee - order.CommissionAmount;
if (order.Profit < 0)
{
Debug.WriteLine($"正常单负利润 :{order.OrderId} {order.Profit}");
}
}
}
}
@@ -704,7 +737,7 @@ public class ShopRevenueStatisticsService : ITransientDependency
StatDate = statDate,
OrderCount = valid.Count,
SalesAmount = valid.Sum(o => (long)o.OrderPrice),
ProfitAmount = valid.Sum(o => (long)o.Profit),
ProfitAmount = shopGroup.Sum(o => (long)o.Profit),//利润 包括 正常订单和退款订单所有的利润
PlatformFee = valid.Sum(o => (long)o.PredictCommissionFee),
RefundOrderCount = afterSale.Count,
RefundDone = afterSaleItems.Where(i => i.IsRefundSuccessed)
@@ -805,7 +838,7 @@ public class ShopRevenueStatisticsService : ITransientDependency
yield return source.Skip(i).Take(size).ToArray();
}
private static bool IsRefundDone(string statusText)
internal static bool IsRefundDone(string statusText)
{
return !string.IsNullOrEmpty(statusText) && statusText == "退款成功";
}
@@ -1,4 +1,5 @@
using MAX.Core.DependencyInjection;
using MAX.Core.Logger;
using Store.Framework.Jobs;
using System;
using System.Collections.Generic;
@@ -15,14 +16,20 @@ namespace KJD_Web.Services.Shops;
public class ShopStatsJob : IScheduledJobs, ITransientDependency
{
private readonly ShopRevenueStatisticsService _shopRevenueStatisticsService;
private readonly ILoggerFacade _logger;
public ShopStatsJob(ShopRevenueStatisticsService shopRevenueStatisticsService)
public ShopStatsJob(ShopRevenueStatisticsService shopRevenueStatisticsService, ILoggerFacade logger)
{
_shopRevenueStatisticsService = shopRevenueStatisticsService;
_logger = logger;
}
public Task RunAsync()
{
_shopRevenueStatisticsService.UpdateStats(DateTime.Now.AddDays(-1).Date);
var data = DateTime.Now.AddDays(-1).Date;
_logger.Info($">>> 执行商铺统计更新:{data.ToString("yyyy-MM-dd")}");
_shopRevenueStatisticsService.UpdateStats(data);
_logger.Info($"<<< 执行商铺更新:{data.ToString("yyyy-MM-dd")}");
return Task.CompletedTask;
}
}
@@ -120,4 +120,7 @@ public class OrderPddBuyerAfterSaleEntity
/// </summary>
[Column(Name = "mdy_time")]
public DateTime MdyTime { get; set; }
[Column(Name = "remark")]
public string Remark { get; set; }
}
@@ -259,7 +259,7 @@ public class VirtualLogisticsApi : ISingletonDependency
}
catch (Exception ex)
{
_logger.Error(ex, $"VirtualLogisticsApi:{item.URL}\n{item.Postdata}");
//_logger.Error(ex, $"VirtualLogisticsApi:{item.URL}\n{item.Postdata}");
return new Result<T>
{
Code = -1,
+60 -21
View File
@@ -101,36 +101,59 @@ internal class ShopTest
//shopService.GetShopOrderAmountRange(id, DateTime.Now.AddDays(-10));
}
private static IEnumerable<DateTime> CaseArray
{
get
{
DateTime startDate = DateTime.Parse("2026/08/01");
DateTime endDate = DateTime.Parse("2026/10/08");
for (DateTime d = startDate; d <= endDate; d = d.AddDays(1))
{
yield return d;
}
}
}
[Test]
[TestCaseSource(nameof(CaseArray))]
public void StatsDataRangeShopSalesOrderTest(DateTime date)
{
var shopService = _container.Resolve<ShopRevenueStatisticsService>();
Console.WriteLine($"开始:{date.ToLongDateString()}");
try
{
shopService.ShopDailyStats(date);
}
catch
{
Console.WriteLine($"错误:{date.ToLongDateString()}");
}
}
[Test]
public void GetShopSalesOrderTest()
{
var shopService = _container.Resolve<ShopRevenueStatisticsService>();
DateTime startDate = DateTime.Parse("2026/08/01");
DateTime endDate = DateTime.Parse("2026/10/07");
DateTime date = startDate;
while (date <= endDate)
DateTime date = DateTime.Parse("2026/10/01");
Console.WriteLine($"开始:{date.ToLongDateString()}");
try
{
Console.WriteLine($"开始:{date.ToLongDateString()}");
try
{
shopService.ShopDailyStats(date);
}
catch
{
Console.WriteLine($"错误:{date.ToLongDateString()}");
}
date = date.AddDays(1);
shopService.ShopDailyStats(date, [
1960967267443626508,
]);
}
catch
{
Console.WriteLine($"错误:{date.ToLongDateString()}");
}
}
}
[Test]
public void GetBuyerDailyStatsTest()
{
var shopService = _container.Resolve<ShopRevenueStatisticsService>();
shopService.BuyerDailyStats(DateTime.Parse("2026/10/02"), [1960967267443620449]);
}
[Test]
public void UpdateStatsTest()
{
@@ -177,4 +200,20 @@ internal class ShopTest
}
Console.WriteLine(sb.ToString());
}
[Test]
public void GetShopOrderDetailsTest()
{
var shopService = _container.Resolve<ShopRevenueStatisticsService>();
var ret = shopService.GetShopOrderDetails(DateTime.Parse("2026/10/01"), DateTime.Parse("2026/10/01"), shopIds: [
"1960967267443626517",
]);
foreach (var item in ret)
{
Console.WriteLine($"{item.OrderId} {item.OutAmount}");
}
}
}