diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs
index f94c400..fad3d6d 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs
@@ -96,6 +96,7 @@ namespace NCC.Extend.LqHytkHytk
.WhereIF(queryTksj != null, p => p.Tksj >= new DateTime(startTksj.ToDate().Year, startTksj.ToDate().Month, startTksj.ToDate().Day, 0, 0, 0))
.WhereIF(queryTksj != null, p => p.Tksj <= new DateTime(endTksj.ToDate().Year, endTksj.ToDate().Month, endTksj.ToDate().Day, 23, 59, 59))
.WhereIF(!string.IsNullOrEmpty(input.czry), p => p.Czry.Equals(input.czry))
+ .WhereIF(input.isEffective != 0, p => p.IsEffective == input.isEffective)
.Select(it => new LqHytkHytkListOutput
{
id = it.Id,
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
index 6b63c97..7f99c04 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
@@ -43,6 +43,7 @@ using NCC.System.Entitys.Permission;
using SqlSugar;
using Yitter.IdGenerator;
using NCC.Extend.Entitys.lq_package_info;
+using NCC.Extend.Entitys.lq_mdxx;
namespace NCC.Extend.LqKdKdjlb
{
@@ -216,9 +217,9 @@ namespace NCC.Extend.LqKdKdjlb
.WhereIF(queryKdrq != null, p => p.Kdrq <= new DateTime(endKdrq.ToDate().Year, endKdrq.ToDate().Month, endKdrq.ToDate().Day, 23, 59, 59))
.WhereIF(!string.IsNullOrEmpty(input.gjlx), p => p.Gjlx.Equals(input.gjlx))
.WhereIF(!string.IsNullOrEmpty(input.hgjg), p => p.Hgjg.Equals(input.hgjg))
- .WhereIF(!string.IsNullOrEmpty(input.zdyj), p => p.Zdyj.Equals(input.zdyj))
- .WhereIF(!string.IsNullOrEmpty(input.sfyj), p => p.Sfyj.Equals(input.sfyj))
- .WhereIF(!string.IsNullOrEmpty(input.qk), p => p.Qk.Equals(input.qk))
+ .WhereIF(input.zdyj != null, p => p.Zdyj > input.zdyj)
+ .WhereIF(input.sfyj != null, p => p.Sfyj > input.sfyj)
+ .WhereIF(input.qk != null, p => p.Qk > input.qk)
.WhereIF(!string.IsNullOrEmpty(input.ckfs), p => p.Ckfs.Equals(input.ckfs))
.WhereIF(!string.IsNullOrEmpty(input.fkfs), p => p.Fkfs.Equals(input.fkfs))
.WhereIF(!string.IsNullOrEmpty(input.fkyy), p => p.Fkyy.Equals(input.fkyy))
@@ -233,6 +234,7 @@ namespace NCC.Extend.LqKdKdjlb
.WhereIF(!string.IsNullOrEmpty(input.kdhysjh), p => p.Kdhysjh.Contains(input.kdhysjh))
.WhereIF(!string.IsNullOrEmpty(input.F_FIleUrl), p => p.F_FIleUrl.Contains(input.F_FIleUrl))
.WhereIF(!string.IsNullOrEmpty(input.CreateUser), p => p.CreateUser.Equals(input.CreateUser))
+ .WhereIF(input.isEffective != 0, p => p.IsEffective == input.isEffective)
.Select(it => new LqKdKdjlbListOutput
{
id = it.Id,
@@ -781,9 +783,9 @@ namespace NCC.Extend.LqKdKdjlb
.WhereIF(queryKdrq != null, p => p.Kdrq <= new DateTime(endKdrq.ToDate().Year, endKdrq.ToDate().Month, endKdrq.ToDate().Day, 23, 59, 59))
.WhereIF(!string.IsNullOrEmpty(input.gjlx), p => p.Gjlx.Equals(input.gjlx))
.WhereIF(!string.IsNullOrEmpty(input.hgjg), p => p.Hgjg.Equals(input.hgjg))
- .WhereIF(!string.IsNullOrEmpty(input.zdyj), p => p.Zdyj.Equals(input.zdyj))
- .WhereIF(!string.IsNullOrEmpty(input.sfyj), p => p.Sfyj.Equals(input.sfyj))
- .WhereIF(!string.IsNullOrEmpty(input.qk), p => p.Qk.Equals(input.qk))
+ .WhereIF(input.zdyj != null, p => p.Zdyj > input.zdyj)
+ .WhereIF(input.sfyj != null, p => p.Sfyj > input.sfyj)
+ .WhereIF(input.qk != null, p => p.Qk > input.qk)
.WhereIF(!string.IsNullOrEmpty(input.ckfs), p => p.Ckfs.Equals(input.ckfs))
.WhereIF(!string.IsNullOrEmpty(input.fkfs), p => p.Fkfs.Equals(input.fkfs))
.WhereIF(!string.IsNullOrEmpty(input.fkyy), p => p.Fkyy.Equals(input.fkyy))
@@ -797,6 +799,7 @@ namespace NCC.Extend.LqKdKdjlb
.WhereIF(!string.IsNullOrEmpty(input.kdhyc), p => p.Kdhyc.Contains(input.kdhyc))
.WhereIF(!string.IsNullOrEmpty(input.kdhysjh), p => p.Kdhysjh.Contains(input.kdhysjh))
.WhereIF(!string.IsNullOrEmpty(input.F_FIleUrl), p => p.F_FIleUrl.Contains(input.F_FIleUrl))
+ .WhereIF(input.isEffective != 0, p => p.IsEffective == input.isEffective)
.Select(it => new LqKdKdjlbListOutput
{
id = it.Id,
@@ -2324,6 +2327,7 @@ namespace NCC.Extend.LqKdKdjlb
/// 转卡是指一个会员把自己剩余的某些品项,转给另外一个会员
/// 转卡会员转出的品项,就做退卡操作
/// 被转卡会员收到的品项,做开卡操作
+ /// 系统会自动从原开单记录中获取健康师和科技部老师的业绩数据
///
/// 示例请求:
/// ```json
@@ -2331,68 +2335,37 @@ namespace NCC.Extend.LqKdKdjlb
/// "fromMemberId": "member001",
/// "toMemberId": "member002",
/// "storeId": "store001",
- /// "signatureFile": "签名文件路径",
- /// "remarks": "转卡备注",
+ /// "signatureFile": "base64签名数据",
+ /// "remarks": "转卡备注信息",
/// "transferItems": [
/// {
- /// "billingItemId": "item001",
+ /// "billingItemId": "pxmx001",
/// "transferQuantity": 5,
- /// "itemId": "px001",
- /// "itemName": "美容项目",
- /// "itemPrice": 100.00,
- /// "sourceType": "转卡",
- /// "healthTeacherPerformances": [
- /// {
- /// "healthTeacherId": "jks001",
- /// "healthTeacherName": "张医生",
- /// "healthTeacherAccount": "zhang001",
- /// "performanceAmount": 50.00,
- /// "laborCost": 20.00,
- /// "itemQuantity": 5
- /// }
- /// ],
- /// "techTeacherPerformances": [
- /// {
- /// "techTeacherId": "kjbs001",
- /// "techTeacherName": "李老师",
- /// "techTeacherAccount": "li001",
- /// "performanceAmount": 30.00,
- /// "laborCost": 10.00,
- /// "itemQuantity": 5
- /// }
- /// ]
+ /// "itemName": "美容项目A",
+ /// "itemPrice": 100.00
/// }
/// ]
/// }
/// ```
///
/// 参数说明:
- /// - fromMemberId: 转出会员ID
- /// - toMemberId: 转入会员ID
- /// - storeId: 门店ID
- /// - signatureFile: 转出会员签名
- /// - remarks: 转卡备注
- /// - transferItems: 转出品项列表
- /// - billingItemId: 开单品项明细ID
- /// - transferQuantity: 转出数量
- /// - itemId: 品项ID
- /// - itemName: 品项名称
- /// - itemPrice: 品项价格
- /// - sourceType: 来源类型
- /// - healthTeacherPerformances: 健康师业绩列表
- /// - healthTeacherId: 健康师ID
- /// - healthTeacherName: 健康师姓名
- /// - healthTeacherAccount: 健康师账号
- /// - performanceAmount: 业绩金额
- /// - laborCost: 人工成本
- /// - itemQuantity: 品项数量
- /// - techTeacherPerformances: 科技部老师业绩列表
- /// - techTeacherId: 科技部老师ID
- /// - techTeacherName: 科技部老师姓名
- /// - techTeacherAccount: 科技部老师账号
- /// - performanceAmount: 业绩金额
- /// - laborCost: 人工成本
- /// - itemQuantity: 品项数量
+ /// - fromMemberId: 转出会员ID(必填)
+ /// - toMemberId: 转入会员ID(必填)
+ /// - storeId: 门店ID(必填)
+ /// - signatureFile: 转出会员签名文件(必填)
+ /// - remarks: 转卡备注信息(可选)
+ /// - transferItems: 转出品项列表(必填)
+ /// - billingItemId: 开单品项明细ID(必填)
+ /// - transferQuantity: 转出数量(必填,大于0)
+ /// - itemName: 品项名称(必填)
+ /// - itemPrice: 品项价格(必填,大于等于0)
+ ///
+ /// 业务规则:
+ /// - 转出和转入会员必须存在且有效
+ /// - 转出品项的剩余数量必须足够
+ /// - 系统会自动从原开单记录中获取健康师和科技部老师业绩数据
+ /// - 转卡操作会同时创建退卡记录和开卡记录
+ /// - 所有操作在事务中执行,确保数据一致性
///
/// 转卡输入参数
/// 转卡结果
@@ -2406,10 +2379,8 @@ namespace NCC.Extend.LqKdKdjlb
{
throw NCCException.Oh("转卡参数不能为空");
}
-
var userInfo = await _userManager.GetUserInfo();
var transferTime = DateTime.Now;
-
try
{
// 开启事务
@@ -2425,7 +2396,6 @@ namespace NCC.Extend.LqKdKdjlb
{
throw NCCException.Oh("转入会员不存在或已失效");
}
-
// 2. 验证转出品项的余额是否足够
foreach (var item in input.TransferItems)
{
@@ -2434,7 +2404,6 @@ namespace NCC.Extend.LqKdKdjlb
{
throw NCCException.Oh($"品项明细不存在:{item.ItemName}");
}
-
// 查询剩余数量
var remainingCount = await GetItemRemainingCount(item.BillingItemId);
if (remainingCount < item.TransferQuantity)
@@ -2446,6 +2415,7 @@ namespace NCC.Extend.LqKdKdjlb
// 3. 创建退卡记录(转出方)
var refundId = YitIdHelper.NextId().ToString();
var totalRefundAmount = input.TransferItems.Sum(x => x.ItemPrice * x.TransferQuantity);
+ var StoreEntity = await _db.Queryable().Where(p => p.Id == input.StoreId).FirstAsync();
var refundEntity = new LqHytkHytkEntity
{
Id = refundId,
@@ -2456,7 +2426,12 @@ namespace NCC.Extend.LqKdKdjlb
Hy = input.FromMemberId,
Hymc = fromMember.Khmc,
Md = input.StoreId,
+ Mdmc = StoreEntity.Dm,
+ Mdbh = StoreEntity.Mdbm,
SignatureFile = input.SignatureFile,
+ Hyzh = input.FromMemberId,
+ Gklx = fromMember.Khlx,
+ Tksj = DateTime.Now,
Tkje = totalRefundAmount,
ActualRefundAmount = totalRefundAmount, // 转卡时实退金额等于退卡总金额
Tkyy = "转卡",
@@ -2472,9 +2447,9 @@ namespace NCC.Extend.LqKdKdjlb
foreach (var item in input.TransferItems)
{
- var refundPxmxEntity = _db.Queryable().First(p => p.Id == item.BillingItemId);
+ var refundPxmxEntity = await _db.Queryable().Where(p => p.Id == item.BillingItemId).FirstAsync();
//计算品项扣除总金额
- var 品项扣除总金额 = refundPxmxEntity.Pxjg * item.TransferQuantity;
+ var totalItemDeduction = item.ItemPrice * item.TransferQuantity;
//保存退卡明细表
var refundMxEntity = new LqHytkMxEntity
{
@@ -2483,13 +2458,13 @@ namespace NCC.Extend.LqKdKdjlb
BillingItemId = item.BillingItemId,
CreateTime = transferTime,
CreateUser = userInfo.userId,
- Px = item.ItemId,
+ Px = refundPxmxEntity.Px,
Pxmc = item.ItemName,
Pxjg = item.ItemPrice,
- Tkje = 品项扣除总金额,
+ Tkje = totalItemDeduction,
ProjectNumber = item.TransferQuantity,
- SourceType = item.SourceType,
- TotalPrice = 品项扣除总金额,
+ SourceType = refundPxmxEntity.SourceType,
+ TotalPrice = totalItemDeduction,
IsEffective = StatusEnum.有效.GetHashCode()
};
refundMxEntities.Add(refundMxEntity);
@@ -2499,7 +2474,12 @@ namespace NCC.Extend.LqKdKdjlb
{
//获取健康师当月金三角id
var monthString = DateTime.Now.ToString("yyyyMM");
- var GetMonTeam = _db.Queryable().Where(p => p.UserId == jks.Jks && p.Month == monthString).First();
+ var GetMonTeamResult = await _db.Queryable().Where(p => p.UserId == jks.Jkszh && p.Month == monthString).ToListAsync();
+ var GetMonTeam = GetMonTeamResult.FirstOrDefault();
+ if (GetMonTeam == null)
+ {
+ throw NCCException.Oh($"健康师 {jks.Jksxm} 在 {monthString} 月份的金三角团队中不存在,请先配置金三角团队信息");
+ }
//获取本月
refundJksyjEntities.Add(new LqHytkJksyjEntity
{
@@ -2508,7 +2488,7 @@ namespace NCC.Extend.LqKdKdjlb
Jks = jks.Jks,
Jksxm = jks.Jksxm,
Jkszh = jks.Jkszh,
- Jksyj = (品项扣除总金额 / refundKdyjEntities.Count()),
+ Jksyj = (totalItemDeduction / refundKdyjEntities.Count()),
Tksj = DateTime.Now,
F_jsjid = GetMonTeam.JsjId,
F_tkpxid = refundMxEntity.Id,
@@ -2531,7 +2511,7 @@ namespace NCC.Extend.LqKdKdjlb
Kjbls = kjbs.Kjbls,
Kjblsxm = kjbs.Kjblsxm,
Kjblszh = kjbs.Kjblszh,
- Kjblsyj = (品项扣除总金额 / TechTeacherEntities.Count()),
+ Kjblsyj = (totalItemDeduction / TechTeacherEntities.Count()),
Tksj = transferTime,
F_tkpxid = refundMxEntity.Id,
F_LaborCost = kjbs.LaborCost,
@@ -2565,8 +2545,11 @@ namespace NCC.Extend.LqKdKdjlb
CreateUser = userInfo.userId,
Kdhy = input.ToMemberId,
Djmd = input.StoreId,
+ Kdrq = DateTime.Now,
+ Gjlx = toMember.Khlx,
Fkfs = "转卡",
Sfskdd = "否",
+ Zdyj = input.TransferItems.Sum(x => x.ItemPrice * x.TransferQuantity),
Sfyj = input.TransferItems.Sum(x => x.ItemPrice * x.TransferQuantity),
Bz = $"从会员 {fromMember.Khmc} 转入,{input.Remarks}"
};
@@ -2578,18 +2561,19 @@ namespace NCC.Extend.LqKdKdjlb
foreach (var item in input.TransferItems)
{
+ var refundPxmxEntity = await _db.Queryable().Where(p => p.Id == item.BillingItemId).FirstAsync();
var billingPxmxEntity = new LqKdPxmxEntity
{
Id = YitIdHelper.NextId().ToString(),
Glkdbh = billingId,
- Px = item.ItemId,
+ Px = refundPxmxEntity.Px,
Pxmc = item.ItemName,
Pxjg = item.ItemPrice,
MemberId = input.ToMemberId,
CreateTIme = transferTime,
ProjectNumber = item.TransferQuantity,
IsEnabled = StatusEnum.有效.GetHashCode(),
- SourceType = item.SourceType,
+ SourceType = refundPxmxEntity.SourceType,
TotalPrice = item.ItemPrice * item.TransferQuantity,
ActualPrice = item.ItemPrice * item.TransferQuantity,
IsEffective = StatusEnum.有效.GetHashCode(),
@@ -2666,361 +2650,6 @@ namespace NCC.Extend.LqKdKdjlb
}
#endregion
- // #region 会员转卡操作
- // ///
- // /// 会员转卡操作
- // ///
- // ///
- // /// 转卡是指一个会员把自己剩余的某些品项,转给另外一个会员
- // /// 转卡会员转出的品项,就做退卡操作
- // /// 被转卡会员收到的品项,做开卡操作
- // ///
- // /// 示例请求:
- // /// ```json
- // /// {
- // /// "fromMemberId": "member001",
- // /// "toMemberId": "member002",
- // /// "storeId": "store001",
- // /// "signatureFile": "签名文件路径",
- // /// "remarks": "转卡备注",
- // /// "transferItems": [
- // /// {
- // /// "billingItemId": "item001",
- // /// "transferQuantity": 5,
- // /// "itemId": "px001",
- // /// "itemName": "美容项目",
- // /// "itemPrice": 100.00,
- // /// "sourceType": "转卡",
- // /// "healthTeacherPerformances": [
- // /// {
- // /// "healthTeacherId": "jks001",
- // /// "healthTeacherName": "张医生",
- // /// "healthTeacherAccount": "zhang001",
- // /// "performanceAmount": 50.00,
- // /// "laborCost": 20.00,
- // /// "itemQuantity": 5
- // /// }
- // /// ],
- // /// "techTeacherPerformances": [
- // /// {
- // /// "techTeacherId": "kjbs001",
- // /// "techTeacherName": "李老师",
- // /// "techTeacherAccount": "li001",
- // /// "performanceAmount": 30.00,
- // /// "laborCost": 10.00,
- // /// "itemQuantity": 5
- // /// }
- // /// ]
- // /// }
- // /// ]
- // /// }
- // /// ```
- // ///
- // /// 参数说明:
- // /// - fromMemberId: 转出会员ID
- // /// - toMemberId: 转入会员ID
- // /// - storeId: 门店ID
- // /// - signatureFile: 转出会员签名
- // /// - remarks: 转卡备注
- // /// - transferItems: 转出品项列表
- // /// - billingItemId: 开单品项明细ID
- // /// - transferQuantity: 转出数量
- // /// - itemId: 品项ID
- // /// - itemName: 品项名称
- // /// - itemPrice: 品项价格
- // /// - sourceType: 来源类型
- // /// - healthTeacherPerformances: 健康师业绩列表
- // /// - healthTeacherId: 健康师ID
- // /// - healthTeacherName: 健康师姓名
- // /// - healthTeacherAccount: 健康师账号
- // /// - performanceAmount: 业绩金额
- // /// - laborCost: 人工成本
- // /// - itemQuantity: 品项数量
- // /// - techTeacherPerformances: 科技部老师业绩列表
- // /// - techTeacherId: 科技部老师ID
- // /// - techTeacherName: 科技部老师姓名
- // /// - techTeacherAccount: 科技部老师账号
- // /// - performanceAmount: 业绩金额
- // /// - laborCost: 人工成本
- // /// - itemQuantity: 品项数量
- // ///
- // /// 转卡输入参数
- // /// 转卡结果
- // /// 转卡成功
- // /// 参数错误或业务规则验证失败
- // /// 服务器错误
- // [HttpPost("TransferCard")]
- // public async Task TransferCard([FromBody] TransferCardInput input)
- // {
- // if (input == null)
- // {
- // throw NCCException.Oh("转卡参数不能为空");
- // }
-
- // var userInfo = await _userManager.GetUserInfo();
- // var transferTime = DateTime.Now;
-
- // try
- // {
- // // 开启事务
- // _db.BeginTran();
-
- // // 1. 验证转出和转入会员是否存在
- // var fromMember = await _db.Queryable().Where(x => x.Id == input.FromMemberId && x.IsEffective == StatusEnum.有效.GetHashCode()).FirstAsync();
- // if (fromMember == null)
- // {
- // throw NCCException.Oh("转出会员不存在或已失效");
- // }
- // var toMember = await _db.Queryable().Where(x => x.Id == input.ToMemberId && x.IsEffective == StatusEnum.有效.GetHashCode()).FirstAsync();
- // if (toMember == null)
- // {
- // throw NCCException.Oh("转入会员不存在或已失效");
- // }
-
- // // 2. 验证转出品项的余额是否足够
- // foreach (var item in input.TransferItems)
- // {
- // var billingItem = await _db.Queryable().Where(x => x.Id == item.BillingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()).FirstAsync();
- // if (billingItem == null)
- // {
- // throw NCCException.Oh($"品项明细不存在:{item.ItemName}");
- // }
-
- // // 查询剩余数量
- // var remainingCount = await GetItemRemainingCount(item.BillingItemId);
- // if (remainingCount < item.TransferQuantity)
- // {
- // throw NCCException.Oh($"品项 {item.ItemName} 剩余数量不足,当前剩余:{remainingCount},需要转出:{item.TransferQuantity}");
- // }
- // }
-
- // // 3. 创建退卡记录(转出方)
- // var refundId = YitIdHelper.NextId().ToString();
- // var totalRefundAmount = input.TransferItems.Sum(x => x.ItemPrice * x.TransferQuantity);
- // var refundEntity = new LqHytkHytkEntity
- // {
- // Id = refundId,
- // F_CreateTime = transferTime,
- // F_CreateUser = userInfo.userId,
- // IsEffective = StatusEnum.有效.GetHashCode(),
- // Czry = userInfo.userId,
- // Hy = input.FromMemberId,
- // Hymc = fromMember.Khmc,
- // Md = input.StoreId,
- // SignatureFile = input.SignatureFile,
- // Tkje = totalRefundAmount,
- // ActualRefundAmount = totalRefundAmount, // 转卡时实退金额等于退卡总金额
- // Tkyy = "转卡",
- // Bz = $"转卡给会员:{toMember.Khmc},{input.Remarks}"
- // };
- // await _db.Insertable(refundEntity).ExecuteCommandAsync();
-
- // // 4. 创建退卡品项明细和业绩记录
- // var refundMxEntities = new List();
- // var refundJksyjEntities = new List();
- // var refundKjbsyjEntities = new List();
-
- // foreach (var item in input.TransferItems)
- // {
- // var refundMxEntity = new LqHytkMxEntity
- // {
- // Id = YitIdHelper.NextId().ToString(),
- // RefundInfoId = refundId,
- // BillingItemId = item.BillingItemId,
- // CreateTime = transferTime,
- // CreateUser = userInfo.userId,
- // Px = item.ItemId,
- // Pxmc = item.ItemName,
- // Pxjg = item.ItemPrice,
- // Tkje = item.ItemPrice * item.TransferQuantity,
- // ProjectNumber = item.TransferQuantity,
- // SourceType = item.SourceType,
- // TotalPrice = item.ItemPrice * item.TransferQuantity,
- // IsEffective = StatusEnum.有效.GetHashCode()
- // };
- // refundMxEntities.Add(refundMxEntity);
-
- // // 创建退卡健康师业绩记录
- // if (item.HealthTeacherPerformances != null && item.HealthTeacherPerformances.Any())
- // {
- // foreach (var jks in item.HealthTeacherPerformances)
- // {
- // refundJksyjEntities.Add(new LqHytkJksyjEntity
- // {
- // Id = YitIdHelper.NextId().ToString(),
- // Gltkbh = refundId,
- // Jks = jks.HealthTeacherId,
- // Jksxm = jks.HealthTeacherName,
- // Jkszh = jks.HealthTeacherAccount,
- // Jksyj = jks.PerformanceAmount,
- // Tksj = transferTime,
- // F_jsjid = jks.HealthTeacherId,
- // F_tkpxid = refundMxEntity.Id,
- // F_LaborCost = jks.LaborCost,
- // F_tkpxNumber = jks.ItemQuantity,
- // F_CreateTime = transferTime,
- // F_CreateUser = userInfo.userId,
- // CardReturn = refundMxEntity.Id,
- // IsEffective = StatusEnum.有效.GetHashCode()
- // });
- // }
- // }
-
- // // 创建退卡科技部老师业绩记录
- // if (item.TechTeacherPerformances != null && item.TechTeacherPerformances.Any())
- // {
- // foreach (var kjbs in item.TechTeacherPerformances)
- // {
- // refundKjbsyjEntities.Add(new LqHytkKjbsyjEntity
- // {
- // Id = YitIdHelper.NextId().ToString(),
- // Gltkbh = refundId,
- // Kjbls = kjbs.TechTeacherId,
- // Kjblsxm = kjbs.TechTeacherName,
- // Kjblszh = kjbs.TechTeacherAccount,
- // Kjblsyj = kjbs.PerformanceAmount,
- // Tksj = transferTime,
- // F_tkpxid = refundMxEntity.Id,
- // F_LaborCost = kjbs.LaborCost,
- // F_tkpxNumber = kjbs.ItemQuantity,
- // F_CreateTime = transferTime,
- // F_CreateUser = userInfo.userId,
- // CardReturn = refundMxEntity.Id,
- // IsEffective = StatusEnum.有效.GetHashCode()
- // });
- // }
- // }
- // }
-
- // await _db.Insertable(refundMxEntities).ExecuteCommandAsync();
- // if (refundJksyjEntities.Any())
- // {
- // await _db.Insertable(refundJksyjEntities).ExecuteCommandAsync();
- // }
- // if (refundKjbsyjEntities.Any())
- // {
- // await _db.Insertable(refundKjbsyjEntities).ExecuteCommandAsync();
- // }
-
- // // 5. 创建开卡记录(转入方)
- // var billingId = YitIdHelper.NextId().ToString();
- // var billingEntity = new LqKdKdjlbEntity
- // {
- // Id = billingId,
- // CreateTime = transferTime,
- // UpdateTime = transferTime,
- // IsEffective = StatusEnum.有效.GetHashCode(),
- // CreateUser = userInfo.userId,
- // Kdhy = input.ToMemberId,
- // Djmd = input.StoreId,
- // Sfyj = input.TransferItems.Sum(x => x.ItemPrice * x.TransferQuantity),
- // Bz = $"从会员 {fromMember.Khmc} 转入,{input.Remarks}"
- // };
- // await _db.Insertable(billingEntity).ExecuteCommandAsync();
- // // 6. 创建开单品项明细和业绩记录
- // var billingPxmxEntities = new List();
- // var billingJksyjEntities = new List();
- // var billingKjbsyjEntities = new List();
-
- // foreach (var item in input.TransferItems)
- // {
- // var billingPxmxEntity = new LqKdPxmxEntity
- // {
- // Id = YitIdHelper.NextId().ToString(),
- // Glkdbh = billingId,
- // Px = item.ItemId,
- // Pxmc = item.ItemName,
- // Pxjg = item.ItemPrice,
- // MemberId = input.ToMemberId,
- // CreateTIme = transferTime,
- // ProjectNumber = item.TransferQuantity,
- // IsEnabled = StatusEnum.有效.GetHashCode(),
- // SourceType = item.SourceType,
- // TotalPrice = item.ItemPrice * item.TransferQuantity,
- // ActualPrice = item.ItemPrice * item.TransferQuantity,
- // IsEffective = StatusEnum.有效.GetHashCode(),
- // Remark = $"从会员 {fromMember.Khmc} 转入"
- // };
- // billingPxmxEntities.Add(billingPxmxEntity);
-
- // // 创建开卡健康师业绩记录
- // if (item.HealthTeacherPerformances != null && item.HealthTeacherPerformances.Any())
- // {
- // foreach (var jks in item.HealthTeacherPerformances)
- // {
- // billingJksyjEntities.Add(new LqKdJksyjEntity
- // {
- // Id = YitIdHelper.NextId().ToString(),
- // Glkdbh = billingId,
- // Jks = jks.HealthTeacherId,
- // Jksxm = jks.HealthTeacherName,
- // Jkszh = jks.HealthTeacherAccount,
- // Jksyj = jks.PerformanceAmount.ToString(),
- // Yjsj = transferTime,
- // Jsj_id = jks.HealthTeacherId,
- // Kdpxid = billingPxmxEntity.Id,
- // IsEffective = StatusEnum.有效.GetHashCode()
- // });
- // }
- // }
-
- // // 创建开卡科技部老师业绩记录
- // if (item.TechTeacherPerformances != null && item.TechTeacherPerformances.Any())
- // {
- // foreach (var kjbs in item.TechTeacherPerformances)
- // {
- // billingKjbsyjEntities.Add(new LqKdKjbsyjEntity
- // {
- // Id = YitIdHelper.NextId().ToString(),
- // Glkdbh = billingId,
- // Kjbls = kjbs.TechTeacherId,
- // Kjblsxm = kjbs.TechTeacherName,
- // Kjblszh = kjbs.TechTeacherAccount,
- // Kjblsyj = kjbs.PerformanceAmount.ToString(),
- // Yjsj = transferTime,
- // Kdpxid = billingPxmxEntity.Id,
- // LaborCost = kjbs.LaborCost,
- // IsEffective = StatusEnum.有效.GetHashCode()
- // });
- // }
- // }
- // }
-
- // await _db.Insertable(billingPxmxEntities).ExecuteCommandAsync();
- // if (billingJksyjEntities.Any())
- // {
- // await _db.Insertable(billingJksyjEntities).ExecuteCommandAsync();
- // }
- // if (billingKjbsyjEntities.Any())
- // {
- // await _db.Insertable(billingKjbsyjEntities).ExecuteCommandAsync();
- // }
- // // 提交事务
- // _db.CommitTran();
-
- // return new TransferCardOutput
- // {
- // Success = true,
- // TransferId = refundId,
- // RefundId = refundId,
- // BillingId = billingId,
- // TotalAmount = input.TransferItems.Sum(x => x.ItemPrice * x.TransferQuantity),
- // TotalQuantity = input.TransferItems.Sum(x => x.TransferQuantity),
- // FromMemberName = fromMember.Khmc,
- // ToMemberName = toMember.Khmc,
- // TransferTime = transferTime,
- // Message = "转卡操作成功"
- // };
- // }
- // catch (Exception ex)
- // {
- // _db.RollbackTran();
- // _logger.LogError(ex, "转卡操作失败:{Message}", ex.Message);
- // throw NCCException.Oh($"转卡操作失败:{ex.Message}");
- // }
- // }
- // #endregion
-
#region 获取品项剩余数量
///
/// 获取品项剩余数量
@@ -3032,13 +2661,25 @@ namespace NCC.Extend.LqKdKdjlb
try
{
// 查询购买数量
- var purchasedCount = await _db.Queryable().Where(x => x.Id == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()).Select(x => x.ProjectNumber).FirstAsync();
+ var purchasedCount = await _db.Queryable()
+ .Where(x => x.Id == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode())
+ .SumAsync(x => x.ProjectNumber);
+
// 查询消费数量
- var consumedCount = await _db.Queryable().Where(x => x.BillingItemId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()).SumAsync(x => x.ProjectNumber);
+ var consumedCount = await _db.Queryable()
+ .Where(x => x.BillingItemId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode())
+ .SumAsync(x => x.ProjectNumber);
+
// 查询退卡数量
- var refundedCount = await _db.Queryable().Where(x => x.BillingItemId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()).SumAsync(x => x.ProjectNumber);
+ var refundedCount = await _db.Queryable()
+ .Where(x => x.BillingItemId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode())
+ .SumAsync(x => x.ProjectNumber);
+
// 查询储扣数量
- var deductCount = await _db.Queryable().Where(x => x.DeductId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()).SumAsync(x => x.ProjectNumber);
+ var deductCount = await _db.Queryable()
+ .Where(x => x.DeductId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode())
+ .SumAsync(x => x.ProjectNumber) ?? 0;
+
// 计算剩余数量
var remainingCount = (int)(purchasedCount - consumedCount - refundedCount - deductCount);
return Math.Max(0, remainingCount); // 确保不为负数
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs
index 1a4b767..7fbe557 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs
@@ -684,55 +684,55 @@ namespace NCC.Extend.LqTkjlb
var tkData = await _db.Ado.SqlQueryAsync(tkSql, new { eventId });
var tkDict = tkData.ToDictionary(x => (string)x.F_StoreId, x => x);
- // 第二步:获取邀约数据
+ // 第二步:获取邀约数据(按会员ID去重)
var yaoySql = @"
SELECT
tk.F_StoreId,
- COUNT(DISTINCT yy.F_Id) as yaoy_count
+ COUNT(DISTINCT tk.F_MemberId) as yaoy_count
FROM lq_tkjlb tk
LEFT JOIN lq_yaoyjl yy ON tk.F_MemberId = yy.yykh AND yy.F_StoreId = tk.F_StoreId
- WHERE tk.F_EventId = @eventId
+ WHERE tk.F_EventId = @eventId AND yy.F_Id IS NOT NULL
GROUP BY tk.F_StoreId";
var yaoyData = await _db.Ado.SqlQueryAsync(yaoySql, new { eventId });
var yaoyDict = yaoyData.ToDictionary(x => (string)x.F_StoreId, x => (int)x.yaoy_count);
- // 第三步:获取预约数据
+ // 第三步:获取预约数据(按会员ID去重)
var yySql = @"
SELECT
tk.F_StoreId,
- COUNT(DISTINCT yyjl.F_Id) as yy_count
+ COUNT(DISTINCT tk.F_MemberId) as yy_count
FROM lq_tkjlb tk
LEFT JOIN lq_yyjl yyjl ON tk.F_MemberId = yyjl.gk AND yyjl.F_Status = '已确认'
- WHERE tk.F_EventId = @eventId
+ WHERE tk.F_EventId = @eventId AND yyjl.F_Id IS NOT NULL
GROUP BY tk.F_StoreId";
var yyData = await _db.Ado.SqlQueryAsync(yySql, new { eventId });
var yyDict = yyData.ToDictionary(x => (string)x.F_StoreId, x => (int)x.yy_count);
- // 第四步:获取耗卡数据
+ // 第四步:获取耗卡数据(按会员ID去重,但金额不去重)
var hkSql = @"
SELECT
tk.F_StoreId,
- COUNT(DISTINCT xh.F_Id) as hk_count,
+ COUNT(DISTINCT tk.F_MemberId) as hk_count,
COALESCE(SUM(xh.xfje), 0) as hk_amount
FROM lq_tkjlb tk
LEFT JOIN lq_xh_hyhk xh ON tk.F_MemberId = xh.hy AND xh.F_IsEffective = 1
- WHERE tk.F_EventId = @eventId
+ WHERE tk.F_EventId = @eventId AND xh.F_Id IS NOT NULL
GROUP BY tk.F_StoreId";
var hkData = await _db.Ado.SqlQueryAsync(hkSql, new { eventId });
var hkDict = hkData.ToDictionary(x => (string)x.F_StoreId, x => new { count = (int)x.hk_count, amount = (decimal)x.hk_amount });
- // 第五步:获取开单数据
+ // 第五步:获取开单数据(按会员ID去重,但金额不去重)
var kdSql = @"
SELECT
tk.F_StoreId,
- COUNT(DISTINCT kd.F_Id) as kd_count,
+ COUNT(DISTINCT tk.F_MemberId) as kd_count,
COALESCE(SUM(kd.sfyj), 0) as kd_amount
FROM lq_tkjlb tk
LEFT JOIN lq_kd_kdjlb kd ON tk.F_MemberId = kd.kdhy AND kd.F_IsEffective = 1
- WHERE tk.F_EventId = @eventId
+ WHERE tk.F_EventId = @eventId AND kd.F_Id IS NOT NULL
GROUP BY tk.F_StoreId";
var kdData = await _db.Ado.SqlQueryAsync(kdSql, new { eventId });
@@ -770,6 +770,91 @@ namespace NCC.Extend.LqTkjlb
#region 门店顾客详情
///
+ /// 生成门店顾客详情查询SQL
+ ///
+ /// 是否分页
+ /// SQL语句
+ private string GetStoreCustomerDetailsSql(bool isPaged = false)
+ {
+ var baseSql = @"
+ SELECT
+ tk.F_Id as tk_id, -- 拓客记录ID
+ tk.F_CustomerPhone as customer_phone, -- 顾客手机号
+ tk.F_MemberId as member_id, -- 会员ID
+ tk.F_CustomerName as customer_name, -- 顾客姓名
+ tk.F_CreateTime as tk_time, -- 拓客时间
+ -- 邀约信息
+ yaoy.F_Id as yaoy_id, -- 邀约ID
+ yaoy.F_CreateTime as yaoy_time, -- 邀约时间
+ yaoy.F_Status as yaoy_status, -- 邀约状态
+ -- 预约信息
+ yy.F_Id as yy_id, -- 预约ID
+ yy.F_Status as yy_status, -- 预约状态
+ yy.F_CreateTime as yy_time, -- 预约时间
+ yy.yysj as appointment_time, -- 预约到店时间
+ -- 耗卡信息(聚合)
+ xh_summary.total_consume_amount, -- 耗卡总金额
+ xh_summary.consume_count, -- 耗卡次数
+ xh_summary.first_consume_time, -- 首次耗卡时间
+ xh_summary.last_consume_time, -- 最后耗卡时间
+ -- 开卡信息(聚合)
+ kd_summary.total_billing_amount, -- 开卡总金额
+ kd_summary.total_debt_amount, -- 总欠款金额
+ kd_summary.billing_count, -- 开卡次数
+ kd_summary.first_billing_time, -- 首次开卡时间
+ kd_summary.last_billing_time, -- 最后开卡时间
+ -- 状态描述
+ CASE
+ WHEN yaoy.F_Id IS NOT NULL THEN '已邀约'
+ ELSE '未邀约'
+ END as invitation_status, -- 邀约状态描述
+ CASE
+ WHEN yy.F_Id IS NOT NULL THEN '已预约'
+ ELSE '未预约'
+ END as appointment_status, -- 预约状态描述
+ CASE
+ WHEN xh_summary.total_consume_amount > 0 THEN '已耗卡'
+ ELSE '未耗卡'
+ END as consume_status, -- 耗卡状态描述
+ CASE
+ WHEN kd_summary.total_billing_amount > 0 THEN '已开卡'
+ ELSE '未开卡'
+ END as billing_status -- 开卡状态描述
+ FROM lq_tkjlb tk
+ LEFT JOIN lq_yaoyjl yaoy ON tk.F_MemberId = yaoy.yykh
+ AND yaoy.F_StoreId = tk.F_StoreId
+ LEFT JOIN lq_yyjl yy ON tk.F_MemberId = yy.gk
+ AND yy.F_Status = '已确认'
+ LEFT JOIN (
+ SELECT
+ hy as member_id,
+ SUM(xfje) as total_consume_amount,
+ COUNT(*) as consume_count,
+ MIN(F_CreateTime) as first_consume_time,
+ MAX(F_CreateTime) as last_consume_time
+ FROM lq_xh_hyhk
+ WHERE F_IsEffective = 1
+ GROUP BY hy
+ ) xh_summary ON tk.F_MemberId = xh_summary.member_id
+ LEFT JOIN (
+ SELECT
+ kdhy as member_id,
+ SUM(sfyj) as total_billing_amount,
+ SUM(qk) as total_debt_amount,
+ COUNT(*) as billing_count,
+ MIN(F_CreateTime) as first_billing_time,
+ MAX(F_CreateTime) as last_billing_time
+ FROM lq_kd_kdjlb
+ WHERE F_IsEffective = 1
+ GROUP BY kdhy
+ ) kd_summary ON tk.F_MemberId = kd_summary.member_id
+ WHERE tk.F_EventId = @eventId
+ AND tk.F_StoreId = @storeId
+ ORDER BY tk.F_CreateTime DESC";
+ return isPaged ? baseSql + " LIMIT @offset, @pageSize" : baseSql;
+ }
+
+ ///
/// 获取门店拓客活动顾客详情
///
/// 活动ID
@@ -780,37 +865,7 @@ namespace NCC.Extend.LqTkjlb
{
try
{
- var sql = @"
- SELECT
- tk.F_Id as tk_id, -- 拓客记录ID
- tk.F_CustomerPhone as customer_phone, -- 顾客手机号
- tk.F_MemberId as member_id, -- 会员ID
- tk.F_CustomerName as customer_name, -- 顾客姓名
- tk.F_CreateTime as tk_time, -- 拓客时间
- yy.F_Id as yy_id, -- 预约ID
- yy.F_Status as yy_status, -- 预约状态
- yy.F_CreateTime as yy_time, -- 预约时间
- yy.yysj as appointment_time, -- 预约到店时间
- xh.F_Id as xh_id, -- 耗卡ID
- xh.F_CreateTime as xh_time, -- 耗卡时间
- xh.xfje as consume_amount, -- 耗卡金额
- CASE
- WHEN yy.F_Id IS NOT NULL THEN '已预约'
- ELSE '未预约'
- END as appointment_status, -- 预约状态描述
- CASE
- WHEN xh.F_Id IS NOT NULL THEN '已耗卡'
- ELSE '未耗卡'
- END as consume_status -- 耗卡状态描述
- FROM lq_tkjlb tk
- LEFT JOIN lq_yyjl yy ON tk.F_MemberId = yy.gk
- AND yy.F_Status = '已确认'
- LEFT JOIN lq_xh_hyhk xh ON tk.F_MemberId = xh.hy
- AND xh.F_IsEffective = 1
- WHERE tk.F_EventId = @eventId
- AND tk.F_StoreId = @storeId
- ORDER BY tk.F_CreateTime DESC";
-
+ var sql = GetStoreCustomerDetailsSql(false);
var result = await _db.Ado.SqlQueryAsync(sql, new { eventId, storeId });
return new
@@ -839,44 +894,12 @@ namespace NCC.Extend.LqTkjlb
{
try
{
- var sql = @"
- SELECT
- tk.F_Id as tk_id, -- 拓客记录ID
- tk.F_CustomerPhone as customer_phone, -- 顾客手机号
- tk.F_MemberId as member_id, -- 会员ID
- tk.F_CustomerName as customer_name, -- 顾客姓名
- tk.F_CreateTime as tk_time, -- 拓客时间
- yy.F_Id as yy_id, -- 预约ID
- yy.F_Status as yy_status, -- 预约状态
- yy.F_CreateTime as yy_time, -- 预约时间
- yy.yysj as appointment_time, -- 预约到店时间
- xh.F_Id as xh_id, -- 耗卡ID
- xh.F_CreateTime as xh_time, -- 耗卡时间
- xh.xfje as consume_amount, -- 耗卡金额
- CASE
- WHEN yy.F_Id IS NOT NULL THEN '已预约'
- ELSE '未预约'
- END as appointment_status, -- 预约状态描述
- CASE
- WHEN xh.F_Id IS NOT NULL THEN '已耗卡'
- ELSE '未耗卡'
- END as consume_status -- 耗卡状态描述
- FROM lq_tkjlb tk
- LEFT JOIN lq_yyjl yy ON tk.F_MemberId = yy.gk
- AND yy.F_Status = '已确认'
- LEFT JOIN lq_xh_hyhk xh ON tk.F_MemberId = xh.hy
- AND xh.F_IsEffective = 1
- WHERE tk.F_EventId = @eventId
- AND tk.F_StoreId = @storeId
- ORDER BY tk.F_CreateTime DESC
- LIMIT @offset, @pageSize";
-
+ var sql = GetStoreCustomerDetailsSql(true);
var countSql = @"
SELECT COUNT(*) as total
FROM lq_tkjlb tk
WHERE tk.F_EventId = @eventId
AND tk.F_StoreId = @storeId";
-
var offset = (pageIndex - 1) * pageSize;
var result = await _db.Ado.SqlQueryAsync(sql, new { eventId, storeId, offset, pageSize });
var totalResult = await _db.Ado.SqlQueryAsync(countSql, new { eventId, storeId });
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs
index 8e6f6cd..56bbc87 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs
@@ -193,6 +193,7 @@ namespace NCC.Extend.LqXhHyhk
.WhereIF(queryHksj != null, p => p.Hksj >= new DateTime(startHksj.ToDate().Year, startHksj.ToDate().Month, startHksj.ToDate().Day, 0, 0, 0))
.WhereIF(queryHksj != null, p => p.Hksj <= new DateTime(endHksj.ToDate().Year, endHksj.ToDate().Month, endHksj.ToDate().Day, 23, 59, 59))
.WhereIF(!string.IsNullOrEmpty(input.czry), p => p.Czry.Equals(input.czry))
+ .WhereIF(input.isEffective != 0, p => p.IsEffective == input.isEffective)
.Select(it => new LqXhHyhkListOutput
{
id = it.Id,
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqXmzlService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqXmzlService.cs
index 6c50d62..3024f22 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqXmzlService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqXmzlService.cs
@@ -15,6 +15,12 @@ using System.Linq;
using System.Threading.Tasks;
using NCC.Extend.Entitys.lq_xmzl;
using NCC.Extend.Entitys.Dto.LqXmzl;
+using NCC.Extend.Entitys.lq_kd_pxmx;
+using NCC.Extend.Entitys.lq_xh_pxmx;
+using NCC.Extend.Entitys.lq_hytk_mx;
+using NCC.Extend.Entitys.lq_kd_kdjlb;
+using NCC.Extend.Entitys.lq_xh_hyhk;
+using NCC.Extend.Entitys.lq_hytk_hytk;
using Yitter.IdGenerator;
using NCC.Common.Helper;
using NCC.JsonSerialization;
@@ -28,7 +34,7 @@ namespace NCC.Extend.LqXmzl
///
/// 项目资料服务
///
- [ApiDescriptionSettings(Tag = "绿纤项目资料服务", Name = "LqXmzl", Order = 200)]
+ [ApiDescriptionSettings(Tag = "绿纤品项资料服务", Name = "LqXmzl", Order = 200)]
[Route("api/Extend/[controller]")]
public class LqXmzlService : ILqXmzlService, IDynamicApiController, ITransient
{
@@ -46,7 +52,7 @@ namespace NCC.Extend.LqXmzl
_userManager = userManager;
}
- #region 获取项目资料
+ #region 获取品项资料
///
/// 获取项目资料
@@ -62,9 +68,9 @@ namespace NCC.Extend.LqXmzl
}
#endregion
- #region 获取项目资料列表
+ #region 获取品项资料列表
///
- /// 获取项目资料列表
+ /// 获取品项资料列表
///
/// 请求参数
///
@@ -114,9 +120,9 @@ namespace NCC.Extend.LqXmzl
}
#endregion
- #region 新建项目资料
+ #region 新建品项资料
///
- /// 新建项目资料
+ /// 新建品项资料
///
/// 参数
///
@@ -131,9 +137,9 @@ namespace NCC.Extend.LqXmzl
}
#endregion
- #region 获取项目资料无分页列表
+ #region 获取品项资料无分页列表
///
- /// 获取项目资料无分页列表
+ /// 获取品项资料无分页列表
///
/// 请求参数
///
@@ -177,9 +183,9 @@ namespace NCC.Extend.LqXmzl
}
#endregion
- #region 导出项目资料
+ #region 导出品项资料
///
- /// 导出项目资料
+ /// 导出品项资料
///
/// 请求参数
///
@@ -225,9 +231,9 @@ namespace NCC.Extend.LqXmzl
}
#endregion
- #region 批量删除项目资料
+ #region 批量删除品项资料
///
- /// 批量删除项目资料
+ /// 批量删除品项资料
///
/// 主键数组
///
@@ -257,9 +263,9 @@ namespace NCC.Extend.LqXmzl
}
#endregion
- #region 更新项目资料
+ #region 更新品项资料
///
- /// 更新项目资料
+ /// 更新品项资料
///
/// 主键
/// 参数
@@ -273,9 +279,9 @@ namespace NCC.Extend.LqXmzl
}
#endregion
- #region 删除项目资料
+ #region 删除品项资料
///
- /// 删除项目资料
+ /// 删除品项资料
///
/// 主键
///
@@ -386,6 +392,309 @@ namespace NCC.Extend.LqXmzl
}
#endregion
+ #region 品项维度统计
+ ///
+ /// 品项维度统计
+ ///
+ ///
+ /// 按品项维度统计开卡、消耗、退卡等数据
+ /// 包括业绩、人数、占比、复购率等指标
+ ///
+ /// 示例请求:
+ /// ```json
+ /// {
+ /// "startTime": "2024-01-01",
+ /// "endTime": "2024-12-31",
+ /// "storeId": "store001",
+ /// "category": "美容",
+ /// "itemId": "item001"
+ /// }
+ /// ```
+ ///
+ /// 参数说明:
+ /// - startTime: 开始时间(可选)
+ /// - endTime: 结束时间(可选)
+ /// - storeId: 门店ID(可选)
+ /// - category: 品项分类(可选)
+ /// - itemId: 品项ID(可选,单个品项统计)
+ ///
+ /// 统计输入参数
+ /// 品项维度统计数据
+ /// 统计成功
+ /// 参数错误
+ /// 服务器错误
+ [HttpPost("GetItemStatistics")]
+ public async Task GetItemStatistics([FromBody] LqXmzlStatisticsInput input)
+ {
+ try
+ {
+ // 第一步:获取品项基础信息
+ var itemsQuery = _db.Queryable()
+ .Where(x => x.IsEffective == 1);
+
+ if (!string.IsNullOrEmpty(input.ItemId))
+ {
+ itemsQuery = itemsQuery.Where(x => x.Id == input.ItemId);
+ }
+
+ if (!string.IsNullOrEmpty(input.Category))
+ {
+ itemsQuery = itemsQuery.Where(x => x.Fl1 == input.Category || x.Fl2 == input.Category || x.Fl == input.Category);
+ }
+
+ var items = await itemsQuery.ToListAsync();
+
+ if (!items.Any())
+ {
+ return new
+ {
+ success = true,
+ data = new List(),
+ message = "未找到符合条件的品项"
+ };
+ }
+
+ var itemIds = items.Select(x => x.Id).ToList();
+
+ // 第二步:开卡数据统计
+ var billingStats = await GetBillingStatistics(itemIds, input);
+
+ // 第三步:消耗数据统计
+ var consumeStats = await GetConsumeStatistics(itemIds, input);
+
+ // 第四步:退卡数据统计
+ var refundStats = await GetRefundStatistics(itemIds, input);
+
+ // 第五步:计算总数据用于占比计算
+ var totalBillingAmount = billingStats.Sum(x => x.BillingAmount);
+ var totalConsumeAmount = consumeStats.Sum(x => x.ConsumeAmount);
+ var totalBuyers = billingStats.Sum(x => x.TotalBuyers);
+
+ // 第六步:合并数据并计算占比
+ var result = new List();
+
+ foreach (var item in items)
+ {
+ var billingData = billingStats.FirstOrDefault(x => x.ItemId == item.Id);
+ var consumeData = consumeStats.FirstOrDefault(x => x.ItemId == item.Id);
+ var refundData = refundStats.FirstOrDefault(x => x.ItemId == item.Id);
+
+ var output = new LqXmzlStatisticsOutput
+ {
+ ItemId = item.Id,
+ ItemName = item.Xmmc,
+ ItemNumber = item.Xmbh,
+ BillingAmount = billingData?.BillingAmount ?? 0,
+ BillingAmountRatio = totalBillingAmount > 0 ? (billingData?.BillingAmount ?? 0) / totalBillingAmount : 0,
+ TotalBuyers = billingData?.TotalBuyers ?? 0,
+ ItemRatio = totalBuyers > 0 ? (billingData?.TotalBuyers ?? 0) / (decimal)totalBuyers : 0,
+ RepeatBuyers = billingData?.RepeatBuyers ?? 0,
+ RepeatBuyRate = (billingData?.TotalBuyers ?? 0) > 0 ? (billingData?.RepeatBuyers ?? 0) / (decimal)(billingData?.TotalBuyers ?? 1) : 0,
+ ConsumeAmount = consumeData?.ConsumeAmount ?? 0,
+ ConsumeAmountRatio = totalConsumeAmount > 0 ? (consumeData?.ConsumeAmount ?? 0) / totalConsumeAmount : 0,
+ ConsumePurchaseCount = consumeData?.ConsumePurchaseCount ?? 0,
+ ConsumeGiftCount = consumeData?.ConsumeGiftCount ?? 0,
+ ConsumeExperienceCount = consumeData?.ConsumeExperienceCount ?? 0,
+ RefundAmount = refundData?.RefundAmount ?? 0,
+ RefundCount = refundData?.RefundCount ?? 0
+ };
+
+ result.Add(output);
+ }
+
+ return new
+ {
+ success = true,
+ data = result,
+ message = "品项维度统计成功"
+ };
+ }
+ catch (Exception ex)
+ {
+ throw NCCException.Oh($"品项维度统计失败:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 获取开卡统计数据
+ ///
+ private async Task> GetBillingStatistics(List itemIds, LqXmzlStatisticsInput input)
+ {
+ var query = _db.Queryable()
+ .Where(x => itemIds.Contains(x.Px) && x.IsEffective == 1);
+
+ // 时间过滤
+ if (input.StartTime.HasValue)
+ {
+ query = query.Where(x => x.CreateTIme >= input.StartTime.Value);
+ }
+ if (input.EndTime.HasValue)
+ {
+ query = query.Where(x => x.CreateTIme <= input.EndTime.Value);
+ }
+
+ // 门店过滤(通过开单记录关联)
+ if (!string.IsNullOrEmpty(input.StoreId))
+ {
+ query = query.InnerJoin((px, kd) => px.Glkdbh == kd.Id)
+ .Where((px, kd) => kd.Djmd == input.StoreId && kd.IsEffective == 1);
+ }
+
+ var result = await query
+ .GroupBy(x => x.Px)
+ .Select(x => new ItemStatisticsData
+ {
+ ItemId = x.Px,
+ BillingAmount = SqlFunc.AggregateSum(x.Pxjg * x.ProjectNumber),
+ TotalBuyers = SqlFunc.AggregateCount(x.MemberId),
+ RepeatBuyers = 0 // 复购人数需要单独计算
+ })
+ .ToListAsync();
+
+ // 单独计算复购人数
+ foreach (var item in result)
+ {
+ var memberCountQuery = _db.Queryable()
+ .Where(x => x.Px == item.ItemId && x.IsEffective == 1);
+
+ if (input.StartTime.HasValue)
+ {
+ memberCountQuery = memberCountQuery.Where(x => x.CreateTIme >= input.StartTime.Value);
+ }
+ if (input.EndTime.HasValue)
+ {
+ memberCountQuery = memberCountQuery.Where(x => x.CreateTIme <= input.EndTime.Value);
+ }
+ if (!string.IsNullOrEmpty(input.StoreId))
+ {
+ memberCountQuery = memberCountQuery.InnerJoin((px, kd) => px.Glkdbh == kd.Id)
+ .Where((px, kd) => kd.Djmd == input.StoreId && kd.IsEffective == 1);
+ }
+
+ var memberStats = await memberCountQuery
+ .GroupBy(x => x.MemberId)
+ .Having(x => SqlFunc.AggregateCount(x.MemberId) > 1)
+ .Select(x => SqlFunc.AggregateCount(x.MemberId))
+ .ToListAsync();
+
+ item.RepeatBuyers = memberStats.Count;
+ }
+
+ return result;
+ }
+
+ ///
+ /// 获取消耗统计数据
+ ///
+ private async Task> GetConsumeStatistics(List itemIds, LqXmzlStatisticsInput input)
+ {
+ var query = _db.Queryable()
+ .Where(x => itemIds.Contains(x.Px));
+
+ // 时间过滤
+ if (input.StartTime.HasValue)
+ {
+ query = query.Where(x => x.CreateTIme >= input.StartTime.Value);
+ }
+ if (input.EndTime.HasValue)
+ {
+ query = query.Where(x => x.CreateTIme <= input.EndTime.Value);
+ }
+
+ // 门店过滤(通过耗卡记录关联)
+ if (!string.IsNullOrEmpty(input.StoreId))
+ {
+ query = query.InnerJoin((px, xh) => px.ConsumeInfoId == xh.Id)
+ .Where((px, xh) => xh.Md == input.StoreId && xh.IsEffective == 1);
+ }
+
+ var result = await query
+ .GroupBy(x => x.Px)
+ .Select(x => new ItemConsumeStatisticsData
+ {
+ ItemId = x.Px,
+ ConsumeAmount = SqlFunc.AggregateSum(x.Pxjg * x.ProjectNumber),
+ ConsumePurchaseCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SourceType == "购买", x.ProjectNumber, 0)),
+ ConsumeGiftCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SourceType == "赠送", x.ProjectNumber, 0)),
+ ConsumeExperienceCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SourceType == "体验", x.ProjectNumber, 0))
+ })
+ .ToListAsync();
+
+ return result;
+ }
+
+ ///
+ /// 获取退卡统计数据
+ ///
+ private async Task> GetRefundStatistics(List itemIds, LqXmzlStatisticsInput input)
+ {
+ var query = _db.Queryable()
+ .Where(x => itemIds.Contains(x.Px));
+
+ // 时间过滤
+ if (input.StartTime.HasValue)
+ {
+ query = query.Where(x => x.Tksj >= input.StartTime.Value);
+ }
+ if (input.EndTime.HasValue)
+ {
+ query = query.Where(x => x.Tksj <= input.EndTime.Value);
+ }
+
+ // 门店过滤(通过退卡记录关联)
+ if (!string.IsNullOrEmpty(input.StoreId))
+ {
+ query = query.InnerJoin((mx, hytk) => mx.RefundInfoId == hytk.Id)
+ .Where((mx, hytk) => hytk.Md == input.StoreId && hytk.IsEffective == 1);
+ }
+
+ var result = await query
+ .GroupBy(x => x.Px)
+ .Select(x => new ItemRefundStatisticsData
+ {
+ ItemId = x.Px,
+ RefundAmount = SqlFunc.AggregateSum(x.Tkje ?? 0),
+ RefundCount = SqlFunc.AggregateCount(x.Id)
+ })
+ .ToListAsync();
+
+ return result;
+ }
+ #endregion
+
+ }
+
+ ///
+ /// 品项统计数据(内部类)
+ ///
+ public class ItemStatisticsData
+ {
+ public string ItemId { get; set; }
+ public decimal BillingAmount { get; set; }
+ public int TotalBuyers { get; set; }
+ public int RepeatBuyers { get; set; }
+ }
+
+ ///
+ /// 品项消耗统计数据(内部类)
+ ///
+ public class ItemConsumeStatisticsData
+ {
+ public string ItemId { get; set; }
+ public decimal ConsumeAmount { get; set; }
+ public int ConsumePurchaseCount { get; set; }
+ public int ConsumeGiftCount { get; set; }
+ public int ConsumeExperienceCount { get; set; }
+ }
+
+ ///
+ /// 品项退卡统计数据(内部类)
+ ///
+ public class ItemRefundStatisticsData
+ {
+ public string ItemId { get; set; }
+ public decimal RefundAmount { get; set; }
+ public int RefundCount { get; set; }
}
}