307 lines
11 KiB
C#
307 lines
11 KiB
C#
using StoreHub.KJDWebService.Models;
|
||
using StoreHub.Framework.Repositorys;
|
||
using Microsoft.Extensions.Configuration;
|
||
using StoreHub.KJDWebService.Models.WxModel;
|
||
using StoreHub.KJDWebService.Commons;
|
||
using StoreHub.KJDWebService.Commons;
|
||
using MySql.Data.MySqlClient;
|
||
using NaiBa.Util.Extension;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using Newtonsoft.Json.Serialization;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Data;
|
||
using System.Linq;
|
||
using System.Net;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using System.Threading;
|
||
|
||
namespace StoreHub.KJDWebService.Services
|
||
{
|
||
public class WXShopRevenueStatisticsService : ServiceBase
|
||
{
|
||
private readonly WXOrderService _wxOrderService;
|
||
public WXShopRevenueStatisticsService(SqlRepository sqlRepository, IConfiguration configuration, WXOrderService wxOrderService) : base(sqlRepository, configuration)
|
||
{
|
||
_wxOrderService = wxOrderService;
|
||
}
|
||
public string GetShopOrderAmountRange(string inputData)
|
||
{
|
||
Result ret = Result.ArgumentNull();
|
||
if (!string.IsNullOrEmpty(inputData))
|
||
{
|
||
try
|
||
{
|
||
// todo 获取当前用户微信店铺,或指定某一个店铺,某一段时间
|
||
// 获取店铺下时间范围内的所有订单涉及到的金额
|
||
// 直接返回
|
||
if (!WXUserService.GetSign(inputData))
|
||
throw new ArgumentException("校验失败");
|
||
var timeCalc = DateTime.Now;
|
||
|
||
string shop_ids = RegexUtils.GetStringQuery(ref inputData, "shop_ids")?.Replace("'", "");//所有店铺信息
|
||
if (string.IsNullOrEmpty(shop_ids))
|
||
throw new ArgumentException("请选择店铺");
|
||
List<string> shopIdLst = shop_ids.Split(',').ToList();
|
||
if (shopIdLst.Count > 0)
|
||
shop_ids = "'" + string.Join("','", shopIdLst) + "'";
|
||
|
||
|
||
|
||
string start_Time = RegexUtils.GetStringQuery(ref inputData, "start_time")?.Replace("'", "");
|
||
string end_Time = RegexUtils.GetStringQuery(ref inputData, "end_time")?.Replace("'", "");
|
||
DateTime startTime = DateTime.Now.AddDays(-7);
|
||
DateTime endTime = DateTime.Now;
|
||
if (!string.IsNullOrEmpty(start_Time))
|
||
startTime = TimeUtils.StampMillisecondsToDateTime(start_Time.ParseToLong());
|
||
if (!string.IsNullOrEmpty(end_Time))
|
||
endTime = TimeUtils.StampMillisecondsToDateTime(end_Time.ParseToLong());
|
||
if (endTime <= startTime)
|
||
throw new ArgumentException("结束时间必须大于开始时间");
|
||
if (endTime > startTime.AddMonths(3))
|
||
throw new ArgumentException("时间范围不能超过3个月");
|
||
|
||
int startTimestamp = TimeUtils.DateTimeToTimestampSeconds(startTime);
|
||
int endTimestamp = TimeUtils.DateTimeToTimestampSeconds(endTime);
|
||
|
||
StringBuilder sb = new StringBuilder();
|
||
sb.Append("SELECT ");
|
||
sb.Append("A.shop_name, ");
|
||
sb.Append("A.create_time, ");
|
||
sb.Append("A.order_id, ");
|
||
sb.Append("A.`status`, ");
|
||
sb.Append("A.product_price, ");
|
||
sb.Append("A.order_price, ");
|
||
sb.Append("A.purchase_price, ");
|
||
sb.Append("A.freight, ");
|
||
sb.Append("A.predict_commission_fee, ");
|
||
sb.Append("A.commission_amount, ");
|
||
sb.Append("A.discounted_price, ");
|
||
sb.Append("A.profit, ");
|
||
sb.Append("A.purchase_status, ");
|
||
sb.Append("A.out_amount, ");
|
||
sb.Append("B.refund_status, ");
|
||
sb.Append("c.`status` as refund_status_string, ");
|
||
sb.Append("IFNULL(C.refund_amount, 0) AS refund_amount ");
|
||
sb.Append("FROM erp.oms_wei_order AS A ");
|
||
sb.Append("INNER JOIN erp.`oms_wei_order_item` AS B ON A.`order_id` = B.`order_id` ");
|
||
sb.Append("LEFT JOIN ( SELECT order_id,`status`,refund_amount,id FROM erp.`oms_wei_refund` WHERE id IN ( SELECT MAX(id) FROM erp.`oms_wei_refund` GROUP BY order_id)) AS C ON A.order_id = C.order_id ");
|
||
sb.Append("WHERE A.create_time BETWEEN " + startTimestamp + " AND " + endTimestamp + " ");
|
||
sb.Append("AND A.`status` > 10 ");
|
||
sb.Append("AND A.shop_id IN (" + shop_ids + ") ");
|
||
sb.Append("ORDER BY A.create_time asc");
|
||
|
||
string conn = "ConnKJD";
|
||
MysqlUtils mySql = new MysqlUtils(conn);
|
||
DataTable dt = mySql.ExecuteDataTable(sb.ToString());
|
||
mySql.Close();
|
||
if (!string.IsNullOrEmpty(mySql.Message))
|
||
throw new Exception(mySql.Message);
|
||
|
||
// out_amount 为空或为0的订单,从中转仓订单表(GetTransitOrderTable)补全外采金额
|
||
// external_procurement:0=未查到,1=从 GetTransitOrderTable 查询到
|
||
Dictionary<string, int> transitOutAmountMap = new Dictionary<string, int>();
|
||
if (dt != null && dt.Rows.Count > 0)
|
||
{
|
||
HashSet<string> needLookupOrderIds = new HashSet<string>();
|
||
foreach (DataRow row in dt.Rows)
|
||
{
|
||
int? rowOutAmount = row["out_amount"].ParseToInt();
|
||
if (rowOutAmount == null || rowOutAmount.Value == 0)
|
||
{
|
||
string orderId = row["order_id"].ParseToString();
|
||
if (!string.IsNullOrEmpty(orderId))
|
||
needLookupOrderIds.Add(orderId);
|
||
}
|
||
}
|
||
|
||
if (needLookupOrderIds.Count > 0)
|
||
{
|
||
|
||
const int chunkSize = 100;
|
||
const int transitPageSize = 500;
|
||
List<string> needLookupList = needLookupOrderIds.ToList();
|
||
for (int i = 0; i < needLookupList.Count; i += chunkSize)
|
||
{
|
||
int takeCount = Math.Min(chunkSize, needLookupList.Count - i);
|
||
string chunkOrderIds = string.Join(",", needLookupList.GetRange(i, takeCount));
|
||
int pageIndex = 1;
|
||
while (true)
|
||
{
|
||
int count = -1;
|
||
var transitList = _wxOrderService.GetTransitOrderTable(pageIndex, transitPageSize, chunkOrderIds, null, null, null, null, "true", out count);
|
||
if (transitList == null || transitList.Count == 0)
|
||
break;
|
||
foreach (var transit in transitList)
|
||
{
|
||
if (transit != null && !string.IsNullOrEmpty(transit.order_no) && needLookupOrderIds.Contains(transit.order_no))
|
||
{
|
||
if (!transitOutAmountMap.ContainsKey(transit.order_no))
|
||
transitOutAmountMap[transit.order_no] = transit.out_amount ?? 0;
|
||
}
|
||
}
|
||
if (transitList.Count < transitPageSize)
|
||
break;
|
||
pageIndex++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
List<WXOrderAmountInfo> orderList = new List<WXOrderAmountInfo>();
|
||
if (dt != null)
|
||
{
|
||
foreach (DataRow row in dt.Rows)
|
||
orderList.Add(BuildOrderAmountInfo(row, transitOutAmountMap));
|
||
}
|
||
|
||
// 买手号退款金额:退款订单(refund_status>1)且非外采时,从买手售后表补全退款金额
|
||
FillBuyerRefundAmount(orderList, conn);
|
||
|
||
ret.Code = 200;
|
||
ret.Msg = "success";
|
||
ret.Data = orderList;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ret.Code = 500;
|
||
ret.Msg = ex.Message;
|
||
}
|
||
}
|
||
return JsonUtils.SerializeObjectToString(ret, new JsonSerializerSettings
|
||
{
|
||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||
NullValueHandling = NullValueHandling.Ignore
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将订单行转换为金额详情:out_amount 为空或0时从中转仓订单表补全,并计算利润
|
||
/// </summary>
|
||
private WXOrderAmountInfo BuildOrderAmountInfo(DataRow row, Dictionary<string, int> transitOutAmountMap)
|
||
{
|
||
string orderId = row["order_id"].ParseToString();
|
||
|
||
int outAmount = row["out_amount"].ParseToInt();
|
||
int externalProcurement = 0;
|
||
if (outAmount == 0)
|
||
{
|
||
int transitAmount;
|
||
if (transitOutAmountMap.TryGetValue(orderId, out transitAmount))
|
||
{
|
||
externalProcurement = 1;
|
||
outAmount = transitAmount;
|
||
}
|
||
}
|
||
|
||
int orderPrice = row["order_price"].ParseToInt();
|
||
int predictCommissionFee = row["predict_commission_fee"].ParseToInt();
|
||
int commissionAmount = row["commission_amount"].ParseToInt();
|
||
int refund_amount = row["refund_amount"].ParseToInt();
|
||
// 利润 = 订单金额 - 外采金额 - 平台服务费 - 达人佣金(为空按0处理)
|
||
int profit = orderPrice - outAmount - predictCommissionFee - commissionAmount;
|
||
if (refund_amount > 0) //退款利润计算
|
||
{
|
||
profit = orderPrice - refund_amount;
|
||
}
|
||
|
||
return new WXOrderAmountInfo
|
||
{
|
||
shop_name = row["shop_name"].ParseToString(),
|
||
create_time = row["create_time"].ParseToInt(),
|
||
order_id = orderId,
|
||
status = row["status"].ParseToInt(),
|
||
product_price = row["product_price"].ParseToInt(),
|
||
order_price = orderPrice,
|
||
purchase_price = row["purchase_price"].ParseToInt(),
|
||
freight = row["freight"].ParseToInt(),
|
||
predict_commission_fee = predictCommissionFee,
|
||
commission_amount = commissionAmount,
|
||
discounted_price = row["discounted_price"].ParseToInt(),
|
||
profit = profit,
|
||
purchase_status = row["purchase_status"].ParseToInt(),
|
||
out_amount = outAmount,
|
||
refund_status = row["refund_status"].ParseToInt(),
|
||
refund_status_string = row["refund_status_string"].ParseToString(),
|
||
refund_amount = row["refund_amount"].ParseToInt(),
|
||
external_procurement = externalProcurement
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 买手号退款金额:退款订单(refund_status>1)且非外采时,从买手售后表(wxxd.order_pdd_buyer_after_sale)查询退款金额(refundAmount)填入
|
||
/// </summary>
|
||
private void FillBuyerRefundAmount(List<WXOrderAmountInfo> orderList, string conn)
|
||
{
|
||
if (orderList == null || orderList.Count == 0)
|
||
return;
|
||
|
||
// 退款订单(refund_status>1)且非外采(out_amount、external_procurement都为0)的订单才查询买手号退款金额
|
||
HashSet<string> needLookupOrderIds = new HashSet<string>();
|
||
foreach (WXOrderAmountInfo order in orderList)
|
||
{
|
||
if (order.refund_status > 1 && order.external_procurement == 1 && order.out_amount > 0)
|
||
{
|
||
if (!string.IsNullOrEmpty(order.order_id))
|
||
needLookupOrderIds.Add(order.order_id);
|
||
}
|
||
}
|
||
if (needLookupOrderIds.Count == 0)
|
||
return;
|
||
|
||
Dictionary<string, Tuple<int, string>> buyerRefundAmountMap = new Dictionary<string, Tuple<int, string>>();
|
||
MysqlUtils mySql = new MysqlUtils(conn);
|
||
try
|
||
{
|
||
const int chunkSize = 100;
|
||
List<string> needLookupList = needLookupOrderIds.ToList();
|
||
for (int i = 0; i < needLookupList.Count; i += chunkSize)
|
||
{
|
||
int takeCount = Math.Min(chunkSize, needLookupList.Count - i);
|
||
string chunkOrderIds = string.Join("','", needLookupList.GetRange(i, takeCount));
|
||
string sql = "SELECT WX_ORDER_ID,refundAmount,statusText FROM wxxd.order_pdd_buyer_after_sale a " +
|
||
"WHERE a.WX_ORDER_ID IN ('" + chunkOrderIds + "') AND a.id = ( SELECT MAX(b.id) FROM wxxd.order_pdd_buyer_after_sale b WHERE b.WX_ORDER_ID = a.WX_ORDER_ID) ORDER BY a.WX_ORDER_ID;";
|
||
DataTable buyerDt = mySql.ExecuteDataTable(sql);
|
||
if (buyerDt != null)
|
||
{
|
||
foreach (DataRow row in buyerDt.Rows)
|
||
{
|
||
string wxOrderId = row["WX_ORDER_ID"].ParseToString();
|
||
int refundAmount = row["refundAmount"].ParseToInt();
|
||
string statusText = row["statusText"].ParseToString();
|
||
if (!string.IsNullOrEmpty(wxOrderId) && !buyerRefundAmountMap.ContainsKey(wxOrderId))
|
||
buyerRefundAmountMap[wxOrderId] = new Tuple<int, string>(refundAmount, statusText);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
mySql.Close();
|
||
}
|
||
if (!string.IsNullOrEmpty(mySql.Message))
|
||
throw new Exception(mySql.Message);
|
||
|
||
foreach (WXOrderAmountInfo order in orderList)
|
||
{
|
||
Tuple<int, string> buyerRefundAmount;
|
||
if (buyerRefundAmountMap.TryGetValue(order.order_id, out buyerRefundAmount))
|
||
{
|
||
order.buyer_refund_amount = buyerRefundAmount.Item1;
|
||
order.buyer_refund_status = buyerRefundAmount.Item2;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|