Commit b5ed92da95acbcdd4dd7676b53063b842c51690d
1 parent
e701f6b4
feat: 修复转卡接口和开单品项明细查询接口问题
- 修复GetItemRemainingCount方法中SumAsync返回null的问题 - 修复billing-item-detail-list接口日期参数解析问题,支持startTime/endTime参数 - 新增清洗管理功能:门店消耗品库存、清洗商、清洗流水管理 - 新增只买了女神卡的会员统计功能 - 优化统计接口,使用SqlSugar ORM替代原始SQL
Showing
43 changed files
with
3838 additions
and
192 deletions
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateInput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.ComponentModel.DataAnnotations; | |
| 4 | + | |
| 5 | +namespace NCC.Extend.Entitys.Dto.LqInventoryUsage | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 库存使用记录批量创建输入 | |
| 9 | + /// </summary> | |
| 10 | + public class LqInventoryUsageBatchCreateInput | |
| 11 | + { | |
| 12 | + /// <summary> | |
| 13 | + /// 使用记录列表 | |
| 14 | + /// </summary> | |
| 15 | + [Required(ErrorMessage = "使用记录列表不能为空")] | |
| 16 | + [MinLength(1, ErrorMessage = "至少需要添加一条使用记录")] | |
| 17 | + [Display(Name = "使用记录列表")] | |
| 18 | + public List<LqInventoryUsageItemInput> UsageItems { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 使用批次ID(可选,不传则自动生成) | |
| 22 | + /// </summary> | |
| 23 | + [StringLength(50, ErrorMessage = "批次ID长度不能超过50个字符")] | |
| 24 | + [Display(Name = "使用批次ID")] | |
| 25 | + public string BatchId { get; set; } | |
| 26 | + } | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 库存使用记录项输入 | |
| 30 | + /// </summary> | |
| 31 | + public class LqInventoryUsageItemInput | |
| 32 | + { | |
| 33 | + /// <summary> | |
| 34 | + /// 产品ID | |
| 35 | + /// </summary> | |
| 36 | + [Required(ErrorMessage = "产品ID不能为空")] | |
| 37 | + [StringLength(50, ErrorMessage = "产品ID长度不能超过50个字符")] | |
| 38 | + [Display(Name = "产品ID")] | |
| 39 | + public string ProductId { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 门店ID | |
| 43 | + /// </summary> | |
| 44 | + [Required(ErrorMessage = "门店ID不能为空")] | |
| 45 | + [StringLength(50, ErrorMessage = "门店ID长度不能超过50个字符")] | |
| 46 | + [Display(Name = "门店ID")] | |
| 47 | + public string StoreId { get; set; } | |
| 48 | + | |
| 49 | + /// <summary> | |
| 50 | + /// 使用时间 | |
| 51 | + /// </summary> | |
| 52 | + [Required(ErrorMessage = "使用时间不能为空")] | |
| 53 | + [Display(Name = "使用时间")] | |
| 54 | + public DateTime UsageTime { get; set; } | |
| 55 | + | |
| 56 | + /// <summary> | |
| 57 | + /// 使用数量 | |
| 58 | + /// </summary> | |
| 59 | + [Required(ErrorMessage = "使用数量不能为空")] | |
| 60 | + [Range(1, int.MaxValue, ErrorMessage = "使用数量必须大于0")] | |
| 61 | + [Display(Name = "使用数量")] | |
| 62 | + public int UsageQuantity { get; set; } | |
| 63 | + | |
| 64 | + /// <summary> | |
| 65 | + /// 关联消耗ID(可选) | |
| 66 | + /// </summary> | |
| 67 | + [StringLength(50, ErrorMessage = "关联消耗ID长度不能超过50个字符")] | |
| 68 | + [Display(Name = "关联消耗ID")] | |
| 69 | + public string RelatedConsumeId { get; set; } | |
| 70 | + } | |
| 71 | +} | |
| 72 | + | |
| 73 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateOutput.cs
0 → 100644
| 1 | +using System.Collections.Generic; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqInventoryUsage | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 库存使用记录批量创建输出 | |
| 7 | + /// </summary> | |
| 8 | + public class LqInventoryUsageBatchCreateOutput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 批次ID | |
| 12 | + /// </summary> | |
| 13 | + public string BatchId { get; set; } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 成功创建的数量 | |
| 17 | + /// </summary> | |
| 18 | + public int SuccessCount { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 失败的数量 | |
| 22 | + /// </summary> | |
| 23 | + public int FailCount { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 创建成功的记录ID列表 | |
| 27 | + /// </summary> | |
| 28 | + public List<string> SuccessIds { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 失败详情列表 | |
| 32 | + /// </summary> | |
| 33 | + public List<BatchCreateFailItem> FailItems { get; set; } | |
| 34 | + } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 批量创建失败项 | |
| 38 | + /// </summary> | |
| 39 | + public class BatchCreateFailItem | |
| 40 | + { | |
| 41 | + /// <summary> | |
| 42 | + /// 失败索引(对应输入列表的索引) | |
| 43 | + /// </summary> | |
| 44 | + public int Index { get; set; } | |
| 45 | + | |
| 46 | + /// <summary> | |
| 47 | + /// 产品ID | |
| 48 | + /// </summary> | |
| 49 | + public string ProductId { get; set; } | |
| 50 | + | |
| 51 | + /// <summary> | |
| 52 | + /// 失败原因 | |
| 53 | + /// </summary> | |
| 54 | + public string Reason { get; set; } | |
| 55 | + } | |
| 56 | +} | |
| 57 | + | |
| 58 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchInfoOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqInventoryUsage | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 库存使用记录批次信息输出 | |
| 8 | + /// </summary> | |
| 9 | + public class LqInventoryUsageBatchInfoOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 批次ID | |
| 13 | + /// </summary> | |
| 14 | + public string BatchId { get; set; } | |
| 15 | + | |
| 16 | + /// <summary> | |
| 17 | + /// 创建时间 | |
| 18 | + /// </summary> | |
| 19 | + public DateTime CreateTime { get; set; } | |
| 20 | + | |
| 21 | + /// <summary> | |
| 22 | + /// 创建人ID | |
| 23 | + /// </summary> | |
| 24 | + public string CreateUser { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 创建人姓名 | |
| 28 | + /// </summary> | |
| 29 | + public string CreateUserName { get; set; } | |
| 30 | + | |
| 31 | + /// <summary> | |
| 32 | + /// 记录总数 | |
| 33 | + /// </summary> | |
| 34 | + public int TotalCount { get; set; } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 有效记录数 | |
| 38 | + /// </summary> | |
| 39 | + public int EffectiveCount { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 无效记录数 | |
| 43 | + /// </summary> | |
| 44 | + public int IneffectiveCount { get; set; } | |
| 45 | + | |
| 46 | + /// <summary> | |
| 47 | + /// 使用总数量 | |
| 48 | + /// </summary> | |
| 49 | + public int TotalUsageQuantity { get; set; } | |
| 50 | + | |
| 51 | + /// <summary> | |
| 52 | + /// 使用总金额 | |
| 53 | + /// </summary> | |
| 54 | + public decimal TotalUsageAmount { get; set; } | |
| 55 | + | |
| 56 | + /// <summary> | |
| 57 | + /// 使用记录列表 | |
| 58 | + /// </summary> | |
| 59 | + public List<LqInventoryUsageListOutput> UsageRecords { get; set; } | |
| 60 | + } | |
| 61 | +} | |
| 62 | + | |
| 63 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs
| ... | ... | @@ -96,5 +96,10 @@ namespace NCC.Extend.Entitys.Dto.LqInventoryUsage |
| 96 | 96 | /// 使用总价值 |
| 97 | 97 | /// </summary> |
| 98 | 98 | public decimal usageTotalValue { get; set; } |
| 99 | + | |
| 100 | + /// <summary> | |
| 101 | + /// 使用批次ID(同一批次申请的使用记录使用相同的批次ID) | |
| 102 | + /// </summary> | |
| 103 | + public string usageBatchId { get; set; } | |
| 99 | 104 | } |
| 100 | 105 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListQueryInput.cs
| ... | ... | @@ -51,5 +51,10 @@ namespace NCC.Extend.Entitys.Dto.LqInventoryUsage |
| 51 | 51 | /// 是否有效 |
| 52 | 52 | /// </summary> |
| 53 | 53 | public int? IsEffective { get; set; } |
| 54 | + | |
| 55 | + /// <summary> | |
| 56 | + /// 使用批次ID(用于查询同一批次的所有记录) | |
| 57 | + /// </summary> | |
| 58 | + public string UsageBatchId { get; set; } | |
| 54 | 59 | } |
| 55 | 60 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs
| ... | ... | @@ -28,6 +28,16 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb |
| 28 | 28 | public string EndBillingTime { get; set; } |
| 29 | 29 | |
| 30 | 30 | /// <summary> |
| 31 | + /// 开始时间(兼容参数名) | |
| 32 | + /// </summary> | |
| 33 | + public string startTime { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 结束时间(兼容参数名) | |
| 37 | + /// </summary> | |
| 38 | + public string endTime { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 31 | 41 | /// 营销活动ID |
| 32 | 42 | /// </summary> |
| 33 | 43 | public string ActivityId { get; set; } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LaundryStatisticsInput.cs
0 → 100644
| 1 | +using System.ComponentModel.DataAnnotations; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 清洗费用统计输入 | |
| 7 | + /// </summary> | |
| 8 | + public class LaundryStatisticsInput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 开始月份(格式:YYYYMM,如202411) | |
| 12 | + /// </summary> | |
| 13 | + [Display(Name = "开始月份")] | |
| 14 | + public string StartMonth { get; set; } | |
| 15 | + | |
| 16 | + /// <summary> | |
| 17 | + /// 结束月份(格式:YYYYMM,如202412) | |
| 18 | + /// </summary> | |
| 19 | + [Display(Name = "结束月份")] | |
| 20 | + public string EndMonth { get; set; } | |
| 21 | + | |
| 22 | + /// <summary> | |
| 23 | + /// 门店ID(可选,门店统计时使用) | |
| 24 | + /// </summary> | |
| 25 | + [Display(Name = "门店ID")] | |
| 26 | + public string StoreId { get; set; } | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 产品类型(可选,产品统计时使用) | |
| 30 | + /// </summary> | |
| 31 | + [Display(Name = "产品类型")] | |
| 32 | + public string ProductType { get; set; } | |
| 33 | + } | |
| 34 | +} | |
| 35 | + | |
| 36 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowDifferenceOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.ComponentModel.DataAnnotations; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 清洗流水差异输出(送出数量 > 送回数量) | |
| 8 | + /// </summary> | |
| 9 | + public class LqLaundryFlowDifferenceOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 批次号 | |
| 13 | + /// </summary> | |
| 14 | + [Display(Name = "批次号")] | |
| 15 | + public string batchNumber { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 门店ID | |
| 19 | + /// </summary> | |
| 20 | + [Display(Name = "门店ID")] | |
| 21 | + public string storeId { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 门店名称 | |
| 25 | + /// </summary> | |
| 26 | + [Display(Name = "门店名称")] | |
| 27 | + public string storeName { get; set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 产品类型 | |
| 31 | + /// </summary> | |
| 32 | + [Display(Name = "产品类型")] | |
| 33 | + public string productType { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 送出数量 | |
| 37 | + /// </summary> | |
| 38 | + [Display(Name = "送出数量")] | |
| 39 | + public int sendQuantity { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 送回数量 | |
| 43 | + /// </summary> | |
| 44 | + [Display(Name = "送回数量")] | |
| 45 | + public int returnQuantity { get; set; } | |
| 46 | + | |
| 47 | + /// <summary> | |
| 48 | + /// 差异数量 | |
| 49 | + /// </summary> | |
| 50 | + [Display(Name = "差异数量")] | |
| 51 | + public int differenceQuantity { get; set; } | |
| 52 | + | |
| 53 | + /// <summary> | |
| 54 | + /// 差异说明(备注) | |
| 55 | + /// </summary> | |
| 56 | + [Display(Name = "差异说明")] | |
| 57 | + public string differenceRemark { get; set; } | |
| 58 | + | |
| 59 | + /// <summary> | |
| 60 | + /// 送出时间 | |
| 61 | + /// </summary> | |
| 62 | + [Display(Name = "送出时间")] | |
| 63 | + public DateTime? sendTime { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 送回时间 | |
| 67 | + /// </summary> | |
| 68 | + [Display(Name = "送回时间")] | |
| 69 | + public DateTime? returnTime { get; set; } | |
| 70 | + } | |
| 71 | +} | |
| 72 | + | |
| 73 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowInfoOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.ComponentModel.DataAnnotations; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 清洗流水详情输出 | |
| 8 | + /// </summary> | |
| 9 | + public class LqLaundryFlowInfoOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 主键ID | |
| 13 | + /// </summary> | |
| 14 | + [Display(Name = "ID")] | |
| 15 | + public string id { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 流水类型(0:送出 1:送回) | |
| 19 | + /// </summary> | |
| 20 | + [Display(Name = "流水类型")] | |
| 21 | + public int flowType { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 流水类型名称 | |
| 25 | + /// </summary> | |
| 26 | + [Display(Name = "流水类型名称")] | |
| 27 | + public string flowTypeName { get; set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 批次号 | |
| 31 | + /// </summary> | |
| 32 | + [Display(Name = "批次号")] | |
| 33 | + public string batchNumber { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 门店ID | |
| 37 | + /// </summary> | |
| 38 | + [Display(Name = "门店ID")] | |
| 39 | + public string storeId { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 门店名称 | |
| 43 | + /// </summary> | |
| 44 | + [Display(Name = "门店名称")] | |
| 45 | + public string storeName { get; set; } | |
| 46 | + | |
| 47 | + /// <summary> | |
| 48 | + /// 产品类型 | |
| 49 | + /// </summary> | |
| 50 | + [Display(Name = "产品类型")] | |
| 51 | + public string productType { get; set; } | |
| 52 | + | |
| 53 | + /// <summary> | |
| 54 | + /// 清洗商ID | |
| 55 | + /// </summary> | |
| 56 | + [Display(Name = "清洗商ID")] | |
| 57 | + public string laundrySupplierId { get; set; } | |
| 58 | + | |
| 59 | + /// <summary> | |
| 60 | + /// 清洗商名称 | |
| 61 | + /// </summary> | |
| 62 | + [Display(Name = "清洗商名称")] | |
| 63 | + public string laundrySupplierName { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 数量 | |
| 67 | + /// </summary> | |
| 68 | + [Display(Name = "数量")] | |
| 69 | + public int quantity { get; set; } | |
| 70 | + | |
| 71 | + /// <summary> | |
| 72 | + /// 清洗单价 | |
| 73 | + /// </summary> | |
| 74 | + [Display(Name = "清洗单价")] | |
| 75 | + public decimal laundryPrice { get; set; } | |
| 76 | + | |
| 77 | + /// <summary> | |
| 78 | + /// 总费用 | |
| 79 | + /// </summary> | |
| 80 | + [Display(Name = "总费用")] | |
| 81 | + public decimal totalPrice { get; set; } | |
| 82 | + | |
| 83 | + /// <summary> | |
| 84 | + /// 备注 | |
| 85 | + /// </summary> | |
| 86 | + [Display(Name = "备注")] | |
| 87 | + public string remark { get; set; } | |
| 88 | + | |
| 89 | + /// <summary> | |
| 90 | + /// 是否有效 | |
| 91 | + /// </summary> | |
| 92 | + [Display(Name = "是否有效")] | |
| 93 | + public int isEffective { get; set; } | |
| 94 | + | |
| 95 | + /// <summary> | |
| 96 | + /// 创建人ID | |
| 97 | + /// </summary> | |
| 98 | + [Display(Name = "创建人ID")] | |
| 99 | + public string createUser { get; set; } | |
| 100 | + | |
| 101 | + /// <summary> | |
| 102 | + /// 创建人姓名 | |
| 103 | + /// </summary> | |
| 104 | + [Display(Name = "创建人姓名")] | |
| 105 | + public string createUserName { get; set; } | |
| 106 | + | |
| 107 | + /// <summary> | |
| 108 | + /// 创建时间 | |
| 109 | + /// </summary> | |
| 110 | + [Display(Name = "创建时间")] | |
| 111 | + public DateTime createTime { get; set; } | |
| 112 | + } | |
| 113 | +} | |
| 114 | + | |
| 115 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.ComponentModel.DataAnnotations; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 清洗流水列表输出 | |
| 8 | + /// </summary> | |
| 9 | + public class LqLaundryFlowListOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 主键ID | |
| 13 | + /// </summary> | |
| 14 | + [Display(Name = "ID")] | |
| 15 | + public string id { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 流水类型(0:送出 1:送回) | |
| 19 | + /// </summary> | |
| 20 | + [Display(Name = "流水类型")] | |
| 21 | + public int flowType { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 流水类型名称 | |
| 25 | + /// </summary> | |
| 26 | + [Display(Name = "流水类型名称")] | |
| 27 | + public string flowTypeName { get; set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 批次号 | |
| 31 | + /// </summary> | |
| 32 | + [Display(Name = "批次号")] | |
| 33 | + public string batchNumber { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 门店ID | |
| 37 | + /// </summary> | |
| 38 | + [Display(Name = "门店ID")] | |
| 39 | + public string storeId { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 门店名称 | |
| 43 | + /// </summary> | |
| 44 | + [Display(Name = "门店名称")] | |
| 45 | + public string storeName { get; set; } | |
| 46 | + | |
| 47 | + /// <summary> | |
| 48 | + /// 产品类型 | |
| 49 | + /// </summary> | |
| 50 | + [Display(Name = "产品类型")] | |
| 51 | + public string productType { get; set; } | |
| 52 | + | |
| 53 | + /// <summary> | |
| 54 | + /// 清洗商ID | |
| 55 | + /// </summary> | |
| 56 | + [Display(Name = "清洗商ID")] | |
| 57 | + public string laundrySupplierId { get; set; } | |
| 58 | + | |
| 59 | + /// <summary> | |
| 60 | + /// 清洗商名称 | |
| 61 | + /// </summary> | |
| 62 | + [Display(Name = "清洗商名称")] | |
| 63 | + public string laundrySupplierName { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 数量 | |
| 67 | + /// </summary> | |
| 68 | + [Display(Name = "数量")] | |
| 69 | + public int quantity { get; set; } | |
| 70 | + | |
| 71 | + /// <summary> | |
| 72 | + /// 清洗单价 | |
| 73 | + /// </summary> | |
| 74 | + [Display(Name = "清洗单价")] | |
| 75 | + public decimal laundryPrice { get; set; } | |
| 76 | + | |
| 77 | + /// <summary> | |
| 78 | + /// 总费用 | |
| 79 | + /// </summary> | |
| 80 | + [Display(Name = "总费用")] | |
| 81 | + public decimal totalPrice { get; set; } | |
| 82 | + | |
| 83 | + /// <summary> | |
| 84 | + /// 备注 | |
| 85 | + /// </summary> | |
| 86 | + [Display(Name = "备注")] | |
| 87 | + public string remark { get; set; } | |
| 88 | + | |
| 89 | + /// <summary> | |
| 90 | + /// 是否有效 | |
| 91 | + /// </summary> | |
| 92 | + [Display(Name = "是否有效")] | |
| 93 | + public int isEffective { get; set; } | |
| 94 | + | |
| 95 | + /// <summary> | |
| 96 | + /// 创建人ID | |
| 97 | + /// </summary> | |
| 98 | + [Display(Name = "创建人ID")] | |
| 99 | + public string createUser { get; set; } | |
| 100 | + | |
| 101 | + /// <summary> | |
| 102 | + /// 创建人姓名 | |
| 103 | + /// </summary> | |
| 104 | + [Display(Name = "创建人姓名")] | |
| 105 | + public string createUserName { get; set; } | |
| 106 | + | |
| 107 | + /// <summary> | |
| 108 | + /// 创建时间 | |
| 109 | + /// </summary> | |
| 110 | + [Display(Name = "创建时间")] | |
| 111 | + public DateTime createTime { get; set; } | |
| 112 | + } | |
| 113 | +} | |
| 114 | + | |
| 115 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListQueryInput.cs
0 → 100644
| 1 | +using NCC.Common.Filter; | |
| 2 | +using System; | |
| 3 | +using System.ComponentModel.DataAnnotations; | |
| 4 | + | |
| 5 | +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 清洗流水列表查询输入 | |
| 9 | + /// </summary> | |
| 10 | + public class LqLaundryFlowListQueryInput : PageInputBase | |
| 11 | + { | |
| 12 | + /// <summary> | |
| 13 | + /// 流水类型(0:送出 1:送回) | |
| 14 | + /// </summary> | |
| 15 | + [Display(Name = "流水类型", Description = "根据流水类型筛选")] | |
| 16 | + public int? FlowType { get; set; } | |
| 17 | + | |
| 18 | + /// <summary> | |
| 19 | + /// 批次号 | |
| 20 | + /// </summary> | |
| 21 | + [Display(Name = "批次号", Description = "根据批次号筛选")] | |
| 22 | + public string BatchNumber { get; set; } | |
| 23 | + | |
| 24 | + /// <summary> | |
| 25 | + /// 门店ID | |
| 26 | + /// </summary> | |
| 27 | + [Display(Name = "门店ID", Description = "根据门店ID筛选")] | |
| 28 | + public string StoreId { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 产品类型 | |
| 32 | + /// </summary> | |
| 33 | + [Display(Name = "产品类型", Description = "根据产品类型筛选")] | |
| 34 | + public string ProductType { get; set; } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 清洗商ID | |
| 38 | + /// </summary> | |
| 39 | + [Display(Name = "清洗商ID", Description = "根据清洗商ID筛选")] | |
| 40 | + public string LaundrySupplierId { get; set; } | |
| 41 | + | |
| 42 | + /// <summary> | |
| 43 | + /// 开始时间 | |
| 44 | + /// </summary> | |
| 45 | + [Display(Name = "开始时间", Description = "根据创建时间范围筛选")] | |
| 46 | + public DateTime? StartTime { get; set; } | |
| 47 | + | |
| 48 | + /// <summary> | |
| 49 | + /// 结束时间 | |
| 50 | + /// </summary> | |
| 51 | + [Display(Name = "结束时间", Description = "根据创建时间范围筛选")] | |
| 52 | + public DateTime? EndTime { get; set; } | |
| 53 | + | |
| 54 | + /// <summary> | |
| 55 | + /// 是否有效 | |
| 56 | + /// </summary> | |
| 57 | + [Display(Name = "是否有效", Description = "根据是否有效筛选")] | |
| 58 | + public int? IsEffective { get; set; } | |
| 59 | + } | |
| 60 | +} | |
| 61 | + | |
| 62 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowReturnInput.cs
0 → 100644
| 1 | +using System.ComponentModel.DataAnnotations; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 清洗流水送回输入 | |
| 7 | + /// </summary> | |
| 8 | + public class LqLaundryFlowReturnInput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 批次号(对应的送出记录的ID) | |
| 12 | + /// </summary> | |
| 13 | + [Required(ErrorMessage = "批次号不能为空")] | |
| 14 | + [StringLength(50, ErrorMessage = "批次号长度不能超过50个字符")] | |
| 15 | + [Display(Name = "批次号")] | |
| 16 | + public string BatchNumber { get; set; } | |
| 17 | + | |
| 18 | + /// <summary> | |
| 19 | + /// 清洗商ID(可能和送出的清洗商不同) | |
| 20 | + /// </summary> | |
| 21 | + [Required(ErrorMessage = "清洗商ID不能为空")] | |
| 22 | + [StringLength(50, ErrorMessage = "清洗商ID长度不能超过50个字符")] | |
| 23 | + [Display(Name = "清洗商ID")] | |
| 24 | + public string LaundrySupplierId { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 送回数量 | |
| 28 | + /// </summary> | |
| 29 | + [Required(ErrorMessage = "送回数量不能为空")] | |
| 30 | + [Range(0, int.MaxValue, ErrorMessage = "送回数量不能小于0")] | |
| 31 | + [Display(Name = "送回数量")] | |
| 32 | + public int Quantity { get; set; } | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// 备注(可说明差异原因,如损坏、丢失等) | |
| 36 | + /// </summary> | |
| 37 | + [StringLength(1000, ErrorMessage = "备注长度不能超过1000个字符")] | |
| 38 | + [Display(Name = "备注")] | |
| 39 | + public string Remark { get; set; } | |
| 40 | + } | |
| 41 | +} | |
| 42 | + | |
| 43 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowSendInput.cs
0 → 100644
| 1 | +using System.ComponentModel.DataAnnotations; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 清洗流水送出输入 | |
| 7 | + /// </summary> | |
| 8 | + public class LqLaundryFlowSendInput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 门店ID | |
| 12 | + /// </summary> | |
| 13 | + [Required(ErrorMessage = "门店ID不能为空")] | |
| 14 | + [StringLength(50, ErrorMessage = "门店ID长度不能超过50个字符")] | |
| 15 | + [Display(Name = "门店ID")] | |
| 16 | + public string StoreId { get; set; } | |
| 17 | + | |
| 18 | + /// <summary> | |
| 19 | + /// 产品类型(枚举:毛巾、垫子等) | |
| 20 | + /// </summary> | |
| 21 | + [Required(ErrorMessage = "产品类型不能为空")] | |
| 22 | + [StringLength(50, ErrorMessage = "产品类型长度不能超过50个字符")] | |
| 23 | + [Display(Name = "产品类型")] | |
| 24 | + public string ProductType { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 清洗商ID | |
| 28 | + /// </summary> | |
| 29 | + [Required(ErrorMessage = "清洗商ID不能为空")] | |
| 30 | + [StringLength(50, ErrorMessage = "清洗商ID长度不能超过50个字符")] | |
| 31 | + [Display(Name = "清洗商ID")] | |
| 32 | + public string LaundrySupplierId { get; set; } | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// 送出数量 | |
| 36 | + /// </summary> | |
| 37 | + [Required(ErrorMessage = "送出数量不能为空")] | |
| 38 | + [Range(1, int.MaxValue, ErrorMessage = "送出数量必须大于0")] | |
| 39 | + [Display(Name = "送出数量")] | |
| 40 | + public int Quantity { get; set; } | |
| 41 | + | |
| 42 | + /// <summary> | |
| 43 | + /// 备注 | |
| 44 | + /// </summary> | |
| 45 | + [StringLength(1000, ErrorMessage = "备注长度不能超过1000个字符")] | |
| 46 | + [Display(Name = "备注")] | |
| 47 | + public string Remark { get; set; } | |
| 48 | + } | |
| 49 | +} | |
| 50 | + | |
| 51 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryStatisticsOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.ComponentModel.DataAnnotations; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 清洗费用统计输出 | |
| 8 | + /// </summary> | |
| 9 | + public class LqLaundryStatisticsOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 门店ID(门店统计时使用) | |
| 13 | + /// </summary> | |
| 14 | + [Display(Name = "门店ID")] | |
| 15 | + public string storeId { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 门店名称(门店统计时使用) | |
| 19 | + /// </summary> | |
| 20 | + [Display(Name = "门店名称")] | |
| 21 | + public string storeName { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 产品类型(产品统计时使用) | |
| 25 | + /// </summary> | |
| 26 | + [Display(Name = "产品类型")] | |
| 27 | + public string productType { get; set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 统计月份(格式:YYYYMM) | |
| 31 | + /// </summary> | |
| 32 | + [Display(Name = "统计月份")] | |
| 33 | + public string statisticsMonth { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 总费用 | |
| 37 | + /// </summary> | |
| 38 | + [Display(Name = "总费用")] | |
| 39 | + public decimal totalPrice { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 清洗次数 | |
| 43 | + /// </summary> | |
| 44 | + [Display(Name = "清洗次数")] | |
| 45 | + public int count { get; set; } | |
| 46 | + } | |
| 47 | +} | |
| 48 | + | |
| 49 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierCrInput.cs
0 → 100644
| 1 | +using System.ComponentModel.DataAnnotations; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqLaundrySupplier | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 清洗商创建输入 | |
| 7 | + /// </summary> | |
| 8 | + public class LqLaundrySupplierCrInput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 清洗商名称 | |
| 12 | + /// </summary> | |
| 13 | + [Required(ErrorMessage = "清洗商名称不能为空")] | |
| 14 | + [StringLength(200, ErrorMessage = "清洗商名称长度不能超过200个字符")] | |
| 15 | + [Display(Name = "清洗商名称")] | |
| 16 | + public string SupplierName { get; set; } | |
| 17 | + | |
| 18 | + /// <summary> | |
| 19 | + /// 产品类型(枚举:毛巾、垫子等) | |
| 20 | + /// </summary> | |
| 21 | + [Required(ErrorMessage = "产品类型不能为空")] | |
| 22 | + [StringLength(50, ErrorMessage = "产品类型长度不能超过50个字符")] | |
| 23 | + [Display(Name = "产品类型")] | |
| 24 | + public string ProductType { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 清洗价格 | |
| 28 | + /// </summary> | |
| 29 | + [Required(ErrorMessage = "清洗价格不能为空")] | |
| 30 | + [Range(0, double.MaxValue, ErrorMessage = "清洗价格不能小于0")] | |
| 31 | + [Display(Name = "清洗价格")] | |
| 32 | + public decimal LaundryPrice { get; set; } | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// 备注 | |
| 36 | + /// </summary> | |
| 37 | + [StringLength(1000, ErrorMessage = "备注长度不能超过1000个字符")] | |
| 38 | + [Display(Name = "备注")] | |
| 39 | + public string Remark { get; set; } | |
| 40 | + } | |
| 41 | +} | |
| 42 | + | |
| 43 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierInfoOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.ComponentModel.DataAnnotations; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqLaundrySupplier | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 清洗商详情输出 | |
| 8 | + /// </summary> | |
| 9 | + public class LqLaundrySupplierInfoOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 主键ID | |
| 13 | + /// </summary> | |
| 14 | + [Display(Name = "ID")] | |
| 15 | + public string id { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 清洗商名称 | |
| 19 | + /// </summary> | |
| 20 | + [Display(Name = "清洗商名称")] | |
| 21 | + public string supplierName { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 产品类型 | |
| 25 | + /// </summary> | |
| 26 | + [Display(Name = "产品类型")] | |
| 27 | + public string productType { get; set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 清洗价格 | |
| 31 | + /// </summary> | |
| 32 | + [Display(Name = "清洗价格")] | |
| 33 | + public decimal laundryPrice { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 备注 | |
| 37 | + /// </summary> | |
| 38 | + [Display(Name = "备注")] | |
| 39 | + public string remark { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 是否有效 | |
| 43 | + /// </summary> | |
| 44 | + [Display(Name = "是否有效")] | |
| 45 | + public int isEffective { get; set; } | |
| 46 | + | |
| 47 | + /// <summary> | |
| 48 | + /// 创建人ID | |
| 49 | + /// </summary> | |
| 50 | + [Display(Name = "创建人ID")] | |
| 51 | + public string createUser { get; set; } | |
| 52 | + | |
| 53 | + /// <summary> | |
| 54 | + /// 创建人姓名 | |
| 55 | + /// </summary> | |
| 56 | + [Display(Name = "创建人姓名")] | |
| 57 | + public string createUserName { get; set; } | |
| 58 | + | |
| 59 | + /// <summary> | |
| 60 | + /// 创建时间 | |
| 61 | + /// </summary> | |
| 62 | + [Display(Name = "创建时间")] | |
| 63 | + public DateTime createTime { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 更新人ID | |
| 67 | + /// </summary> | |
| 68 | + [Display(Name = "更新人ID")] | |
| 69 | + public string updateUser { get; set; } | |
| 70 | + | |
| 71 | + /// <summary> | |
| 72 | + /// 更新人姓名 | |
| 73 | + /// </summary> | |
| 74 | + [Display(Name = "更新人姓名")] | |
| 75 | + public string updateUserName { get; set; } | |
| 76 | + | |
| 77 | + /// <summary> | |
| 78 | + /// 更新时间 | |
| 79 | + /// </summary> | |
| 80 | + [Display(Name = "更新时间")] | |
| 81 | + public DateTime? updateTime { get; set; } | |
| 82 | + } | |
| 83 | +} | |
| 84 | + | |
| 85 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.ComponentModel.DataAnnotations; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqLaundrySupplier | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 清洗商列表输出 | |
| 8 | + /// </summary> | |
| 9 | + public class LqLaundrySupplierListOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 主键ID | |
| 13 | + /// </summary> | |
| 14 | + [Display(Name = "ID")] | |
| 15 | + public string id { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 清洗商名称 | |
| 19 | + /// </summary> | |
| 20 | + [Display(Name = "清洗商名称")] | |
| 21 | + public string supplierName { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 产品类型 | |
| 25 | + /// </summary> | |
| 26 | + [Display(Name = "产品类型")] | |
| 27 | + public string productType { get; set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 清洗价格 | |
| 31 | + /// </summary> | |
| 32 | + [Display(Name = "清洗价格")] | |
| 33 | + public decimal laundryPrice { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 备注 | |
| 37 | + /// </summary> | |
| 38 | + [Display(Name = "备注")] | |
| 39 | + public string remark { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 是否有效 | |
| 43 | + /// </summary> | |
| 44 | + [Display(Name = "是否有效")] | |
| 45 | + public int isEffective { get; set; } | |
| 46 | + | |
| 47 | + /// <summary> | |
| 48 | + /// 创建人ID | |
| 49 | + /// </summary> | |
| 50 | + [Display(Name = "创建人ID")] | |
| 51 | + public string createUser { get; set; } | |
| 52 | + | |
| 53 | + /// <summary> | |
| 54 | + /// 创建人姓名 | |
| 55 | + /// </summary> | |
| 56 | + [Display(Name = "创建人姓名")] | |
| 57 | + public string createUserName { get; set; } | |
| 58 | + | |
| 59 | + /// <summary> | |
| 60 | + /// 创建时间 | |
| 61 | + /// </summary> | |
| 62 | + [Display(Name = "创建时间")] | |
| 63 | + public DateTime createTime { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 更新人ID | |
| 67 | + /// </summary> | |
| 68 | + [Display(Name = "更新人ID")] | |
| 69 | + public string updateUser { get; set; } | |
| 70 | + | |
| 71 | + /// <summary> | |
| 72 | + /// 更新人姓名 | |
| 73 | + /// </summary> | |
| 74 | + [Display(Name = "更新人姓名")] | |
| 75 | + public string updateUserName { get; set; } | |
| 76 | + | |
| 77 | + /// <summary> | |
| 78 | + /// 更新时间 | |
| 79 | + /// </summary> | |
| 80 | + [Display(Name = "更新时间")] | |
| 81 | + public DateTime? updateTime { get; set; } | |
| 82 | + } | |
| 83 | +} | |
| 84 | + | |
| 85 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListQueryInput.cs
0 → 100644
| 1 | +using NCC.Common.Filter; | |
| 2 | +using System.ComponentModel.DataAnnotations; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqLaundrySupplier | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 清洗商列表查询输入 | |
| 8 | + /// </summary> | |
| 9 | + public class LqLaundrySupplierListQueryInput : PageInputBase | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 清洗商名称(模糊查询) | |
| 13 | + /// </summary> | |
| 14 | + [Display(Name = "清洗商名称", Description = "根据清洗商名称筛选")] | |
| 15 | + public string SupplierName { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 产品类型 | |
| 19 | + /// </summary> | |
| 20 | + [Display(Name = "产品类型", Description = "根据产品类型筛选")] | |
| 21 | + public string ProductType { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 是否有效 | |
| 25 | + /// </summary> | |
| 26 | + [Display(Name = "是否有效", Description = "根据是否有效筛选")] | |
| 27 | + public int? IsEffective { get; set; } | |
| 28 | + } | |
| 29 | +} | |
| 30 | + | |
| 31 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierUpInput.cs
0 → 100644
| 1 | +using System.ComponentModel.DataAnnotations; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqLaundrySupplier | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 清洗商更新输入 | |
| 7 | + /// </summary> | |
| 8 | + public class LqLaundrySupplierUpInput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 主键ID | |
| 12 | + /// </summary> | |
| 13 | + [Required(ErrorMessage = "ID不能为空")] | |
| 14 | + [Display(Name = "ID")] | |
| 15 | + public string Id { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 清洗商名称 | |
| 19 | + /// </summary> | |
| 20 | + [Required(ErrorMessage = "清洗商名称不能为空")] | |
| 21 | + [StringLength(200, ErrorMessage = "清洗商名称长度不能超过200个字符")] | |
| 22 | + [Display(Name = "清洗商名称")] | |
| 23 | + public string SupplierName { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 产品类型(枚举:毛巾、垫子等) | |
| 27 | + /// </summary> | |
| 28 | + [Required(ErrorMessage = "产品类型不能为空")] | |
| 29 | + [StringLength(50, ErrorMessage = "产品类型长度不能超过50个字符")] | |
| 30 | + [Display(Name = "产品类型")] | |
| 31 | + public string ProductType { get; set; } | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// 清洗价格 | |
| 35 | + /// </summary> | |
| 36 | + [Required(ErrorMessage = "清洗价格不能为空")] | |
| 37 | + [Range(0, double.MaxValue, ErrorMessage = "清洗价格不能小于0")] | |
| 38 | + [Display(Name = "清洗价格")] | |
| 39 | + public decimal LaundryPrice { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 备注 | |
| 43 | + /// </summary> | |
| 44 | + [StringLength(1000, ErrorMessage = "备注长度不能超过1000个字符")] | |
| 45 | + [Display(Name = "备注")] | |
| 46 | + public string Remark { get; set; } | |
| 47 | + } | |
| 48 | +} | |
| 49 | + | |
| 50 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberListQueryInput.cs
0 → 100644
| 1 | +namespace NCC.Extend.Entitys.Dto.LqStatistics | |
| 2 | +{ | |
| 3 | + /// <summary> | |
| 4 | + /// 只买了女神卡的会员查询输入 | |
| 5 | + /// </summary> | |
| 6 | + public class GoddessCardMemberListQueryInput | |
| 7 | + { | |
| 8 | + /// <summary> | |
| 9 | + /// 当前页码(从1开始) | |
| 10 | + /// </summary> | |
| 11 | + public int PageIndex { get; set; } = 1; | |
| 12 | + | |
| 13 | + /// <summary> | |
| 14 | + /// 每页数量 | |
| 15 | + /// </summary> | |
| 16 | + public int PageSize { get; set; } = 20; | |
| 17 | + } | |
| 18 | +} | |
| 19 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqStatistics | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 只买了女神卡的会员输出 | |
| 8 | + /// </summary> | |
| 9 | + public class GoddessCardMemberOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 会员ID | |
| 13 | + /// </summary> | |
| 14 | + public string memberId { get; set; } | |
| 15 | + | |
| 16 | + /// <summary> | |
| 17 | + /// 会员名称 | |
| 18 | + /// </summary> | |
| 19 | + public string memberName { get; set; } | |
| 20 | + | |
| 21 | + /// <summary> | |
| 22 | + /// 手机号 | |
| 23 | + /// </summary> | |
| 24 | + public string phone { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 归属门店ID | |
| 28 | + /// </summary> | |
| 29 | + public string storeId { get; set; } | |
| 30 | + | |
| 31 | + /// <summary> | |
| 32 | + /// 归属门店名称 | |
| 33 | + /// </summary> | |
| 34 | + public string storeName { get; set; } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 开单记录列表 | |
| 38 | + /// </summary> | |
| 39 | + public List<GoddessCardBillingInfo> billingList { get; set; } | |
| 40 | + } | |
| 41 | + | |
| 42 | + /// <summary> | |
| 43 | + /// 女神卡开单信息 | |
| 44 | + /// </summary> | |
| 45 | + public class GoddessCardBillingInfo | |
| 46 | + { | |
| 47 | + /// <summary> | |
| 48 | + /// 开单编号 | |
| 49 | + /// </summary> | |
| 50 | + public string billingId { get; set; } | |
| 51 | + | |
| 52 | + /// <summary> | |
| 53 | + /// 开单日期 | |
| 54 | + /// </summary> | |
| 55 | + public DateTime? billingDate { get; set; } | |
| 56 | + | |
| 57 | + /// <summary> | |
| 58 | + /// 实付业绩 | |
| 59 | + /// </summary> | |
| 60 | + public decimal actualPerformance { get; set; } | |
| 61 | + | |
| 62 | + /// <summary> | |
| 63 | + /// 门店ID | |
| 64 | + /// </summary> | |
| 65 | + public string storeId { get; set; } | |
| 66 | + | |
| 67 | + /// <summary> | |
| 68 | + /// 门店名称 | |
| 69 | + /// </summary> | |
| 70 | + public string storeName { get; set; } | |
| 71 | + | |
| 72 | + /// <summary> | |
| 73 | + /// 品项列表 | |
| 74 | + /// </summary> | |
| 75 | + public List<GoddessCardBillingItemInfo> itemList { get; set; } | |
| 76 | + } | |
| 77 | + | |
| 78 | + /// <summary> | |
| 79 | + /// 女神卡开单品项信息 | |
| 80 | + /// </summary> | |
| 81 | + public class GoddessCardBillingItemInfo | |
| 82 | + { | |
| 83 | + /// <summary> | |
| 84 | + /// 品项明细ID | |
| 85 | + /// </summary> | |
| 86 | + public string itemId { get; set; } | |
| 87 | + | |
| 88 | + /// <summary> | |
| 89 | + /// 品项编号 | |
| 90 | + /// </summary> | |
| 91 | + public string itemCode { get; set; } | |
| 92 | + | |
| 93 | + /// <summary> | |
| 94 | + /// 品项名称 | |
| 95 | + /// </summary> | |
| 96 | + public string itemName { get; set; } | |
| 97 | + | |
| 98 | + /// <summary> | |
| 99 | + /// 品项价格 | |
| 100 | + /// </summary> | |
| 101 | + public decimal itemPrice { get; set; } | |
| 102 | + | |
| 103 | + /// <summary> | |
| 104 | + /// 来源类型 | |
| 105 | + /// </summary> | |
| 106 | + public string sourceType { get; set; } | |
| 107 | + | |
| 108 | + /// <summary> | |
| 109 | + /// 项目次数 | |
| 110 | + /// </summary> | |
| 111 | + public decimal projectNumber { get; set; } | |
| 112 | + | |
| 113 | + /// <summary> | |
| 114 | + /// 总价 | |
| 115 | + /// </summary> | |
| 116 | + public decimal totalPrice { get; set; } | |
| 117 | + | |
| 118 | + /// <summary> | |
| 119 | + /// 实付金额 | |
| 120 | + /// </summary> | |
| 121 | + public decimal actualPrice { get; set; } | |
| 122 | + | |
| 123 | + /// <summary> | |
| 124 | + /// 业绩时间 | |
| 125 | + /// </summary> | |
| 126 | + public DateTime? performanceTime { get; set; } | |
| 127 | + } | |
| 128 | +} | |
| 129 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs
| ... | ... | @@ -33,11 +33,6 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics |
| 33 | 33 | public decimal OrderAchievement { get; set; } |
| 34 | 34 | |
| 35 | 35 | /// <summary> |
| 36 | - /// 开卡品项次数 | |
| 37 | - /// </summary> | |
| 38 | - public int OrderItemCount { get; set; } | |
| 39 | - | |
| 40 | - /// <summary> | |
| 41 | 36 | /// 耗卡品项次数 |
| 42 | 37 | /// </summary> |
| 43 | 38 | public int ConsumeItemCount { get; set; } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryCrInput.cs
0 → 100644
| 1 | +using System.ComponentModel.DataAnnotations; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqStoreConsumableInventory | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 门店消耗品库存创建输入 | |
| 7 | + /// </summary> | |
| 8 | + public class LqStoreConsumableInventoryCrInput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 门店ID | |
| 12 | + /// </summary> | |
| 13 | + [Required(ErrorMessage = "门店ID不能为空")] | |
| 14 | + [StringLength(50, ErrorMessage = "门店ID长度不能超过50个字符")] | |
| 15 | + [Display(Name = "门店ID")] | |
| 16 | + public string StoreId { get; set; } | |
| 17 | + | |
| 18 | + /// <summary> | |
| 19 | + /// 产品类型(枚举:毛巾、垫子等) | |
| 20 | + /// </summary> | |
| 21 | + [Required(ErrorMessage = "产品类型不能为空")] | |
| 22 | + [StringLength(50, ErrorMessage = "产品类型长度不能超过50个字符")] | |
| 23 | + [Display(Name = "产品类型")] | |
| 24 | + public string ProductType { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 库存数量 | |
| 28 | + /// </summary> | |
| 29 | + [Required(ErrorMessage = "库存数量不能为空")] | |
| 30 | + [Range(0, int.MaxValue, ErrorMessage = "库存数量不能小于0")] | |
| 31 | + [Display(Name = "库存数量")] | |
| 32 | + public int Quantity { get; set; } | |
| 33 | + } | |
| 34 | +} | |
| 35 | + | |
| 36 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryInfoOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.ComponentModel.DataAnnotations; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqStoreConsumableInventory | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 门店消耗品库存详情输出 | |
| 8 | + /// </summary> | |
| 9 | + public class LqStoreConsumableInventoryInfoOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 主键ID | |
| 13 | + /// </summary> | |
| 14 | + [Display(Name = "ID")] | |
| 15 | + public string id { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 门店ID | |
| 19 | + /// </summary> | |
| 20 | + [Display(Name = "门店ID")] | |
| 21 | + public string storeId { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 门店名称 | |
| 25 | + /// </summary> | |
| 26 | + [Display(Name = "门店名称")] | |
| 27 | + public string storeName { get; set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 产品类型 | |
| 31 | + /// </summary> | |
| 32 | + [Display(Name = "产品类型")] | |
| 33 | + public string productType { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 库存数量 | |
| 37 | + /// </summary> | |
| 38 | + [Display(Name = "库存数量")] | |
| 39 | + public int quantity { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 是否有效 | |
| 43 | + /// </summary> | |
| 44 | + [Display(Name = "是否有效")] | |
| 45 | + public int isEffective { get; set; } | |
| 46 | + | |
| 47 | + /// <summary> | |
| 48 | + /// 创建人ID | |
| 49 | + /// </summary> | |
| 50 | + [Display(Name = "创建人ID")] | |
| 51 | + public string createUser { get; set; } | |
| 52 | + | |
| 53 | + /// <summary> | |
| 54 | + /// 创建人姓名 | |
| 55 | + /// </summary> | |
| 56 | + [Display(Name = "创建人姓名")] | |
| 57 | + public string createUserName { get; set; } | |
| 58 | + | |
| 59 | + /// <summary> | |
| 60 | + /// 创建时间 | |
| 61 | + /// </summary> | |
| 62 | + [Display(Name = "创建时间")] | |
| 63 | + public DateTime createTime { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 更新人ID | |
| 67 | + /// </summary> | |
| 68 | + [Display(Name = "更新人ID")] | |
| 69 | + public string updateUser { get; set; } | |
| 70 | + | |
| 71 | + /// <summary> | |
| 72 | + /// 更新人姓名 | |
| 73 | + /// </summary> | |
| 74 | + [Display(Name = "更新人姓名")] | |
| 75 | + public string updateUserName { get; set; } | |
| 76 | + | |
| 77 | + /// <summary> | |
| 78 | + /// 更新时间 | |
| 79 | + /// </summary> | |
| 80 | + [Display(Name = "更新时间")] | |
| 81 | + public DateTime? updateTime { get; set; } | |
| 82 | + } | |
| 83 | +} | |
| 84 | + | |
| 85 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.ComponentModel.DataAnnotations; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqStoreConsumableInventory | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 门店消耗品库存列表输出 | |
| 8 | + /// </summary> | |
| 9 | + public class LqStoreConsumableInventoryListOutput | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 主键ID | |
| 13 | + /// </summary> | |
| 14 | + [Display(Name = "ID")] | |
| 15 | + public string id { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 门店ID | |
| 19 | + /// </summary> | |
| 20 | + [Display(Name = "门店ID")] | |
| 21 | + public string storeId { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 门店名称 | |
| 25 | + /// </summary> | |
| 26 | + [Display(Name = "门店名称")] | |
| 27 | + public string storeName { get; set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 产品类型 | |
| 31 | + /// </summary> | |
| 32 | + [Display(Name = "产品类型")] | |
| 33 | + public string productType { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 库存数量 | |
| 37 | + /// </summary> | |
| 38 | + [Display(Name = "库存数量")] | |
| 39 | + public int quantity { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 是否有效 | |
| 43 | + /// </summary> | |
| 44 | + [Display(Name = "是否有效")] | |
| 45 | + public int isEffective { get; set; } | |
| 46 | + | |
| 47 | + /// <summary> | |
| 48 | + /// 创建人ID | |
| 49 | + /// </summary> | |
| 50 | + [Display(Name = "创建人ID")] | |
| 51 | + public string createUser { get; set; } | |
| 52 | + | |
| 53 | + /// <summary> | |
| 54 | + /// 创建人姓名 | |
| 55 | + /// </summary> | |
| 56 | + [Display(Name = "创建人姓名")] | |
| 57 | + public string createUserName { get; set; } | |
| 58 | + | |
| 59 | + /// <summary> | |
| 60 | + /// 创建时间 | |
| 61 | + /// </summary> | |
| 62 | + [Display(Name = "创建时间")] | |
| 63 | + public DateTime createTime { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 更新人ID | |
| 67 | + /// </summary> | |
| 68 | + [Display(Name = "更新人ID")] | |
| 69 | + public string updateUser { get; set; } | |
| 70 | + | |
| 71 | + /// <summary> | |
| 72 | + /// 更新人姓名 | |
| 73 | + /// </summary> | |
| 74 | + [Display(Name = "更新人姓名")] | |
| 75 | + public string updateUserName { get; set; } | |
| 76 | + | |
| 77 | + /// <summary> | |
| 78 | + /// 更新时间 | |
| 79 | + /// </summary> | |
| 80 | + [Display(Name = "更新时间")] | |
| 81 | + public DateTime? updateTime { get; set; } | |
| 82 | + } | |
| 83 | +} | |
| 84 | + | |
| 85 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListQueryInput.cs
0 → 100644
| 1 | +using NCC.Common.Filter; | |
| 2 | +using System.ComponentModel.DataAnnotations; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqStoreConsumableInventory | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 门店消耗品库存列表查询输入 | |
| 8 | + /// </summary> | |
| 9 | + public class LqStoreConsumableInventoryListQueryInput : PageInputBase | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 门店ID | |
| 13 | + /// </summary> | |
| 14 | + [Display(Name = "门店ID", Description = "根据门店ID筛选")] | |
| 15 | + public string StoreId { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 产品类型 | |
| 19 | + /// </summary> | |
| 20 | + [Display(Name = "产品类型", Description = "根据产品类型筛选")] | |
| 21 | + public string ProductType { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 是否有效 | |
| 25 | + /// </summary> | |
| 26 | + [Display(Name = "是否有效", Description = "根据是否有效筛选")] | |
| 27 | + public int? IsEffective { get; set; } | |
| 28 | + } | |
| 29 | +} | |
| 30 | + | |
| 31 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryUpInput.cs
0 → 100644
| 1 | +using System.ComponentModel.DataAnnotations; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqStoreConsumableInventory | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 门店消耗品库存更新输入 | |
| 7 | + /// </summary> | |
| 8 | + public class LqStoreConsumableInventoryUpInput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 主键ID | |
| 12 | + /// </summary> | |
| 13 | + [Required(ErrorMessage = "ID不能为空")] | |
| 14 | + [Display(Name = "ID")] | |
| 15 | + public string Id { get; set; } | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 门店ID | |
| 19 | + /// </summary> | |
| 20 | + [Required(ErrorMessage = "门店ID不能为空")] | |
| 21 | + [StringLength(50, ErrorMessage = "门店ID长度不能超过50个字符")] | |
| 22 | + [Display(Name = "门店ID")] | |
| 23 | + public string StoreId { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 产品类型(枚举:毛巾、垫子等) | |
| 27 | + /// </summary> | |
| 28 | + [Required(ErrorMessage = "产品类型不能为空")] | |
| 29 | + [StringLength(50, ErrorMessage = "产品类型长度不能超过50个字符")] | |
| 30 | + [Display(Name = "产品类型")] | |
| 31 | + public string ProductType { get; set; } | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// 库存数量 | |
| 35 | + /// </summary> | |
| 36 | + [Required(ErrorMessage = "库存数量不能为空")] | |
| 37 | + [Range(0, int.MaxValue, ErrorMessage = "库存数量不能小于0")] | |
| 38 | + [Display(Name = "库存数量")] | |
| 39 | + public int Quantity { get; set; } | |
| 40 | + } | |
| 41 | +} | |
| 42 | + | |
| 43 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage/LqInventoryUsageEntity.cs
| ... | ... | @@ -48,6 +48,12 @@ namespace NCC.Extend.Entitys.lq_inventory_usage |
| 48 | 48 | public string RelatedConsumeId { get; set; } |
| 49 | 49 | |
| 50 | 50 | /// <summary> |
| 51 | + /// 使用批次ID(同一批次申请的使用记录使用相同的批次ID) | |
| 52 | + /// </summary> | |
| 53 | + [SugarColumn(ColumnName = "F_UsageBatchId")] | |
| 54 | + public string UsageBatchId { get; set; } | |
| 55 | + | |
| 56 | + /// <summary> | |
| 51 | 57 | /// 创建人ID |
| 52 | 58 | /// </summary> |
| 53 | 59 | [SugarColumn(ColumnName = "F_CreateUser")] | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_flow/LqLaundryFlowEntity.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using NCC.Common.Const; | |
| 3 | +using SqlSugar; | |
| 4 | + | |
| 5 | +namespace NCC.Extend.Entitys.lq_laundry_flow | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 清洗流水表 | |
| 9 | + /// </summary> | |
| 10 | + [SugarTable("lq_laundry_flow")] | |
| 11 | + [Tenant(ClaimConst.TENANT_ID)] | |
| 12 | + public class LqLaundryFlowEntity | |
| 13 | + { | |
| 14 | + /// <summary> | |
| 15 | + /// 主键ID(送出时作为批次号) | |
| 16 | + /// </summary> | |
| 17 | + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)] | |
| 18 | + public string Id { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 流水类型(0:送出 1:送回) | |
| 22 | + /// </summary> | |
| 23 | + [SugarColumn(ColumnName = "F_FlowType")] | |
| 24 | + public int FlowType { get; set; } = 0; | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 批次号(送出时=F_Id,送回时=对应的送出记录的F_Id) | |
| 28 | + /// </summary> | |
| 29 | + [SugarColumn(ColumnName = "F_BatchNumber")] | |
| 30 | + public string BatchNumber { get; set; } | |
| 31 | + | |
| 32 | + /// <summary> | |
| 33 | + /// 门店ID(关联lq_mdxx.F_Id) | |
| 34 | + /// </summary> | |
| 35 | + [SugarColumn(ColumnName = "F_StoreId")] | |
| 36 | + public string StoreId { get; set; } | |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 产品类型(枚举:毛巾、垫子等) | |
| 40 | + /// </summary> | |
| 41 | + [SugarColumn(ColumnName = "F_ProductType")] | |
| 42 | + public string ProductType { get; set; } | |
| 43 | + | |
| 44 | + /// <summary> | |
| 45 | + /// 清洗商ID(关联lq_laundry_supplier.F_Id) | |
| 46 | + /// </summary> | |
| 47 | + [SugarColumn(ColumnName = "F_LaundrySupplierId")] | |
| 48 | + public string LaundrySupplierId { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 数量 | |
| 52 | + /// </summary> | |
| 53 | + [SugarColumn(ColumnName = "F_Quantity")] | |
| 54 | + public int Quantity { get; set; } = 0; | |
| 55 | + | |
| 56 | + /// <summary> | |
| 57 | + /// 清洗单价(记录历史价格) | |
| 58 | + /// </summary> | |
| 59 | + [SugarColumn(ColumnName = "F_LaundryPrice")] | |
| 60 | + public decimal LaundryPrice { get; set; } = 0; | |
| 61 | + | |
| 62 | + /// <summary> | |
| 63 | + /// 总费用(数量 × 单价) | |
| 64 | + /// </summary> | |
| 65 | + [SugarColumn(ColumnName = "F_TotalPrice")] | |
| 66 | + public decimal TotalPrice { get; set; } = 0; | |
| 67 | + | |
| 68 | + /// <summary> | |
| 69 | + /// 备注(可说明差异原因,如损坏、丢失等) | |
| 70 | + /// </summary> | |
| 71 | + [SugarColumn(ColumnName = "F_Remark")] | |
| 72 | + public string Remark { get; set; } | |
| 73 | + | |
| 74 | + /// <summary> | |
| 75 | + /// 是否有效(1:有效 0:无效) | |
| 76 | + /// </summary> | |
| 77 | + [SugarColumn(ColumnName = "F_IsEffective")] | |
| 78 | + public int IsEffective { get; set; } = 1; | |
| 79 | + | |
| 80 | + /// <summary> | |
| 81 | + /// 创建人ID | |
| 82 | + /// </summary> | |
| 83 | + [SugarColumn(ColumnName = "F_CreateUser")] | |
| 84 | + public string CreateUser { get; set; } | |
| 85 | + | |
| 86 | + /// <summary> | |
| 87 | + /// 创建时间 | |
| 88 | + /// </summary> | |
| 89 | + [SugarColumn(ColumnName = "F_CreateTime")] | |
| 90 | + public DateTime CreateTime { get; set; } | |
| 91 | + } | |
| 92 | +} | |
| 93 | + | |
| 94 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_supplier/LqLaundrySupplierEntity.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using NCC.Common.Const; | |
| 3 | +using SqlSugar; | |
| 4 | + | |
| 5 | +namespace NCC.Extend.Entitys.lq_laundry_supplier | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 清洗商表 | |
| 9 | + /// </summary> | |
| 10 | + [SugarTable("lq_laundry_supplier")] | |
| 11 | + [Tenant(ClaimConst.TENANT_ID)] | |
| 12 | + public class LqLaundrySupplierEntity | |
| 13 | + { | |
| 14 | + /// <summary> | |
| 15 | + /// 主键ID | |
| 16 | + /// </summary> | |
| 17 | + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)] | |
| 18 | + public string Id { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 清洗商名称 | |
| 22 | + /// </summary> | |
| 23 | + [SugarColumn(ColumnName = "F_SupplierName")] | |
| 24 | + public string SupplierName { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 产品类型(枚举:毛巾、垫子等) | |
| 28 | + /// </summary> | |
| 29 | + [SugarColumn(ColumnName = "F_ProductType")] | |
| 30 | + public string ProductType { get; set; } | |
| 31 | + | |
| 32 | + /// <summary> | |
| 33 | + /// 清洗价格(当前价格) | |
| 34 | + /// </summary> | |
| 35 | + [SugarColumn(ColumnName = "F_LaundryPrice")] | |
| 36 | + public decimal LaundryPrice { get; set; } = 0; | |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 备注 | |
| 40 | + /// </summary> | |
| 41 | + [SugarColumn(ColumnName = "F_Remark")] | |
| 42 | + public string Remark { get; set; } | |
| 43 | + | |
| 44 | + /// <summary> | |
| 45 | + /// 是否有效(1:有效 0:无效) | |
| 46 | + /// </summary> | |
| 47 | + [SugarColumn(ColumnName = "F_IsEffective")] | |
| 48 | + public int IsEffective { get; set; } = 1; | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 创建人ID | |
| 52 | + /// </summary> | |
| 53 | + [SugarColumn(ColumnName = "F_CreateUser")] | |
| 54 | + public string CreateUser { get; set; } | |
| 55 | + | |
| 56 | + /// <summary> | |
| 57 | + /// 创建时间 | |
| 58 | + /// </summary> | |
| 59 | + [SugarColumn(ColumnName = "F_CreateTime")] | |
| 60 | + public DateTime CreateTime { get; set; } | |
| 61 | + | |
| 62 | + /// <summary> | |
| 63 | + /// 更新人ID | |
| 64 | + /// </summary> | |
| 65 | + [SugarColumn(ColumnName = "F_UpdateUser")] | |
| 66 | + public string UpdateUser { get; set; } | |
| 67 | + | |
| 68 | + /// <summary> | |
| 69 | + /// 更新时间 | |
| 70 | + /// </summary> | |
| 71 | + [SugarColumn(ColumnName = "F_UpdateTime")] | |
| 72 | + public DateTime? UpdateTime { get; set; } | |
| 73 | + } | |
| 74 | +} | |
| 75 | + | |
| 76 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_store_consumable_inventory/LqStoreConsumableInventoryEntity.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using NCC.Common.Const; | |
| 3 | +using SqlSugar; | |
| 4 | + | |
| 5 | +namespace NCC.Extend.Entitys.lq_store_consumable_inventory | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 门店消耗品库存表 | |
| 9 | + /// </summary> | |
| 10 | + [SugarTable("lq_store_consumable_inventory")] | |
| 11 | + [Tenant(ClaimConst.TENANT_ID)] | |
| 12 | + public class LqStoreConsumableInventoryEntity | |
| 13 | + { | |
| 14 | + /// <summary> | |
| 15 | + /// 主键ID | |
| 16 | + /// </summary> | |
| 17 | + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)] | |
| 18 | + public string Id { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 门店ID(关联lq_mdxx.F_Id) | |
| 22 | + /// </summary> | |
| 23 | + [SugarColumn(ColumnName = "F_StoreId")] | |
| 24 | + public string StoreId { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 产品类型(枚举:毛巾、垫子等) | |
| 28 | + /// </summary> | |
| 29 | + [SugarColumn(ColumnName = "F_ProductType")] | |
| 30 | + public string ProductType { get; set; } | |
| 31 | + | |
| 32 | + /// <summary> | |
| 33 | + /// 当前库存数量 | |
| 34 | + /// </summary> | |
| 35 | + [SugarColumn(ColumnName = "F_Quantity")] | |
| 36 | + public int Quantity { get; set; } = 0; | |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 是否有效(1:有效 0:无效) | |
| 40 | + /// </summary> | |
| 41 | + [SugarColumn(ColumnName = "F_IsEffective")] | |
| 42 | + public int IsEffective { get; set; } = 1; | |
| 43 | + | |
| 44 | + /// <summary> | |
| 45 | + /// 创建人ID | |
| 46 | + /// </summary> | |
| 47 | + [SugarColumn(ColumnName = "F_CreateUser")] | |
| 48 | + public string CreateUser { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 创建时间 | |
| 52 | + /// </summary> | |
| 53 | + [SugarColumn(ColumnName = "F_CreateTime")] | |
| 54 | + public DateTime CreateTime { get; set; } | |
| 55 | + | |
| 56 | + /// <summary> | |
| 57 | + /// 更新人ID | |
| 58 | + /// </summary> | |
| 59 | + [SugarColumn(ColumnName = "F_UpdateUser")] | |
| 60 | + public string UpdateUser { get; set; } | |
| 61 | + | |
| 62 | + /// <summary> | |
| 63 | + /// 更新时间 | |
| 64 | + /// </summary> | |
| 65 | + [SugarColumn(ColumnName = "F_UpdateTime")] | |
| 66 | + public DateTime? UpdateTime { get; set; } | |
| 67 | + } | |
| 68 | +} | |
| 69 | + | |
| 70 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ConsumableProductTypeEnum.cs
0 → 100644
| 1 | +using System.ComponentModel; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Enum | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 消耗品产品类型枚举 | |
| 7 | + /// </summary> | |
| 8 | + public enum ConsumableProductTypeEnum | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 毛巾 | |
| 12 | + /// </summary> | |
| 13 | + [Description("毛巾")] | |
| 14 | + 毛巾 = 1, | |
| 15 | + | |
| 16 | + /// <summary> | |
| 17 | + /// 垫子 | |
| 18 | + /// </summary> | |
| 19 | + [Description("垫子")] | |
| 20 | + 垫子 = 2, | |
| 21 | + | |
| 22 | + /// <summary> | |
| 23 | + /// 浴巾 | |
| 24 | + /// </summary> | |
| 25 | + [Description("浴巾")] | |
| 26 | + 浴巾 = 3, | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 床单 | |
| 30 | + /// </summary> | |
| 31 | + [Description("床单")] | |
| 32 | + 床单 = 4, | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// 枕套 | |
| 36 | + /// </summary> | |
| 37 | + [Description("枕套")] | |
| 38 | + 枕套 = 5, | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 其他 | |
| 42 | + /// </summary> | |
| 43 | + [Description("其他")] | |
| 44 | + 其他 = 99 | |
| 45 | + } | |
| 46 | +} | |
| 47 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundryFlow/ILqLaundryFlowService.cs
0 → 100644
netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundrySupplier/ILqLaundrySupplierService.cs
0 → 100644
netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqStoreConsumableInventory/ILqStoreConsumableInventoryService.cs
0 → 100644
netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs
| ... | ... | @@ -265,8 +265,8 @@ namespace NCC.Extend |
| 265 | 265 | FROM lq_kd_kdjlb billing |
| 266 | 266 | WHERE billing.djmd = store.F_Id |
| 267 | 267 | AND billing.F_IsEffective = 1 |
| 268 | - AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd}' | |
| 269 | - AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd}' | |
| 268 | + AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd 00:00:00}' | |
| 269 | + AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd 23:59:59}' | |
| 270 | 270 | ), 0) as BillingPerformance, |
| 271 | 271 | -- 退款业绩总和(退卡业绩) |
| 272 | 272 | COALESCE(( |
| ... | ... | @@ -274,8 +274,8 @@ namespace NCC.Extend |
| 274 | 274 | FROM lq_hytk_hytk refund |
| 275 | 275 | WHERE refund.md = store.F_Id |
| 276 | 276 | AND refund.F_IsEffective = 1 |
| 277 | - AND DATE(refund.tksj) >= '{startDate:yyyy-MM-dd}' | |
| 278 | - AND DATE(refund.tksj) <= '{endDate:yyyy-MM-dd}' | |
| 277 | + AND DATE(refund.tksj) >= '{startDate:yyyy-MM-dd 00:00:00}' | |
| 278 | + AND DATE(refund.tksj) <= '{endDate:yyyy-MM-dd 23:59:59}' | |
| 279 | 279 | ), 0) as RefundPerformance |
| 280 | 280 | FROM lq_mdxx store |
| 281 | 281 | LEFT JOIN lq_md_target target ON target.F_StoreId = store.F_Id AND target.F_Month = '{month}' |
| ... | ... | @@ -1762,8 +1762,6 @@ namespace NCC.Extend |
| 1762 | 1762 | } |
| 1763 | 1763 | #endregion |
| 1764 | 1764 | |
| 1765 | - | |
| 1766 | - | |
| 1767 | 1765 | #region 获取储值扣减金额统计 |
| 1768 | 1766 | /// <summary> |
| 1769 | 1767 | /// 获取储值扣减金额统计 | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
| 1 | 1 | using System; |
| 2 | +using System.Collections.Generic; | |
| 2 | 3 | using System.Linq; |
| 3 | 4 | using System.Threading.Tasks; |
| 4 | 5 | using Microsoft.AspNetCore.Mvc; |
| ... | ... | @@ -117,6 +118,173 @@ namespace NCC.Extend |
| 117 | 118 | } |
| 118 | 119 | #endregion |
| 119 | 120 | |
| 121 | + #region 批量添加库存使用记录 | |
| 122 | + /// <summary> | |
| 123 | + /// 批量添加库存使用记录 | |
| 124 | + /// </summary> | |
| 125 | + /// <remarks> | |
| 126 | + /// 一次性添加多条库存使用记录,同一批次的所有记录使用相同的批次ID | |
| 127 | + /// | |
| 128 | + /// 示例请求: | |
| 129 | + /// ```json | |
| 130 | + /// { | |
| 131 | + /// "batchId": "可选,不传则自动生成", | |
| 132 | + /// "usageItems": [ | |
| 133 | + /// { | |
| 134 | + /// "productId": "产品ID", | |
| 135 | + /// "storeId": "门店ID", | |
| 136 | + /// "usageTime": "2024-01-01T10:00:00", | |
| 137 | + /// "usageQuantity": 10, | |
| 138 | + /// "relatedConsumeId": "关联消耗ID(可选)" | |
| 139 | + /// } | |
| 140 | + /// ] | |
| 141 | + /// } | |
| 142 | + /// ``` | |
| 143 | + /// | |
| 144 | + /// 参数说明: | |
| 145 | + /// - batchId: 批次ID,可选。如果不传,系统会自动生成一个唯一的批次ID | |
| 146 | + /// - usageItems: 使用记录列表,至少需要一条记录 | |
| 147 | + /// - productId: 产品ID(必填) | |
| 148 | + /// - storeId: 门店ID(必填) | |
| 149 | + /// - usageTime: 使用时间(必填) | |
| 150 | + /// - usageQuantity: 使用数量(必填,必须大于0) | |
| 151 | + /// - relatedConsumeId: 关联消耗ID(可选) | |
| 152 | + /// </remarks> | |
| 153 | + /// <param name="input">批量创建输入</param> | |
| 154 | + /// <returns>批量创建结果,包含批次ID和成功/失败信息</returns> | |
| 155 | + /// <response code="200">批量创建成功,返回批次ID和创建结果</response> | |
| 156 | + /// <response code="400">输入参数错误或库存不足</response> | |
| 157 | + /// <response code="500">服务器错误</response> | |
| 158 | + [HttpPost("BatchCreate")] | |
| 159 | + public async Task<LqInventoryUsageBatchCreateOutput> BatchCreateAsync([FromBody] LqInventoryUsageBatchCreateInput input) | |
| 160 | + { | |
| 161 | + try | |
| 162 | + { | |
| 163 | + if (input == null || input.UsageItems == null || !input.UsageItems.Any()) | |
| 164 | + { | |
| 165 | + throw NCCException.Oh("使用记录列表不能为空"); | |
| 166 | + } | |
| 167 | + | |
| 168 | + // 生成批次ID(如果未提供) | |
| 169 | + var batchId = string.IsNullOrWhiteSpace(input.BatchId) | |
| 170 | + ? YitIdHelper.NextId().ToString() | |
| 171 | + : input.BatchId; | |
| 172 | + | |
| 173 | + var successIds = new List<string>(); | |
| 174 | + var failItems = new List<BatchCreateFailItem>(); | |
| 175 | + | |
| 176 | + _db.Ado.BeginTran(); | |
| 177 | + | |
| 178 | + try | |
| 179 | + { | |
| 180 | + // 按产品ID分组,批量验证库存 | |
| 181 | + var productGroups = input.UsageItems | |
| 182 | + .Select((item, index) => new { Item = item, Index = index }) | |
| 183 | + .GroupBy(x => x.Item.ProductId) | |
| 184 | + .ToList(); | |
| 185 | + | |
| 186 | + // 计算每个产品的总需求并检查库存 | |
| 187 | + foreach (var productGroup in productGroups) | |
| 188 | + { | |
| 189 | + var productId = productGroup.Key; | |
| 190 | + var totalRequired = productGroup.Sum(x => x.Item.UsageQuantity); | |
| 191 | + | |
| 192 | + // 计算该产品的总库存数量 | |
| 193 | + var totalInventory = await _db.Queryable<LqInventoryEntity>() | |
| 194 | + .Where(x => x.ProductId == productId && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 195 | + .SumAsync(x => (int?)x.Quantity) ?? 0; | |
| 196 | + | |
| 197 | + // 计算该产品的已使用数量 | |
| 198 | + var totalUsage = await _db.Queryable<LqInventoryUsageEntity>() | |
| 199 | + .Where(x => x.ProductId == productId && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 200 | + .SumAsync(x => (int?)x.UsageQuantity) ?? 0; | |
| 201 | + | |
| 202 | + // 计算可用库存 | |
| 203 | + var availableInventory = totalInventory - totalUsage; | |
| 204 | + | |
| 205 | + // 检查库存是否足够 | |
| 206 | + if (availableInventory < totalRequired) | |
| 207 | + { | |
| 208 | + var failIndices = productGroup.Select(x => x.Index).ToList(); | |
| 209 | + | |
| 210 | + foreach (var index in failIndices) | |
| 211 | + { | |
| 212 | + failItems.Add(new BatchCreateFailItem | |
| 213 | + { | |
| 214 | + Index = index, | |
| 215 | + ProductId = productId, | |
| 216 | + Reason = $"库存不足,当前可用库存:{availableInventory},需要数量:{totalRequired}" | |
| 217 | + }); | |
| 218 | + } | |
| 219 | + } | |
| 220 | + } | |
| 221 | + | |
| 222 | + // 创建成功的使用记录 | |
| 223 | + var entitiesToInsert = new List<LqInventoryUsageEntity>(); | |
| 224 | + for (int i = 0; i < input.UsageItems.Count; i++) | |
| 225 | + { | |
| 226 | + var item = input.UsageItems[i]; | |
| 227 | + | |
| 228 | + // 跳过失败项 | |
| 229 | + if (failItems.Any(x => x.Index == i)) | |
| 230 | + { | |
| 231 | + continue; | |
| 232 | + } | |
| 233 | + | |
| 234 | + var usageEntity = new LqInventoryUsageEntity | |
| 235 | + { | |
| 236 | + Id = YitIdHelper.NextId().ToString(), | |
| 237 | + ProductId = item.ProductId, | |
| 238 | + StoreId = item.StoreId, | |
| 239 | + UsageTime = item.UsageTime, | |
| 240 | + UsageQuantity = item.UsageQuantity, | |
| 241 | + RelatedConsumeId = item.RelatedConsumeId, | |
| 242 | + UsageBatchId = batchId, | |
| 243 | + CreateUser = _userManager.UserId, | |
| 244 | + CreateTime = DateTime.Now, | |
| 245 | + IsEffective = StatusEnum.有效.GetHashCode() | |
| 246 | + }; | |
| 247 | + | |
| 248 | + entitiesToInsert.Add(usageEntity); | |
| 249 | + successIds.Add(usageEntity.Id); | |
| 250 | + } | |
| 251 | + | |
| 252 | + // 批量插入 | |
| 253 | + if (entitiesToInsert.Any()) | |
| 254 | + { | |
| 255 | + var insertCount = await _db.Insertable(entitiesToInsert).ExecuteCommandAsync(); | |
| 256 | + if (insertCount != entitiesToInsert.Count) | |
| 257 | + { | |
| 258 | + throw NCCException.Oh($"批量插入失败,预期插入{entitiesToInsert.Count}条,实际插入{insertCount}条"); | |
| 259 | + } | |
| 260 | + } | |
| 261 | + | |
| 262 | + _db.Ado.CommitTran(); | |
| 263 | + | |
| 264 | + return new LqInventoryUsageBatchCreateOutput | |
| 265 | + { | |
| 266 | + BatchId = batchId, | |
| 267 | + SuccessCount = successIds.Count, | |
| 268 | + FailCount = failItems.Count, | |
| 269 | + SuccessIds = successIds, | |
| 270 | + FailItems = failItems | |
| 271 | + }; | |
| 272 | + } | |
| 273 | + catch | |
| 274 | + { | |
| 275 | + _db.Ado.RollbackTran(); | |
| 276 | + throw; | |
| 277 | + } | |
| 278 | + } | |
| 279 | + catch (Exception ex) | |
| 280 | + { | |
| 281 | + _db.Ado.RollbackTran(); | |
| 282 | + _logger.LogError(ex, "批量添加库存使用记录失败"); | |
| 283 | + throw NCCException.Oh($"批量添加失败:{ex.Message}"); | |
| 284 | + } | |
| 285 | + } | |
| 286 | + #endregion | |
| 287 | + | |
| 120 | 288 | #region 作废库存使用记录 |
| 121 | 289 | /// <summary> |
| 122 | 290 | /// 作废库存使用记录 |
| ... | ... | @@ -185,6 +353,7 @@ namespace NCC.Extend |
| 185 | 353 | .WhereIF(input.UsageStartTime.HasValue, (usage, product) => usage.UsageTime >= input.UsageStartTime.Value) |
| 186 | 354 | .WhereIF(input.UsageEndTime.HasValue, (usage, product) => usage.UsageTime <= input.UsageEndTime.Value) |
| 187 | 355 | .WhereIF(!string.IsNullOrWhiteSpace(input.RelatedConsumeId), (usage, product) => usage.RelatedConsumeId == input.RelatedConsumeId) |
| 356 | + .WhereIF(!string.IsNullOrWhiteSpace(input.UsageBatchId), (usage, product) => usage.UsageBatchId == input.UsageBatchId) | |
| 188 | 357 | .WhereIF(input.IsEffective.HasValue, (usage, product) => usage.IsEffective == input.IsEffective.Value) |
| 189 | 358 | .Select((usage, product) => new LqInventoryUsageListOutput |
| 190 | 359 | { |
| ... | ... | @@ -198,6 +367,7 @@ namespace NCC.Extend |
| 198 | 367 | usageTime = usage.UsageTime, |
| 199 | 368 | usageQuantity = usage.UsageQuantity, |
| 200 | 369 | relatedConsumeId = usage.RelatedConsumeId, |
| 370 | + usageBatchId = usage.UsageBatchId, | |
| 201 | 371 | createUser = usage.CreateUser, |
| 202 | 372 | createUserName = "", |
| 203 | 373 | createTime = usage.CreateTime, |
| ... | ... | @@ -258,6 +428,129 @@ namespace NCC.Extend |
| 258 | 428 | } |
| 259 | 429 | #endregion |
| 260 | 430 | |
| 431 | + #region 根据批次号获取批次信息 | |
| 432 | + /// <summary> | |
| 433 | + /// 根据批次号获取批次信息 | |
| 434 | + /// </summary> | |
| 435 | + /// <remarks> | |
| 436 | + /// 根据批次ID查询该批次的所有使用记录信息,包括批次基本信息和详细的使用记录列表 | |
| 437 | + /// | |
| 438 | + /// 返回数据结构: | |
| 439 | + /// - 批次基本信息:批次ID、创建时间、创建人、统计信息等 | |
| 440 | + /// - 使用记录列表:该批次的所有使用记录详情 | |
| 441 | + /// | |
| 442 | + /// 参数说明: | |
| 443 | + /// - batchId: 批次ID(必填) | |
| 444 | + /// </remarks> | |
| 445 | + /// <param name="batchId">批次ID</param> | |
| 446 | + /// <returns>批次信息,包含该批次的所有使用记录</returns> | |
| 447 | + /// <response code="200">查询成功,返回批次信息和使用记录列表</response> | |
| 448 | + /// <response code="400">批次ID不能为空</response> | |
| 449 | + /// <response code="404">批次不存在</response> | |
| 450 | + /// <response code="500">服务器错误</response> | |
| 451 | + [HttpGet("GetBatchInfo")] | |
| 452 | + public async Task<LqInventoryUsageBatchInfoOutput> GetBatchInfoAsync([FromQuery] string batchId) | |
| 453 | + { | |
| 454 | + try | |
| 455 | + { | |
| 456 | + if (string.IsNullOrWhiteSpace(batchId)) | |
| 457 | + { | |
| 458 | + throw NCCException.Oh("批次ID不能为空"); | |
| 459 | + } | |
| 460 | + | |
| 461 | + // 查询该批次的所有使用记录 | |
| 462 | + var usageRecords = await _db.Queryable<LqInventoryUsageEntity, LqProductEntity>( | |
| 463 | + (usage, product) => usage.ProductId == product.Id) | |
| 464 | + .LeftJoin<LqMdxxEntity>((usage, product, store) => usage.StoreId == store.Id) | |
| 465 | + .Where((usage, product, store) => usage.UsageBatchId == batchId) | |
| 466 | + .Select((usage, product, store) => new LqInventoryUsageListOutput | |
| 467 | + { | |
| 468 | + id = usage.Id, | |
| 469 | + productId = usage.ProductId, | |
| 470 | + productName = product.ProductName, | |
| 471 | + productCategory = product.ProductCategory, | |
| 472 | + productPrice = product.Price, | |
| 473 | + storeId = usage.StoreId, | |
| 474 | + storeName = store.Dm, | |
| 475 | + usageTime = usage.UsageTime, | |
| 476 | + usageQuantity = usage.UsageQuantity, | |
| 477 | + relatedConsumeId = usage.RelatedConsumeId, | |
| 478 | + usageBatchId = usage.UsageBatchId, | |
| 479 | + createUser = usage.CreateUser, | |
| 480 | + createUserName = "", | |
| 481 | + createTime = usage.CreateTime, | |
| 482 | + updateUser = usage.UpdateUser, | |
| 483 | + updateUserName = "", | |
| 484 | + updateTime = usage.UpdateTime, | |
| 485 | + isEffective = usage.IsEffective | |
| 486 | + }) | |
| 487 | + .MergeTable() | |
| 488 | + .OrderBy("createTime") | |
| 489 | + .ToListAsync(); | |
| 490 | + | |
| 491 | + if (!usageRecords.Any()) | |
| 492 | + { | |
| 493 | + throw NCCException.Oh("批次不存在或该批次下没有使用记录"); | |
| 494 | + } | |
| 495 | + | |
| 496 | + // 补充用户信息 | |
| 497 | + var userIds = usageRecords.SelectMany(x => new[] { x.createUser, x.updateUser }) | |
| 498 | + .Where(x => !string.IsNullOrEmpty(x)) | |
| 499 | + .Distinct() | |
| 500 | + .ToList(); | |
| 501 | + | |
| 502 | + if (userIds.Any()) | |
| 503 | + { | |
| 504 | + var userList = await _db.Queryable<UserEntity>() | |
| 505 | + .Where(x => userIds.Contains(x.Id)) | |
| 506 | + .Select(x => new { x.Id, x.RealName }) | |
| 507 | + .ToListAsync(); | |
| 508 | + var userDict = userList.ToDictionary(k => k.Id, v => v.RealName); | |
| 509 | + | |
| 510 | + foreach (var item in usageRecords) | |
| 511 | + { | |
| 512 | + if (!string.IsNullOrEmpty(item.createUser) && userDict.ContainsKey(item.createUser)) | |
| 513 | + item.createUserName = userDict[item.createUser]; | |
| 514 | + if (!string.IsNullOrEmpty(item.updateUser) && userDict.ContainsKey(item.updateUser)) | |
| 515 | + item.updateUserName = userDict[item.updateUser]; | |
| 516 | + } | |
| 517 | + } | |
| 518 | + | |
| 519 | + // 计算使用总金额 | |
| 520 | + foreach (var record in usageRecords) | |
| 521 | + { | |
| 522 | + record.usageTotalValue = record.usageQuantity * record.productPrice; | |
| 523 | + } | |
| 524 | + | |
| 525 | + // 获取批次基本信息(使用第一条记录的创建信息) | |
| 526 | + var firstRecord = usageRecords.OrderBy(x => x.createTime).First(); | |
| 527 | + var effectiveRecords = usageRecords.Where(x => x.isEffective == StatusEnum.有效.GetHashCode()).ToList(); | |
| 528 | + var ineffectiveRecords = usageRecords.Where(x => x.isEffective == StatusEnum.无效.GetHashCode()).ToList(); | |
| 529 | + | |
| 530 | + var batchInfo = new LqInventoryUsageBatchInfoOutput | |
| 531 | + { | |
| 532 | + BatchId = batchId, | |
| 533 | + CreateTime = firstRecord.createTime, | |
| 534 | + CreateUser = firstRecord.createUser, | |
| 535 | + CreateUserName = firstRecord.createUserName, | |
| 536 | + TotalCount = usageRecords.Count, | |
| 537 | + EffectiveCount = effectiveRecords.Count, | |
| 538 | + IneffectiveCount = ineffectiveRecords.Count, | |
| 539 | + TotalUsageQuantity = effectiveRecords.Sum(x => x.usageQuantity), | |
| 540 | + TotalUsageAmount = effectiveRecords.Sum(x => x.usageTotalValue), | |
| 541 | + UsageRecords = usageRecords | |
| 542 | + }; | |
| 543 | + | |
| 544 | + return batchInfo; | |
| 545 | + } | |
| 546 | + catch (Exception ex) | |
| 547 | + { | |
| 548 | + _logger.LogError(ex, "获取批次信息失败"); | |
| 549 | + throw NCCException.Oh($"获取批次信息失败:{ex.Message}"); | |
| 550 | + } | |
| 551 | + } | |
| 552 | + #endregion | |
| 553 | + | |
| 261 | 554 | #region 统计时间周期内每个产品的使用数量 |
| 262 | 555 | /// <summary> |
| 263 | 556 | /// 统计时间周期内每个产品的使用数量 | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
| ... | ... | @@ -3099,22 +3099,22 @@ namespace NCC.Extend.LqKdKdjlb |
| 3099 | 3099 | // 查询购买数量 |
| 3100 | 3100 | var purchasedCount = await _db.Queryable<LqKdPxmxEntity>() |
| 3101 | 3101 | .Where(x => x.Id == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()) |
| 3102 | - .SumAsync(x => x.ProjectNumber); | |
| 3102 | + .SumAsync(x => (decimal?)x.ProjectNumber) ?? 0m; | |
| 3103 | 3103 | |
| 3104 | 3104 | // 查询消费数量 |
| 3105 | 3105 | var consumedCount = await _db.Queryable<LqXhPxmxEntity>() |
| 3106 | 3106 | .Where(x => x.BillingItemId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()) |
| 3107 | - .SumAsync(x => x.OriginalProjectNumber); | |
| 3107 | + .SumAsync(x => x.OriginalProjectNumber) ?? 0m; | |
| 3108 | 3108 | |
| 3109 | 3109 | // 查询退卡数量 |
| 3110 | 3110 | var refundedCount = await _db.Queryable<LqHytkMxEntity>() |
| 3111 | 3111 | .Where(x => x.BillingItemId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()) |
| 3112 | - .SumAsync(x => x.ProjectNumber); | |
| 3112 | + .SumAsync(x => (decimal?)x.ProjectNumber) ?? 0m; | |
| 3113 | 3113 | |
| 3114 | 3114 | // 查询储扣数量 |
| 3115 | 3115 | var deductCount = await _db.Queryable<LqKdDeductinfoEntity>() |
| 3116 | 3116 | .Where(x => x.DeductId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()) |
| 3117 | - .SumAsync(x => x.ProjectNumber) ?? 0; | |
| 3117 | + .SumAsync(x => (decimal?)x.ProjectNumber) ?? 0m; | |
| 3118 | 3118 | |
| 3119 | 3119 | // 计算剩余数量 |
| 3120 | 3120 | var remainingCount = (int)(purchasedCount - consumedCount - refundedCount - deductCount); |
| ... | ... | @@ -3460,15 +3460,34 @@ namespace NCC.Extend.LqKdKdjlb |
| 3460 | 3460 | var sidx = input.sidx == null ? "yjsj" : input.sidx; |
| 3461 | 3461 | var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort; |
| 3462 | 3462 | |
| 3463 | - // 处理开单时间范围 | |
| 3464 | - List<string> queryBillingTime = null; | |
| 3463 | + // 处理开单时间范围(兼容 StartBillingTime/EndBillingTime 和 startTime/endTime 两种参数名) | |
| 3465 | 3464 | DateTime? startBillingTime = null; |
| 3466 | 3465 | DateTime? endBillingTime = null; |
| 3467 | - if (!string.IsNullOrEmpty(input.StartBillingTime) && !string.IsNullOrEmpty(input.EndBillingTime)) | |
| 3466 | + | |
| 3467 | + // 优先使用 StartBillingTime/EndBillingTime,如果没有则使用 startTime/endTime | |
| 3468 | + string startTimeStr = !string.IsNullOrEmpty(input.StartBillingTime) ? input.StartBillingTime : input.startTime; | |
| 3469 | + string endTimeStr = !string.IsNullOrEmpty(input.EndBillingTime) ? input.EndBillingTime : input.endTime; | |
| 3470 | + | |
| 3471 | + if (!string.IsNullOrEmpty(startTimeStr) && !string.IsNullOrEmpty(endTimeStr)) | |
| 3468 | 3472 | { |
| 3469 | - queryBillingTime = new List<string> { input.StartBillingTime, input.EndBillingTime }; | |
| 3470 | - startBillingTime = Ext.GetDateTime(queryBillingTime.First()); | |
| 3471 | - endBillingTime = Ext.GetDateTime(queryBillingTime.Last()); | |
| 3473 | + // 尝试解析日期字符串(支持多种格式) | |
| 3474 | + if (DateTime.TryParse(startTimeStr, out DateTime startDate)) | |
| 3475 | + { | |
| 3476 | + startBillingTime = startDate; | |
| 3477 | + } | |
| 3478 | + else | |
| 3479 | + { | |
| 3480 | + throw NCCException.Oh($"开始时间格式错误:{startTimeStr}"); | |
| 3481 | + } | |
| 3482 | + | |
| 3483 | + if (DateTime.TryParse(endTimeStr, out DateTime endDate)) | |
| 3484 | + { | |
| 3485 | + endBillingTime = endDate; | |
| 3486 | + } | |
| 3487 | + else | |
| 3488 | + { | |
| 3489 | + throw NCCException.Oh($"结束时间格式错误:{endTimeStr}"); | |
| 3490 | + } | |
| 3472 | 3491 | } |
| 3473 | 3492 | |
| 3474 | 3493 | // 优化查询:先分页查询主表,再批量查询关联数据,避免子查询性能问题 |
| ... | ... | @@ -3477,18 +3496,18 @@ namespace NCC.Extend.LqKdKdjlb |
| 3477 | 3496 | .Where(pxmx => pxmx.IsEffective == StatusEnum.有效.GetHashCode()) |
| 3478 | 3497 | .WhereIF(!string.IsNullOrEmpty(input.Id), pxmx => pxmx.Id == input.Id) |
| 3479 | 3498 | .WhereIF(!string.IsNullOrEmpty(input.BillingId), pxmx => pxmx.Glkdbh == input.BillingId) |
| 3480 | - .WhereIF(queryBillingTime != null && startBillingTime.HasValue, pxmx => pxmx.Yjsj >= new DateTime(startBillingTime.Value.Year, startBillingTime.Value.Month, startBillingTime.Value.Day, 0, 0, 0)) | |
| 3481 | - .WhereIF(queryBillingTime != null && endBillingTime.HasValue, pxmx => pxmx.Yjsj <= new DateTime(endBillingTime.Value.Year, endBillingTime.Value.Month, endBillingTime.Value.Day, 23, 59, 59)) | |
| 3499 | + .WhereIF(startBillingTime.HasValue, pxmx => pxmx.Yjsj >= new DateTime(startBillingTime.Value.Year, startBillingTime.Value.Month, startBillingTime.Value.Day, 0, 0, 0)) | |
| 3500 | + .WhereIF(endBillingTime.HasValue, pxmx => pxmx.Yjsj <= new DateTime(endBillingTime.Value.Year, endBillingTime.Value.Month, endBillingTime.Value.Day, 23, 59, 59)) | |
| 3482 | 3501 | .WhereIF(!string.IsNullOrEmpty(input.ActivityId), pxmx => pxmx.ActivityId == input.ActivityId) |
| 3483 | 3502 | .WhereIF(!string.IsNullOrEmpty(input.MemberId), pxmx => pxmx.MemberId == input.MemberId) |
| 3484 | 3503 | .WhereIF(!string.IsNullOrEmpty(input.ItemId), pxmx => pxmx.Px == input.ItemId) |
| 3485 | 3504 | .WhereIF(!string.IsNullOrEmpty(input.ItemName), pxmx => pxmx.Pxmc != null && pxmx.Pxmc.Contains(input.ItemName)) |
| 3486 | - .WhereIF(!string.IsNullOrEmpty(input.SourceType), pxmx => pxmx.SourceType == input.SourceType); | |
| 3505 | + .WhereIF(!string.IsNullOrEmpty(input.SourceType), pxmx => pxmx.SourceType == input.SourceType) | |
| 3506 | + .WhereIF(!string.IsNullOrEmpty(input.ItemType), pxmx => pxmx.ItemCategory == input.ItemType); | |
| 3487 | 3507 | |
| 3488 | 3508 | // 2. 通过 EXISTS 子查询筛选关联字段(在分页前筛选,确保分页准确) |
| 3489 | 3509 | baseQuery = baseQuery.WhereIF(!string.IsNullOrEmpty(input.MemberName), pxmx => SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == pxmx.MemberId && x.Khmc != null && x.Khmc.Contains(input.MemberName)).Any()) |
| 3490 | 3510 | .WhereIF(!string.IsNullOrEmpty(input.MemberPhone), pxmx => SqlFunc.Subqueryable<LqKhxxEntity>().Where(x => x.Id == pxmx.MemberId && x.Sjh == input.MemberPhone).Any()) |
| 3491 | - .WhereIF(!string.IsNullOrEmpty(input.ItemType), pxmx => SqlFunc.Subqueryable<LqXmzlEntity>().Where(x => x.Id == pxmx.Px && x.Fl4 == input.ItemType).Any()) | |
| 3492 | 3511 | .WhereIF(!string.IsNullOrEmpty(input.StoreId), pxmx => SqlFunc.Subqueryable<LqKdKdjlbEntity>().Where(x => x.Id == pxmx.Glkdbh && x.Djmd == input.StoreId).Any()); |
| 3493 | 3512 | |
| 3494 | 3513 | // 3. 先分页查询主表数据(查询实体类,提高性能) |
| ... | ... | @@ -3498,7 +3517,6 @@ namespace NCC.Extend.LqKdKdjlb |
| 3498 | 3517 | var itemIds = pagedData.list.Select(x => x.Id).ToList(); |
| 3499 | 3518 | var memberIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.MemberId)).Select(x => x.MemberId).Distinct().ToList(); |
| 3500 | 3519 | var activityIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.ActivityId)).Select(x => x.ActivityId).Distinct().ToList(); |
| 3501 | - var projectIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.Px)).Select(x => x.Px).Distinct().ToList(); | |
| 3502 | 3520 | var billingIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.Glkdbh)).Select(x => x.Glkdbh).Distinct().ToList(); |
| 3503 | 3521 | |
| 3504 | 3522 | // 批量查询会员信息 |
| ... | ... | @@ -3517,14 +3535,6 @@ namespace NCC.Extend.LqKdKdjlb |
| 3517 | 3535 | activityDict = activities.ToDictionary(x => x.Id, x => x.ActivityName ?? ""); |
| 3518 | 3536 | } |
| 3519 | 3537 | |
| 3520 | - // 批量查询项目资料 | |
| 3521 | - var projectDict = new Dictionary<string, string>(); | |
| 3522 | - if (projectIds.Any()) | |
| 3523 | - { | |
| 3524 | - var projects = await _db.Queryable<LqXmzlEntity>().Where(x => projectIds.Contains(x.Id)).Select(x => new { x.Id, x.Qt2 }).ToListAsync(); | |
| 3525 | - projectDict = projects.ToDictionary(x => x.Id, x => x.Qt2 ?? ""); | |
| 3526 | - } | |
| 3527 | - | |
| 3528 | 3538 | // 批量查询开单记录,获取门店ID |
| 3529 | 3539 | var billingStoreDict = new Dictionary<string, string>(); |
| 3530 | 3540 | if (billingIds.Any()) |
| ... | ... | @@ -3552,7 +3562,7 @@ namespace NCC.Extend.LqKdKdjlb |
| 3552 | 3562 | memberName = pxmx.MemberId != null && memberDict.ContainsKey(pxmx.MemberId) ? memberDict[pxmx.MemberId].Name : "", |
| 3553 | 3563 | memberPhone = pxmx.MemberId != null && memberDict.ContainsKey(pxmx.MemberId) ? memberDict[pxmx.MemberId].Phone : "", |
| 3554 | 3564 | itemName = pxmx.Pxmc, |
| 3555 | - itemType = pxmx.Px != null && projectDict.ContainsKey(pxmx.Px) ? projectDict[pxmx.Px] : "", | |
| 3565 | + itemType = pxmx.ItemCategory, | |
| 3556 | 3566 | actualPrice = pxmx.ActualPrice, |
| 3557 | 3567 | projectNumber = pxmx.ProjectNumber, |
| 3558 | 3568 | sourceType = pxmx.SourceType, | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqLaundryFlowService.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Threading.Tasks; | |
| 5 | +using Microsoft.AspNetCore.Mvc; | |
| 6 | +using Microsoft.Extensions.Logging; | |
| 7 | +using NCC.Common.Core.Manager; | |
| 8 | +using NCC.Common.Enum; | |
| 9 | +using NCC.Common.Filter; | |
| 10 | +using NCC.Dependency; | |
| 11 | +using NCC.DynamicApiController; | |
| 12 | +using NCC.Extend.Entitys.Dto.LqLaundryFlow; | |
| 13 | +using NCC.Extend.Entitys.Enum; | |
| 14 | +using NCC.Extend.Entitys.lq_laundry_flow; | |
| 15 | +using NCC.Extend.Entitys.lq_laundry_supplier; | |
| 16 | +using NCC.Extend.Entitys.lq_mdxx; | |
| 17 | +using NCC.Extend.Interfaces.LqLaundryFlow; | |
| 18 | +using NCC.FriendlyException; | |
| 19 | +using NCC.System.Entitys.Permission; | |
| 20 | +using SqlSugar; | |
| 21 | +using Yitter.IdGenerator; | |
| 22 | + | |
| 23 | +namespace NCC.Extend | |
| 24 | +{ | |
| 25 | + /// <summary> | |
| 26 | + /// 清洗流水服务 | |
| 27 | + /// </summary> | |
| 28 | + [ApiDescriptionSettings(Tag = "绿纤清洗流水管理", Name = "LqLaundryFlow", Order = 200)] | |
| 29 | + [Route("api/Extend/LqLaundryFlow")] | |
| 30 | + public class LqLaundryFlowService : IDynamicApiController, ITransient, ILqLaundryFlowService | |
| 31 | + { | |
| 32 | + private readonly IUserManager _userManager; | |
| 33 | + private readonly ILogger<LqLaundryFlowService> _logger; | |
| 34 | + private readonly ISqlSugarClient _db; | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 构造函数 | |
| 38 | + /// </summary> | |
| 39 | + public LqLaundryFlowService(IUserManager userManager, ILogger<LqLaundryFlowService> logger, ISqlSugarClient db) | |
| 40 | + { | |
| 41 | + _userManager = userManager; | |
| 42 | + _logger = logger; | |
| 43 | + _db = db; | |
| 44 | + } | |
| 45 | + | |
| 46 | + #region 创建送出记录 | |
| 47 | + /// <summary> | |
| 48 | + /// 创建送出记录 | |
| 49 | + /// </summary> | |
| 50 | + /// <remarks> | |
| 51 | + /// 门店选择清洗商和产品,填写送出数量,创建送出记录 | |
| 52 | + /// | |
| 53 | + /// 示例请求: | |
| 54 | + /// ```json | |
| 55 | + /// { | |
| 56 | + /// "storeId": "门店ID", | |
| 57 | + /// "productType": "毛巾", | |
| 58 | + /// "laundrySupplierId": "清洗商ID", | |
| 59 | + /// "quantity": 100, | |
| 60 | + /// "remark": "备注" | |
| 61 | + /// } | |
| 62 | + /// ``` | |
| 63 | + /// </remarks> | |
| 64 | + /// <param name="input">送出输入</param> | |
| 65 | + /// <returns>创建结果(包含批次号)</returns> | |
| 66 | + /// <response code="200">创建成功</response> | |
| 67 | + /// <response code="400">参数错误或清洗商不存在</response> | |
| 68 | + /// <response code="500">服务器错误</response> | |
| 69 | + [HttpPost("Send")] | |
| 70 | + public async Task<dynamic> SendAsync([FromBody] LqLaundryFlowSendInput input) | |
| 71 | + { | |
| 72 | + try | |
| 73 | + { | |
| 74 | + // 验证门店是否存在 | |
| 75 | + var store = await _db.Queryable<LqMdxxEntity>() | |
| 76 | + .Where(x => x.Id == input.StoreId) | |
| 77 | + .FirstAsync(); | |
| 78 | + | |
| 79 | + if (store == null) | |
| 80 | + { | |
| 81 | + throw NCCException.Oh("门店不存在"); | |
| 82 | + } | |
| 83 | + | |
| 84 | + // 验证清洗商是否存在 | |
| 85 | + var supplier = await _db.Queryable<LqLaundrySupplierEntity>() | |
| 86 | + .Where(x => x.Id == input.LaundrySupplierId && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 87 | + .FirstAsync(); | |
| 88 | + | |
| 89 | + if (supplier == null) | |
| 90 | + { | |
| 91 | + throw NCCException.Oh("清洗商不存在或已失效"); | |
| 92 | + } | |
| 93 | + | |
| 94 | + // 验证产品类型是否匹配 | |
| 95 | + if (supplier.ProductType != input.ProductType) | |
| 96 | + { | |
| 97 | + throw NCCException.Oh($"清洗商【{supplier.SupplierName}】不支持清洗产品类型【{input.ProductType}】"); | |
| 98 | + } | |
| 99 | + | |
| 100 | + // 生成批次号(使用ID) | |
| 101 | + var batchId = YitIdHelper.NextId().ToString(); | |
| 102 | + | |
| 103 | + // 创建送出记录 | |
| 104 | + var entity = new LqLaundryFlowEntity | |
| 105 | + { | |
| 106 | + Id = batchId, | |
| 107 | + FlowType = 0, // 送出 | |
| 108 | + BatchNumber = batchId, // 批次号等于ID | |
| 109 | + StoreId = input.StoreId, | |
| 110 | + ProductType = input.ProductType, | |
| 111 | + LaundrySupplierId = input.LaundrySupplierId, | |
| 112 | + Quantity = input.Quantity, | |
| 113 | + LaundryPrice = supplier.LaundryPrice, // 记录历史价格 | |
| 114 | + TotalPrice = 0, // 送出时总费用为0 | |
| 115 | + Remark = input.Remark, | |
| 116 | + IsEffective = StatusEnum.有效.GetHashCode(), | |
| 117 | + CreateUser = _userManager.UserId, | |
| 118 | + CreateTime = DateTime.Now | |
| 119 | + }; | |
| 120 | + | |
| 121 | + var isOk = await _db.Insertable(entity).ExecuteCommandAsync(); | |
| 122 | + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); | |
| 123 | + | |
| 124 | + return new { batchNumber = batchId, message = "送出记录创建成功" }; | |
| 125 | + } | |
| 126 | + catch (Exception ex) | |
| 127 | + { | |
| 128 | + _logger.LogError(ex, "创建送出记录失败"); | |
| 129 | + throw NCCException.Oh($"创建失败:{ex.Message}"); | |
| 130 | + } | |
| 131 | + } | |
| 132 | + #endregion | |
| 133 | + | |
| 134 | + #region 创建送回记录 | |
| 135 | + /// <summary> | |
| 136 | + /// 创建送回记录 | |
| 137 | + /// </summary> | |
| 138 | + /// <remarks> | |
| 139 | + /// 清洗完毕后,填写送回清洗商、送回数量,创建送回记录 | |
| 140 | + /// | |
| 141 | + /// 示例请求: | |
| 142 | + /// ```json | |
| 143 | + /// { | |
| 144 | + /// "batchNumber": "批次号(对应的送出记录的ID)", | |
| 145 | + /// "laundrySupplierId": "清洗商ID", | |
| 146 | + /// "quantity": 95, | |
| 147 | + /// "remark": "5条损坏" | |
| 148 | + /// } | |
| 149 | + /// ``` | |
| 150 | + /// </remarks> | |
| 151 | + /// <param name="input">送回输入</param> | |
| 152 | + /// <returns>创建结果</returns> | |
| 153 | + /// <response code="200">创建成功</response> | |
| 154 | + /// <response code="400">批次号不存在或参数错误</response> | |
| 155 | + /// <response code="500">服务器错误</response> | |
| 156 | + [HttpPost("Return")] | |
| 157 | + public async Task<dynamic> ReturnAsync([FromBody] LqLaundryFlowReturnInput input) | |
| 158 | + { | |
| 159 | + try | |
| 160 | + { | |
| 161 | + // 验证对应的送出记录是否存在 | |
| 162 | + var sendRecord = await _db.Queryable<LqLaundryFlowEntity>() | |
| 163 | + .Where(x => x.BatchNumber == input.BatchNumber && x.FlowType == 0 && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 164 | + .FirstAsync(); | |
| 165 | + | |
| 166 | + if (sendRecord == null) | |
| 167 | + { | |
| 168 | + throw NCCException.Oh("对应的送出记录不存在或已失效"); | |
| 169 | + } | |
| 170 | + | |
| 171 | + // 检查是否已经存在送回记录 | |
| 172 | + var existingReturn = await _db.Queryable<LqLaundryFlowEntity>() | |
| 173 | + .Where(x => x.BatchNumber == input.BatchNumber && x.FlowType == 1 && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 174 | + .FirstAsync(); | |
| 175 | + | |
| 176 | + if (existingReturn != null) | |
| 177 | + { | |
| 178 | + throw NCCException.Oh("该批次已存在送回记录"); | |
| 179 | + } | |
| 180 | + | |
| 181 | + // 验证清洗商是否存在 | |
| 182 | + var supplier = await _db.Queryable<LqLaundrySupplierEntity>() | |
| 183 | + .Where(x => x.Id == input.LaundrySupplierId && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 184 | + .FirstAsync(); | |
| 185 | + | |
| 186 | + if (supplier == null) | |
| 187 | + { | |
| 188 | + throw NCCException.Oh("清洗商不存在或已失效"); | |
| 189 | + } | |
| 190 | + | |
| 191 | + // 验证产品类型是否匹配 | |
| 192 | + if (supplier.ProductType != sendRecord.ProductType) | |
| 193 | + { | |
| 194 | + throw NCCException.Oh($"清洗商【{supplier.SupplierName}】不支持清洗产品类型【{sendRecord.ProductType}】"); | |
| 195 | + } | |
| 196 | + | |
| 197 | + // 计算总费用(送回数量 × 清洗单价) | |
| 198 | + var totalPrice = input.Quantity * supplier.LaundryPrice; | |
| 199 | + | |
| 200 | + // 创建送回记录 | |
| 201 | + var entity = new LqLaundryFlowEntity | |
| 202 | + { | |
| 203 | + Id = YitIdHelper.NextId().ToString(), | |
| 204 | + FlowType = 1, // 送回 | |
| 205 | + BatchNumber = input.BatchNumber, // 使用送出记录的批次号 | |
| 206 | + StoreId = sendRecord.StoreId, | |
| 207 | + ProductType = sendRecord.ProductType, | |
| 208 | + LaundrySupplierId = input.LaundrySupplierId, | |
| 209 | + Quantity = input.Quantity, | |
| 210 | + LaundryPrice = supplier.LaundryPrice, // 记录历史价格(可能已变化) | |
| 211 | + TotalPrice = totalPrice, | |
| 212 | + Remark = input.Remark, | |
| 213 | + IsEffective = StatusEnum.有效.GetHashCode(), | |
| 214 | + CreateUser = _userManager.UserId, | |
| 215 | + CreateTime = DateTime.Now | |
| 216 | + }; | |
| 217 | + | |
| 218 | + var isOk = await _db.Insertable(entity).ExecuteCommandAsync(); | |
| 219 | + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); | |
| 220 | + | |
| 221 | + return new { message = "送回记录创建成功", totalPrice = totalPrice }; | |
| 222 | + } | |
| 223 | + catch (Exception ex) | |
| 224 | + { | |
| 225 | + _logger.LogError(ex, "创建送回记录失败"); | |
| 226 | + throw NCCException.Oh($"创建失败:{ex.Message}"); | |
| 227 | + } | |
| 228 | + } | |
| 229 | + #endregion | |
| 230 | + | |
| 231 | + #region 获取清洗流水列表 | |
| 232 | + /// <summary> | |
| 233 | + /// 获取清洗流水列表 | |
| 234 | + /// </summary> | |
| 235 | + /// <remarks> | |
| 236 | + /// 分页查询清洗流水列表,支持按流水类型、批次号、门店、产品类型、清洗商、时间范围筛选 | |
| 237 | + /// </remarks> | |
| 238 | + /// <param name="input">查询输入</param> | |
| 239 | + /// <returns>清洗流水列表</returns> | |
| 240 | + /// <response code="200">查询成功</response> | |
| 241 | + /// <response code="500">服务器错误</response> | |
| 242 | + [HttpGet("GetList")] | |
| 243 | + public async Task<dynamic> GetListAsync([FromQuery] LqLaundryFlowListQueryInput input) | |
| 244 | + { | |
| 245 | + try | |
| 246 | + { | |
| 247 | + var sidx = string.IsNullOrEmpty(input.sidx) ? "createTime" : input.sidx; | |
| 248 | + var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; | |
| 249 | + | |
| 250 | + var data = await _db.Queryable<LqLaundryFlowEntity, LqMdxxEntity, LqLaundrySupplierEntity>( | |
| 251 | + (flow, store, supplier) => flow.StoreId == store.Id && flow.LaundrySupplierId == supplier.Id) | |
| 252 | + .WhereIF(input.FlowType.HasValue, (flow, store, supplier) => flow.FlowType == input.FlowType.Value) | |
| 253 | + .WhereIF(!string.IsNullOrWhiteSpace(input.BatchNumber), (flow, store, supplier) => flow.BatchNumber == input.BatchNumber) | |
| 254 | + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (flow, store, supplier) => flow.StoreId == input.StoreId) | |
| 255 | + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductType), (flow, store, supplier) => flow.ProductType == input.ProductType) | |
| 256 | + .WhereIF(!string.IsNullOrWhiteSpace(input.LaundrySupplierId), (flow, store, supplier) => flow.LaundrySupplierId == input.LaundrySupplierId) | |
| 257 | + .WhereIF(input.StartTime.HasValue, (flow, store, supplier) => flow.CreateTime >= input.StartTime.Value) | |
| 258 | + .WhereIF(input.EndTime.HasValue, (flow, store, supplier) => flow.CreateTime <= input.EndTime.Value) | |
| 259 | + .WhereIF(input.IsEffective.HasValue, (flow, store, supplier) => flow.IsEffective == input.IsEffective.Value) | |
| 260 | + .Select((flow, store, supplier) => new LqLaundryFlowListOutput | |
| 261 | + { | |
| 262 | + id = flow.Id, | |
| 263 | + flowType = flow.FlowType, | |
| 264 | + flowTypeName = flow.FlowType == 0 ? "送出" : "送回", | |
| 265 | + batchNumber = flow.BatchNumber, | |
| 266 | + storeId = flow.StoreId, | |
| 267 | + storeName = store.Dm ?? "", | |
| 268 | + productType = flow.ProductType, | |
| 269 | + laundrySupplierId = flow.LaundrySupplierId, | |
| 270 | + laundrySupplierName = supplier.SupplierName ?? "", | |
| 271 | + quantity = flow.Quantity, | |
| 272 | + laundryPrice = flow.LaundryPrice, | |
| 273 | + totalPrice = flow.TotalPrice, | |
| 274 | + remark = flow.Remark, | |
| 275 | + isEffective = flow.IsEffective, | |
| 276 | + createUser = flow.CreateUser, | |
| 277 | + createUserName = "", | |
| 278 | + createTime = flow.CreateTime | |
| 279 | + }) | |
| 280 | + .MergeTable() | |
| 281 | + .OrderBy(sidx + " " + sort) | |
| 282 | + .ToPagedListAsync(input.currentPage, input.pageSize); | |
| 283 | + | |
| 284 | + // 补充用户名称信息 | |
| 285 | + var userIds = data.list.Select(x => x.createUser) | |
| 286 | + .Where(x => !string.IsNullOrEmpty(x)) | |
| 287 | + .Distinct() | |
| 288 | + .ToList(); | |
| 289 | + | |
| 290 | + if (userIds.Any()) | |
| 291 | + { | |
| 292 | + var userList = await _db.Queryable<UserEntity>() | |
| 293 | + .Where(x => userIds.Contains(x.Id)) | |
| 294 | + .Select(x => new { x.Id, x.RealName }) | |
| 295 | + .ToListAsync(); | |
| 296 | + var userDict = userList.ToDictionary(k => k.Id, v => v.RealName); | |
| 297 | + | |
| 298 | + foreach (var item in data.list) | |
| 299 | + { | |
| 300 | + item.createUserName = userDict.ContainsKey(item.createUser) ? userDict[item.createUser] : ""; | |
| 301 | + } | |
| 302 | + } | |
| 303 | + | |
| 304 | + return PageResult<LqLaundryFlowListOutput>.SqlSugarPageResult(data); | |
| 305 | + } | |
| 306 | + catch (Exception ex) | |
| 307 | + { | |
| 308 | + _logger.LogError(ex, "获取清洗流水列表失败"); | |
| 309 | + throw NCCException.Oh($"查询失败:{ex.Message}"); | |
| 310 | + } | |
| 311 | + } | |
| 312 | + #endregion | |
| 313 | + | |
| 314 | + #region 获取清洗流水详情 | |
| 315 | + /// <summary> | |
| 316 | + /// 获取清洗流水详情 | |
| 317 | + /// </summary> | |
| 318 | + /// <remarks> | |
| 319 | + /// 根据ID获取清洗流水的详细信息 | |
| 320 | + /// </remarks> | |
| 321 | + /// <param name="id">流水ID</param> | |
| 322 | + /// <returns>流水详情</returns> | |
| 323 | + /// <response code="200">查询成功</response> | |
| 324 | + /// <response code="400">记录不存在</response> | |
| 325 | + /// <response code="500">服务器错误</response> | |
| 326 | + [HttpGet("{id}")] | |
| 327 | + public async Task<LqLaundryFlowInfoOutput> GetInfoAsync(string id) | |
| 328 | + { | |
| 329 | + try | |
| 330 | + { | |
| 331 | + var entity = await _db.Queryable<LqLaundryFlowEntity, LqMdxxEntity, LqLaundrySupplierEntity>( | |
| 332 | + (flow, store, supplier) => flow.StoreId == store.Id && flow.LaundrySupplierId == supplier.Id) | |
| 333 | + .Where((flow, store, supplier) => flow.Id == id) | |
| 334 | + .Select((flow, store, supplier) => new LqLaundryFlowInfoOutput | |
| 335 | + { | |
| 336 | + id = flow.Id, | |
| 337 | + flowType = flow.FlowType, | |
| 338 | + flowTypeName = flow.FlowType == 0 ? "送出" : "送回", | |
| 339 | + batchNumber = flow.BatchNumber, | |
| 340 | + storeId = flow.StoreId, | |
| 341 | + storeName = store.Dm ?? "", | |
| 342 | + productType = flow.ProductType, | |
| 343 | + laundrySupplierId = flow.LaundrySupplierId, | |
| 344 | + laundrySupplierName = supplier.SupplierName ?? "", | |
| 345 | + quantity = flow.Quantity, | |
| 346 | + laundryPrice = flow.LaundryPrice, | |
| 347 | + totalPrice = flow.TotalPrice, | |
| 348 | + remark = flow.Remark, | |
| 349 | + isEffective = flow.IsEffective, | |
| 350 | + createUser = flow.CreateUser, | |
| 351 | + createUserName = "", | |
| 352 | + createTime = flow.CreateTime | |
| 353 | + }) | |
| 354 | + .FirstAsync(); | |
| 355 | + | |
| 356 | + if (entity == null) | |
| 357 | + { | |
| 358 | + throw NCCException.Oh("流水记录不存在"); | |
| 359 | + } | |
| 360 | + | |
| 361 | + // 补充用户名称 | |
| 362 | + if (!string.IsNullOrEmpty(entity.createUser)) | |
| 363 | + { | |
| 364 | + var createUser = await _db.Queryable<UserEntity>() | |
| 365 | + .Where(x => x.Id == entity.createUser) | |
| 366 | + .Select(x => x.RealName) | |
| 367 | + .FirstAsync(); | |
| 368 | + entity.createUserName = createUser ?? ""; | |
| 369 | + } | |
| 370 | + | |
| 371 | + return entity; | |
| 372 | + } | |
| 373 | + catch (Exception ex) | |
| 374 | + { | |
| 375 | + _logger.LogError(ex, "获取清洗流水详情失败"); | |
| 376 | + throw NCCException.Oh($"查询失败:{ex.Message}"); | |
| 377 | + } | |
| 378 | + } | |
| 379 | + #endregion | |
| 380 | + | |
| 381 | + #region 查询差异记录 | |
| 382 | + /// <summary> | |
| 383 | + /// 查询差异记录(送出数量 > 送回数量) | |
| 384 | + /// </summary> | |
| 385 | + /// <remarks> | |
| 386 | + /// 查询所有送出数量大于送回数量的记录,用于追踪差异来源 | |
| 387 | + /// </remarks> | |
| 388 | + /// <param name="input">查询输入(支持分页)</param> | |
| 389 | + /// <returns>差异记录列表</returns> | |
| 390 | + /// <response code="200">查询成功</response> | |
| 391 | + /// <response code="500">服务器错误</response> | |
| 392 | + [HttpPost("GetDifferenceList")] | |
| 393 | + public async Task<dynamic> GetDifferenceListAsync([FromBody] LqLaundryFlowListQueryInput input) | |
| 394 | + { | |
| 395 | + try | |
| 396 | + { | |
| 397 | + // 查询所有送出记录 | |
| 398 | + var sendRecords = await _db.Queryable<LqLaundryFlowEntity, LqMdxxEntity>( | |
| 399 | + (flow, store) => flow.StoreId == store.Id) | |
| 400 | + .Where((flow, store) => flow.FlowType == 0 && flow.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 401 | + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (flow, store) => flow.StoreId == input.StoreId) | |
| 402 | + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductType), (flow, store) => flow.ProductType == input.ProductType) | |
| 403 | + .WhereIF(input.StartTime.HasValue, (flow, store) => flow.CreateTime >= input.StartTime.Value) | |
| 404 | + .WhereIF(input.EndTime.HasValue, (flow, store) => flow.CreateTime <= input.EndTime.Value) | |
| 405 | + .Select((flow, store) => new | |
| 406 | + { | |
| 407 | + flow.BatchNumber, | |
| 408 | + flow.StoreId, | |
| 409 | + StoreName = store.Dm ?? "", | |
| 410 | + flow.ProductType, | |
| 411 | + SendQuantity = flow.Quantity, | |
| 412 | + SendTime = flow.CreateTime | |
| 413 | + }) | |
| 414 | + .ToListAsync(); | |
| 415 | + | |
| 416 | + if (!sendRecords.Any()) | |
| 417 | + { | |
| 418 | + return new | |
| 419 | + { | |
| 420 | + list = new List<LqLaundryFlowDifferenceOutput>(), | |
| 421 | + pagination = new | |
| 422 | + { | |
| 423 | + page = input.currentPage, | |
| 424 | + pageSize = input.pageSize, | |
| 425 | + total = 0 | |
| 426 | + } | |
| 427 | + }; | |
| 428 | + } | |
| 429 | + | |
| 430 | + // 查询所有送回记录 | |
| 431 | + var returnRecords = await _db.Queryable<LqLaundryFlowEntity>() | |
| 432 | + .Where(x => x.FlowType == 1 && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 433 | + .Select(x => new | |
| 434 | + { | |
| 435 | + x.BatchNumber, | |
| 436 | + ReturnQuantity = x.Quantity, | |
| 437 | + ReturnTime = x.CreateTime, | |
| 438 | + x.Remark | |
| 439 | + }) | |
| 440 | + .ToListAsync(); | |
| 441 | + | |
| 442 | + var returnDict = returnRecords | |
| 443 | + .GroupBy(x => x.BatchNumber) | |
| 444 | + .ToDictionary(g => g.Key, g => g.First()); | |
| 445 | + | |
| 446 | + // 计算差异 | |
| 447 | + var differenceList = sendRecords | |
| 448 | + .Select(send => new LqLaundryFlowDifferenceOutput | |
| 449 | + { | |
| 450 | + batchNumber = send.BatchNumber, | |
| 451 | + storeId = send.StoreId, | |
| 452 | + storeName = send.StoreName, | |
| 453 | + productType = send.ProductType, | |
| 454 | + sendQuantity = send.SendQuantity, | |
| 455 | + returnQuantity = returnDict.ContainsKey(send.BatchNumber) ? returnDict[send.BatchNumber].ReturnQuantity : 0, | |
| 456 | + differenceQuantity = send.SendQuantity - (returnDict.ContainsKey(send.BatchNumber) ? returnDict[send.BatchNumber].ReturnQuantity : 0), | |
| 457 | + differenceRemark = returnDict.ContainsKey(send.BatchNumber) ? returnDict[send.BatchNumber].Remark : "", | |
| 458 | + sendTime = send.SendTime, | |
| 459 | + returnTime = returnDict.ContainsKey(send.BatchNumber) ? returnDict[send.BatchNumber].ReturnTime : (DateTime?)null | |
| 460 | + }) | |
| 461 | + .Where(x => x.differenceQuantity > 0) | |
| 462 | + .ToList(); | |
| 463 | + | |
| 464 | + // 手动分页 | |
| 465 | + var totalCount = differenceList.Count; | |
| 466 | + var pagedList = differenceList | |
| 467 | + .Skip((input.currentPage - 1) * input.pageSize) | |
| 468 | + .Take(input.pageSize) | |
| 469 | + .ToList(); | |
| 470 | + | |
| 471 | + return new | |
| 472 | + { | |
| 473 | + list = pagedList, | |
| 474 | + pagination = new | |
| 475 | + { | |
| 476 | + page = input.currentPage, | |
| 477 | + pageSize = input.pageSize, | |
| 478 | + total = totalCount | |
| 479 | + } | |
| 480 | + }; | |
| 481 | + } | |
| 482 | + catch (Exception ex) | |
| 483 | + { | |
| 484 | + _logger.LogError(ex, "查询差异记录失败"); | |
| 485 | + throw NCCException.Oh($"查询失败:{ex.Message}"); | |
| 486 | + } | |
| 487 | + } | |
| 488 | + #endregion | |
| 489 | + | |
| 490 | + #region 门店每月清洗费用统计 | |
| 491 | + /// <summary> | |
| 492 | + /// 门店每月清洗费用统计 | |
| 493 | + /// </summary> | |
| 494 | + /// <remarks> | |
| 495 | + /// 统计每个门店每月的清洗费用(只统计送回记录) | |
| 496 | + /// | |
| 497 | + /// 示例请求: | |
| 498 | + /// ```json | |
| 499 | + /// { | |
| 500 | + /// "startMonth": "202411", | |
| 501 | + /// "endMonth": "202412", | |
| 502 | + /// "storeId": "门店ID(可选)" | |
| 503 | + /// } | |
| 504 | + /// ``` | |
| 505 | + /// </remarks> | |
| 506 | + /// <param name="input">统计输入</param> | |
| 507 | + /// <returns>统计结果</returns> | |
| 508 | + /// <response code="200">统计成功</response> | |
| 509 | + /// <response code="500">服务器错误</response> | |
| 510 | + [HttpPost("GetStoreMonthlyStatistics")] | |
| 511 | + public async Task<List<LqLaundryStatisticsOutput>> GetStoreMonthlyStatisticsAsync([FromBody] LaundryStatisticsInput input) | |
| 512 | + { | |
| 513 | + try | |
| 514 | + { | |
| 515 | + // 构建月份过滤条件 | |
| 516 | + var startDate = (DateTime?)null; | |
| 517 | + var endDate = (DateTime?)null; | |
| 518 | + | |
| 519 | + if (!string.IsNullOrWhiteSpace(input.StartMonth) && input.StartMonth.Length == 6) | |
| 520 | + { | |
| 521 | + var year = int.Parse(input.StartMonth.Substring(0, 4)); | |
| 522 | + var month = int.Parse(input.StartMonth.Substring(4, 2)); | |
| 523 | + startDate = new DateTime(year, month, 1); | |
| 524 | + } | |
| 525 | + | |
| 526 | + if (!string.IsNullOrWhiteSpace(input.EndMonth) && input.EndMonth.Length == 6) | |
| 527 | + { | |
| 528 | + var year = int.Parse(input.EndMonth.Substring(0, 4)); | |
| 529 | + var month = int.Parse(input.EndMonth.Substring(4, 2)); | |
| 530 | + endDate = new DateTime(year, month, DateTime.DaysInMonth(year, month), 23, 59, 59); | |
| 531 | + } | |
| 532 | + | |
| 533 | + var query = _db.Queryable<LqLaundryFlowEntity, LqMdxxEntity>( | |
| 534 | + (flow, store) => flow.StoreId == store.Id) | |
| 535 | + .Where((flow, store) => flow.FlowType == 1 && flow.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 536 | + .WhereIF(startDate.HasValue, (flow, store) => flow.CreateTime >= startDate.Value) | |
| 537 | + .WhereIF(endDate.HasValue, (flow, store) => flow.CreateTime <= endDate.Value) | |
| 538 | + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (flow, store) => flow.StoreId == input.StoreId); | |
| 539 | + | |
| 540 | + var allRecords = await query | |
| 541 | + .Select((flow, store) => new | |
| 542 | + { | |
| 543 | + flow.StoreId, | |
| 544 | + StoreName = store.Dm ?? "", | |
| 545 | + flow.CreateTime, | |
| 546 | + flow.TotalPrice, | |
| 547 | + flow.Id | |
| 548 | + }) | |
| 549 | + .ToListAsync(); | |
| 550 | + | |
| 551 | + // 在内存中分组统计 | |
| 552 | + var result = allRecords | |
| 553 | + .GroupBy(x => new { x.StoreId, x.StoreName, Month = x.CreateTime.ToString("yyyyMM") }) | |
| 554 | + .Select(g => new LqLaundryStatisticsOutput | |
| 555 | + { | |
| 556 | + storeId = g.Key.StoreId, | |
| 557 | + storeName = g.Key.StoreName, | |
| 558 | + statisticsMonth = g.Key.Month, | |
| 559 | + totalPrice = g.Sum(x => x.TotalPrice), | |
| 560 | + count = g.Count() | |
| 561 | + }) | |
| 562 | + .OrderBy(x => x.storeId) | |
| 563 | + .ThenBy(x => x.statisticsMonth) | |
| 564 | + .ToList(); | |
| 565 | + | |
| 566 | + return result; | |
| 567 | + } | |
| 568 | + catch (Exception ex) | |
| 569 | + { | |
| 570 | + _logger.LogError(ex, "门店每月清洗费用统计失败"); | |
| 571 | + throw NCCException.Oh($"统计失败:{ex.Message}"); | |
| 572 | + } | |
| 573 | + } | |
| 574 | + #endregion | |
| 575 | + | |
| 576 | + #region 产品每月清洗费用统计 | |
| 577 | + /// <summary> | |
| 578 | + /// 产品每月清洗费用统计 | |
| 579 | + /// </summary> | |
| 580 | + /// <remarks> | |
| 581 | + /// 统计每个产品每月的清洗费用(只统计送回记录) | |
| 582 | + /// | |
| 583 | + /// 示例请求: | |
| 584 | + /// ```json | |
| 585 | + /// { | |
| 586 | + /// "startMonth": "202411", | |
| 587 | + /// "endMonth": "202412", | |
| 588 | + /// "productType": "毛巾(可选)" | |
| 589 | + /// } | |
| 590 | + /// ``` | |
| 591 | + /// </remarks> | |
| 592 | + /// <param name="input">统计输入</param> | |
| 593 | + /// <returns>统计结果</returns> | |
| 594 | + /// <response code="200">统计成功</response> | |
| 595 | + /// <response code="500">服务器错误</response> | |
| 596 | + [HttpPost("GetProductMonthlyStatistics")] | |
| 597 | + public async Task<List<LqLaundryStatisticsOutput>> GetProductMonthlyStatisticsAsync([FromBody] LaundryStatisticsInput input) | |
| 598 | + { | |
| 599 | + try | |
| 600 | + { | |
| 601 | + // 构建月份过滤条件 | |
| 602 | + var startDate = (DateTime?)null; | |
| 603 | + var endDate = (DateTime?)null; | |
| 604 | + | |
| 605 | + if (!string.IsNullOrWhiteSpace(input.StartMonth) && input.StartMonth.Length == 6) | |
| 606 | + { | |
| 607 | + var year = int.Parse(input.StartMonth.Substring(0, 4)); | |
| 608 | + var month = int.Parse(input.StartMonth.Substring(4, 2)); | |
| 609 | + startDate = new DateTime(year, month, 1); | |
| 610 | + } | |
| 611 | + | |
| 612 | + if (!string.IsNullOrWhiteSpace(input.EndMonth) && input.EndMonth.Length == 6) | |
| 613 | + { | |
| 614 | + var year = int.Parse(input.EndMonth.Substring(0, 4)); | |
| 615 | + var month = int.Parse(input.EndMonth.Substring(4, 2)); | |
| 616 | + endDate = new DateTime(year, month, DateTime.DaysInMonth(year, month), 23, 59, 59); | |
| 617 | + } | |
| 618 | + | |
| 619 | + var query = _db.Queryable<LqLaundryFlowEntity>() | |
| 620 | + .Where(x => x.FlowType == 1 && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 621 | + .WhereIF(startDate.HasValue, x => x.CreateTime >= startDate.Value) | |
| 622 | + .WhereIF(endDate.HasValue, x => x.CreateTime <= endDate.Value) | |
| 623 | + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductType), x => x.ProductType == input.ProductType); | |
| 624 | + | |
| 625 | + var allRecords = await query | |
| 626 | + .Select(x => new | |
| 627 | + { | |
| 628 | + x.ProductType, | |
| 629 | + x.CreateTime, | |
| 630 | + x.TotalPrice, | |
| 631 | + x.Id | |
| 632 | + }) | |
| 633 | + .ToListAsync(); | |
| 634 | + | |
| 635 | + // 在内存中分组统计 | |
| 636 | + var result = allRecords | |
| 637 | + .GroupBy(x => new { x.ProductType, Month = x.CreateTime.ToString("yyyyMM") }) | |
| 638 | + .Select(g => new LqLaundryStatisticsOutput | |
| 639 | + { | |
| 640 | + productType = g.Key.ProductType, | |
| 641 | + statisticsMonth = g.Key.Month, | |
| 642 | + totalPrice = g.Sum(x => x.TotalPrice), | |
| 643 | + count = g.Count() | |
| 644 | + }) | |
| 645 | + .OrderBy(x => x.productType) | |
| 646 | + .ThenBy(x => x.statisticsMonth) | |
| 647 | + .ToList(); | |
| 648 | + | |
| 649 | + return result; | |
| 650 | + } | |
| 651 | + catch (Exception ex) | |
| 652 | + { | |
| 653 | + _logger.LogError(ex, "产品每月清洗费用统计失败"); | |
| 654 | + throw NCCException.Oh($"统计失败:{ex.Message}"); | |
| 655 | + } | |
| 656 | + } | |
| 657 | + #endregion | |
| 658 | + } | |
| 659 | +} | |
| 660 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqLaundrySupplierService.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Linq; | |
| 3 | +using System.Threading.Tasks; | |
| 4 | +using Microsoft.AspNetCore.Mvc; | |
| 5 | +using Microsoft.Extensions.Logging; | |
| 6 | +using NCC.Common.Core.Manager; | |
| 7 | +using NCC.Common.Enum; | |
| 8 | +using NCC.Common.Filter; | |
| 9 | +using NCC.Dependency; | |
| 10 | +using NCC.DynamicApiController; | |
| 11 | +using NCC.Extend.Entitys.Dto.LqLaundrySupplier; | |
| 12 | +using NCC.Extend.Entitys.Enum; | |
| 13 | +using NCC.Extend.Entitys.lq_laundry_supplier; | |
| 14 | +using NCC.Extend.Interfaces.LqLaundrySupplier; | |
| 15 | +using NCC.FriendlyException; | |
| 16 | +using NCC.System.Entitys.Permission; | |
| 17 | +using SqlSugar; | |
| 18 | +using Yitter.IdGenerator; | |
| 19 | + | |
| 20 | +namespace NCC.Extend | |
| 21 | +{ | |
| 22 | + /// <summary> | |
| 23 | + /// 清洗商服务 | |
| 24 | + /// </summary> | |
| 25 | + [ApiDescriptionSettings(Tag = "绿纤清洗商管理", Name = "LqLaundrySupplier", Order = 200)] | |
| 26 | + [Route("api/Extend/LqLaundrySupplier")] | |
| 27 | + public class LqLaundrySupplierService : IDynamicApiController, ITransient, ILqLaundrySupplierService | |
| 28 | + { | |
| 29 | + private readonly IUserManager _userManager; | |
| 30 | + private readonly ILogger<LqLaundrySupplierService> _logger; | |
| 31 | + private readonly ISqlSugarClient _db; | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// 构造函数 | |
| 35 | + /// </summary> | |
| 36 | + public LqLaundrySupplierService(IUserManager userManager, ILogger<LqLaundrySupplierService> logger, ISqlSugarClient db) | |
| 37 | + { | |
| 38 | + _userManager = userManager; | |
| 39 | + _logger = logger; | |
| 40 | + _db = db; | |
| 41 | + } | |
| 42 | + | |
| 43 | + #region 创建清洗商 | |
| 44 | + /// <summary> | |
| 45 | + /// 创建清洗商 | |
| 46 | + /// </summary> | |
| 47 | + /// <remarks> | |
| 48 | + /// 创建清洗商记录,一个清洗商对应一个产品类型一条记录 | |
| 49 | + /// | |
| 50 | + /// 示例请求: | |
| 51 | + /// ```json | |
| 52 | + /// { | |
| 53 | + /// "supplierName": "清洗商A", | |
| 54 | + /// "productType": "毛巾", | |
| 55 | + /// "laundryPrice": 5.00, | |
| 56 | + /// "remark": "备注信息" | |
| 57 | + /// } | |
| 58 | + /// ``` | |
| 59 | + /// </remarks> | |
| 60 | + /// <param name="input">创建输入</param> | |
| 61 | + /// <returns>创建结果</returns> | |
| 62 | + /// <response code="200">创建成功</response> | |
| 63 | + /// <response code="400">清洗商已存在或参数错误</response> | |
| 64 | + /// <response code="500">服务器错误</response> | |
| 65 | + [HttpPost("Create")] | |
| 66 | + public async Task CreateAsync([FromBody] LqLaundrySupplierCrInput input) | |
| 67 | + { | |
| 68 | + try | |
| 69 | + { | |
| 70 | + // 检查是否已存在相同清洗商和产品类型的记录 | |
| 71 | + var existing = await _db.Queryable<LqLaundrySupplierEntity>() | |
| 72 | + .Where(x => x.SupplierName == input.SupplierName | |
| 73 | + && x.ProductType == input.ProductType | |
| 74 | + && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 75 | + .FirstAsync(); | |
| 76 | + | |
| 77 | + if (existing != null) | |
| 78 | + { | |
| 79 | + throw NCCException.Oh($"清洗商【{input.SupplierName}】已存在{input.ProductType}的记录"); | |
| 80 | + } | |
| 81 | + | |
| 82 | + // 创建清洗商记录 | |
| 83 | + var entity = new LqLaundrySupplierEntity | |
| 84 | + { | |
| 85 | + Id = YitIdHelper.NextId().ToString(), | |
| 86 | + SupplierName = input.SupplierName, | |
| 87 | + ProductType = input.ProductType, | |
| 88 | + LaundryPrice = input.LaundryPrice, | |
| 89 | + Remark = input.Remark, | |
| 90 | + IsEffective = StatusEnum.有效.GetHashCode(), | |
| 91 | + CreateUser = _userManager.UserId, | |
| 92 | + CreateTime = DateTime.Now | |
| 93 | + }; | |
| 94 | + | |
| 95 | + var isOk = await _db.Insertable(entity).ExecuteCommandAsync(); | |
| 96 | + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); | |
| 97 | + } | |
| 98 | + catch (Exception ex) | |
| 99 | + { | |
| 100 | + _logger.LogError(ex, "创建清洗商失败"); | |
| 101 | + throw NCCException.Oh($"创建失败:{ex.Message}"); | |
| 102 | + } | |
| 103 | + } | |
| 104 | + #endregion | |
| 105 | + | |
| 106 | + #region 更新清洗商 | |
| 107 | + /// <summary> | |
| 108 | + /// 更新清洗商 | |
| 109 | + /// </summary> | |
| 110 | + /// <remarks> | |
| 111 | + /// 更新清洗商信息,包括价格(更新价格不影响历史流水记录的价格) | |
| 112 | + /// </remarks> | |
| 113 | + /// <param name="input">更新输入</param> | |
| 114 | + /// <returns>更新结果</returns> | |
| 115 | + /// <response code="200">更新成功</response> | |
| 116 | + /// <response code="400">记录不存在或参数错误</response> | |
| 117 | + /// <response code="500">服务器错误</response> | |
| 118 | + [HttpPut("Update")] | |
| 119 | + public async Task UpdateAsync([FromBody] LqLaundrySupplierUpInput input) | |
| 120 | + { | |
| 121 | + try | |
| 122 | + { | |
| 123 | + var existing = await _db.Queryable<LqLaundrySupplierEntity>() | |
| 124 | + .Where(x => x.Id == input.Id && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 125 | + .FirstAsync(); | |
| 126 | + | |
| 127 | + if (existing == null) | |
| 128 | + { | |
| 129 | + throw NCCException.Oh("清洗商记录不存在或已失效"); | |
| 130 | + } | |
| 131 | + | |
| 132 | + // 如果清洗商名称或产品类型改变,检查是否冲突 | |
| 133 | + if (existing.SupplierName != input.SupplierName || existing.ProductType != input.ProductType) | |
| 134 | + { | |
| 135 | + var conflict = await _db.Queryable<LqLaundrySupplierEntity>() | |
| 136 | + .Where(x => x.Id != input.Id | |
| 137 | + && x.SupplierName == input.SupplierName | |
| 138 | + && x.ProductType == input.ProductType | |
| 139 | + && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 140 | + .FirstAsync(); | |
| 141 | + | |
| 142 | + if (conflict != null) | |
| 143 | + { | |
| 144 | + throw NCCException.Oh($"清洗商【{input.SupplierName}】已存在{input.ProductType}的记录"); | |
| 145 | + } | |
| 146 | + } | |
| 147 | + | |
| 148 | + // 更新记录 | |
| 149 | + existing.SupplierName = input.SupplierName; | |
| 150 | + existing.ProductType = input.ProductType; | |
| 151 | + existing.LaundryPrice = input.LaundryPrice; | |
| 152 | + existing.Remark = input.Remark; | |
| 153 | + existing.UpdateUser = _userManager.UserId; | |
| 154 | + existing.UpdateTime = DateTime.Now; | |
| 155 | + | |
| 156 | + var isOk = await _db.Updateable(existing).ExecuteCommandAsync(); | |
| 157 | + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); | |
| 158 | + } | |
| 159 | + catch (Exception ex) | |
| 160 | + { | |
| 161 | + _logger.LogError(ex, "更新清洗商失败"); | |
| 162 | + throw NCCException.Oh($"更新失败:{ex.Message}"); | |
| 163 | + } | |
| 164 | + } | |
| 165 | + #endregion | |
| 166 | + | |
| 167 | + #region 获取清洗商列表 | |
| 168 | + /// <summary> | |
| 169 | + /// 获取清洗商列表 | |
| 170 | + /// </summary> | |
| 171 | + /// <remarks> | |
| 172 | + /// 分页查询清洗商列表,支持按清洗商名称、产品类型筛选 | |
| 173 | + /// </remarks> | |
| 174 | + /// <param name="input">查询输入</param> | |
| 175 | + /// <returns>清洗商列表</returns> | |
| 176 | + /// <response code="200">查询成功</response> | |
| 177 | + /// <response code="500">服务器错误</response> | |
| 178 | + [HttpGet("GetList")] | |
| 179 | + public async Task<dynamic> GetListAsync([FromQuery] LqLaundrySupplierListQueryInput input) | |
| 180 | + { | |
| 181 | + try | |
| 182 | + { | |
| 183 | + var sidx = string.IsNullOrEmpty(input.sidx) ? "createTime" : input.sidx; | |
| 184 | + var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; | |
| 185 | + | |
| 186 | + var data = await _db.Queryable<LqLaundrySupplierEntity>() | |
| 187 | + .WhereIF(!string.IsNullOrWhiteSpace(input.SupplierName), x => x.SupplierName.Contains(input.SupplierName)) | |
| 188 | + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductType), x => x.ProductType == input.ProductType) | |
| 189 | + .WhereIF(input.IsEffective.HasValue, x => x.IsEffective == input.IsEffective.Value) | |
| 190 | + .Select(x => new LqLaundrySupplierListOutput | |
| 191 | + { | |
| 192 | + id = x.Id, | |
| 193 | + supplierName = x.SupplierName, | |
| 194 | + productType = x.ProductType, | |
| 195 | + laundryPrice = x.LaundryPrice, | |
| 196 | + remark = x.Remark, | |
| 197 | + isEffective = x.IsEffective, | |
| 198 | + createUser = x.CreateUser, | |
| 199 | + createUserName = "", | |
| 200 | + createTime = x.CreateTime, | |
| 201 | + updateUser = x.UpdateUser, | |
| 202 | + updateUserName = "", | |
| 203 | + updateTime = x.UpdateTime | |
| 204 | + }) | |
| 205 | + .MergeTable() | |
| 206 | + .OrderBy(sidx + " " + sort) | |
| 207 | + .ToPagedListAsync(input.currentPage, input.pageSize); | |
| 208 | + | |
| 209 | + // 补充用户名称信息 | |
| 210 | + var userIds = data.list.SelectMany(x => new[] { x.createUser, x.updateUser }) | |
| 211 | + .Where(x => !string.IsNullOrEmpty(x)) | |
| 212 | + .Distinct() | |
| 213 | + .ToList(); | |
| 214 | + | |
| 215 | + if (userIds.Any()) | |
| 216 | + { | |
| 217 | + var userList = await _db.Queryable<UserEntity>() | |
| 218 | + .Where(x => userIds.Contains(x.Id)) | |
| 219 | + .Select(x => new { x.Id, x.RealName }) | |
| 220 | + .ToListAsync(); | |
| 221 | + var userDict = userList.ToDictionary(k => k.Id, v => v.RealName); | |
| 222 | + | |
| 223 | + foreach (var item in data.list) | |
| 224 | + { | |
| 225 | + item.createUserName = userDict.ContainsKey(item.createUser) ? userDict[item.createUser] : ""; | |
| 226 | + item.updateUserName = !string.IsNullOrEmpty(item.updateUser) && userDict.ContainsKey(item.updateUser) ? userDict[item.updateUser] : ""; | |
| 227 | + } | |
| 228 | + } | |
| 229 | + | |
| 230 | + return PageResult<LqLaundrySupplierListOutput>.SqlSugarPageResult(data); | |
| 231 | + } | |
| 232 | + catch (Exception ex) | |
| 233 | + { | |
| 234 | + _logger.LogError(ex, "获取清洗商列表失败"); | |
| 235 | + throw NCCException.Oh($"查询失败:{ex.Message}"); | |
| 236 | + } | |
| 237 | + } | |
| 238 | + #endregion | |
| 239 | + | |
| 240 | + #region 获取清洗商详情 | |
| 241 | + /// <summary> | |
| 242 | + /// 获取清洗商详情 | |
| 243 | + /// </summary> | |
| 244 | + /// <remarks> | |
| 245 | + /// 根据ID获取清洗商的详细信息 | |
| 246 | + /// </remarks> | |
| 247 | + /// <param name="id">清洗商ID</param> | |
| 248 | + /// <returns>清洗商详情</returns> | |
| 249 | + /// <response code="200">查询成功</response> | |
| 250 | + /// <response code="400">记录不存在</response> | |
| 251 | + /// <response code="500">服务器错误</response> | |
| 252 | + [HttpGet("{id}")] | |
| 253 | + public async Task<LqLaundrySupplierInfoOutput> GetInfoAsync(string id) | |
| 254 | + { | |
| 255 | + try | |
| 256 | + { | |
| 257 | + var entity = await _db.Queryable<LqLaundrySupplierEntity>() | |
| 258 | + .Where(x => x.Id == id) | |
| 259 | + .Select(x => new LqLaundrySupplierInfoOutput | |
| 260 | + { | |
| 261 | + id = x.Id, | |
| 262 | + supplierName = x.SupplierName, | |
| 263 | + productType = x.ProductType, | |
| 264 | + laundryPrice = x.LaundryPrice, | |
| 265 | + remark = x.Remark, | |
| 266 | + isEffective = x.IsEffective, | |
| 267 | + createUser = x.CreateUser, | |
| 268 | + createUserName = "", | |
| 269 | + createTime = x.CreateTime, | |
| 270 | + updateUser = x.UpdateUser, | |
| 271 | + updateUserName = "", | |
| 272 | + updateTime = x.UpdateTime | |
| 273 | + }) | |
| 274 | + .FirstAsync(); | |
| 275 | + | |
| 276 | + if (entity == null) | |
| 277 | + { | |
| 278 | + throw NCCException.Oh("清洗商记录不存在"); | |
| 279 | + } | |
| 280 | + | |
| 281 | + // 补充用户名称 | |
| 282 | + if (!string.IsNullOrEmpty(entity.createUser)) | |
| 283 | + { | |
| 284 | + var createUser = await _db.Queryable<UserEntity>() | |
| 285 | + .Where(x => x.Id == entity.createUser) | |
| 286 | + .Select(x => x.RealName) | |
| 287 | + .FirstAsync(); | |
| 288 | + entity.createUserName = createUser ?? ""; | |
| 289 | + } | |
| 290 | + | |
| 291 | + if (!string.IsNullOrEmpty(entity.updateUser)) | |
| 292 | + { | |
| 293 | + var updateUser = await _db.Queryable<UserEntity>() | |
| 294 | + .Where(x => x.Id == entity.updateUser) | |
| 295 | + .Select(x => x.RealName) | |
| 296 | + .FirstAsync(); | |
| 297 | + entity.updateUserName = updateUser ?? ""; | |
| 298 | + } | |
| 299 | + | |
| 300 | + return entity; | |
| 301 | + } | |
| 302 | + catch (Exception ex) | |
| 303 | + { | |
| 304 | + _logger.LogError(ex, "获取清洗商详情失败"); | |
| 305 | + throw NCCException.Oh($"查询失败:{ex.Message}"); | |
| 306 | + } | |
| 307 | + } | |
| 308 | + #endregion | |
| 309 | + | |
| 310 | + #region 删除/作废清洗商 | |
| 311 | + /// <summary> | |
| 312 | + /// 删除/作废清洗商 | |
| 313 | + /// </summary> | |
| 314 | + /// <remarks> | |
| 315 | + /// 将清洗商记录标记为无效 | |
| 316 | + /// </remarks> | |
| 317 | + /// <param name="id">清洗商ID</param> | |
| 318 | + /// <returns>操作结果</returns> | |
| 319 | + /// <response code="200">操作成功</response> | |
| 320 | + /// <response code="400">记录不存在</response> | |
| 321 | + /// <response code="500">服务器错误</response> | |
| 322 | + [HttpDelete("{id}")] | |
| 323 | + public async Task DeleteAsync(string id) | |
| 324 | + { | |
| 325 | + try | |
| 326 | + { | |
| 327 | + var entity = await _db.Queryable<LqLaundrySupplierEntity>() | |
| 328 | + .Where(x => x.Id == id) | |
| 329 | + .FirstAsync(); | |
| 330 | + | |
| 331 | + if (entity == null) | |
| 332 | + { | |
| 333 | + throw NCCException.Oh("清洗商记录不存在"); | |
| 334 | + } | |
| 335 | + | |
| 336 | + entity.IsEffective = StatusEnum.无效.GetHashCode(); | |
| 337 | + entity.UpdateUser = _userManager.UserId; | |
| 338 | + entity.UpdateTime = DateTime.Now; | |
| 339 | + | |
| 340 | + var isOk = await _db.Updateable(entity).ExecuteCommandAsync(); | |
| 341 | + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); | |
| 342 | + } | |
| 343 | + catch (Exception ex) | |
| 344 | + { | |
| 345 | + _logger.LogError(ex, "删除清洗商失败"); | |
| 346 | + throw NCCException.Oh($"删除失败:{ex.Message}"); | |
| 347 | + } | |
| 348 | + } | |
| 349 | + #endregion | |
| 350 | + } | |
| 351 | +} | |
| 352 | + | |
| 353 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs
| ... | ... | @@ -26,6 +26,8 @@ using NCC.Extend.Entitys.lq_kd_jksyj; |
| 26 | 26 | using NCC.Extend.Entitys.lq_kd_kdjlb; |
| 27 | 27 | using NCC.Extend.Entitys.lq_kd_kjbsyj; |
| 28 | 28 | using NCC.Extend.Entitys.lq_mdxx; |
| 29 | +using NCC.Extend.Entitys.lq_md_target; | |
| 30 | +using NCC.Extend.Entitys.lq_hytk_hytk; | |
| 29 | 31 | using NCC.Extend.Entitys.lq_md_xdbhsj; |
| 30 | 32 | using NCC.Extend.Entitys.lq_xh_kjbsyj; |
| 31 | 33 | using NCC.Extend.Entitys.lq_xh_hyhk; |
| ... | ... | @@ -50,6 +52,7 @@ using NCC.System.Entitys.Permission; |
| 50 | 52 | using SqlSugar; |
| 51 | 53 | using Yitter.IdGenerator; |
| 52 | 54 | using NCC.Extend.Entitys.lq_kd_pxmx; |
| 55 | +using NCC.Extend.Entitys.lq_khxx; | |
| 53 | 56 | |
| 54 | 57 | namespace NCC.Extend.LqStatistics |
| 55 | 58 | { |
| ... | ... | @@ -886,52 +889,18 @@ namespace NCC.Extend.LqStatistics |
| 886 | 889 | var now = DateTime.Now; |
| 887 | 890 | var startDate = new DateTime(now.Year, now.Month, 1); |
| 888 | 891 | var endDate = startDate.AddMonths(1).AddDays(-1); |
| 889 | - | |
| 890 | 892 | // 获取当前月份(YYYYMM格式) |
| 891 | 893 | var currentMonth = now.ToString("yyyyMM"); |
| 892 | - | |
| 893 | 894 | // 1. 获取本月的门店目标业绩总和(从门店目标表获取 F_StoreTarget 字段,按月份过滤) |
| 894 | - var targetPerformanceSql = @" | |
| 895 | - SELECT | |
| 896 | - COALESCE(SUM(F_StoreTarget), 0) AS TotalTargetPerformance | |
| 897 | - FROM lq_md_target | |
| 898 | - WHERE F_Month = @month"; | |
| 899 | - | |
| 900 | - var targetParameters = new Dictionary<string, object> | |
| 901 | - { | |
| 902 | - { "@month", currentMonth } | |
| 903 | - }; | |
| 904 | - | |
| 905 | - var targetResult = await _db.Ado.SqlQueryAsync<dynamic>(targetPerformanceSql, targetParameters); | |
| 906 | - var targetPerformance = 0m; | |
| 907 | - if (targetResult != null && targetResult.Any()) | |
| 908 | - { | |
| 909 | - targetPerformance = Convert.ToDecimal(targetResult.FirstOrDefault()?.TotalTargetPerformance ?? 0); | |
| 910 | - } | |
| 911 | - | |
| 895 | + var targetPerformance = await _db.Queryable<LqMdTargetEntity>().Where(x => x.Month == currentMonth).SumAsync(x => (decimal?)x.StoreTarget) ?? 0m; | |
| 912 | 896 | // 2. 从开单记录表获取本月实付金额的总和(sfyj 字段) |
| 913 | - var actualPerformanceSql = @" | |
| 914 | - SELECT | |
| 915 | - COALESCE(SUM(sfyj), 0) AS TotalActualPerformance | |
| 916 | - FROM lq_kd_kdjlb | |
| 917 | - WHERE F_IsEffective = 1 | |
| 918 | - AND kdrq >= @startDate | |
| 919 | - AND kdrq <= @endDate"; | |
| 920 | - | |
| 921 | - var parameters = new Dictionary<string, object> | |
| 922 | - { | |
| 923 | - { "@startDate", startDate.ToString("yyyy-MM-dd 00:00:00") }, | |
| 924 | - { "@endDate", endDate.ToString("yyyy-MM-dd 23:59:59") } | |
| 925 | - }; | |
| 926 | - | |
| 927 | - var actualResult = await _db.Ado.SqlQueryAsync<dynamic>(actualPerformanceSql, parameters); | |
| 928 | - var actualPerformance = 0m; | |
| 929 | - if (actualResult != null && actualResult.Any()) | |
| 930 | - { | |
| 931 | - actualPerformance = Convert.ToDecimal(actualResult.FirstOrDefault()?.TotalActualPerformance ?? 0); | |
| 932 | - } | |
| 933 | - | |
| 934 | - // 3. 计算完成率 | |
| 897 | + var endDateTime = endDate.Date.AddDays(1).AddSeconds(-1); // 结束日期的23:59:59 | |
| 898 | + var billingPerformance = await _db.Queryable<LqKdKdjlbEntity>().Where(x => x.IsEffective == 1).Where(x => x.Kdrq.HasValue && x.Kdrq.Value >= startDate && x.Kdrq.Value <= endDateTime).SumAsync(x => (decimal?)x.Sfyj) ?? 0m; | |
| 899 | + // 3. 从退卡记录表获取本月退卡金额的总和(F_ActualRefundAmount 字段) | |
| 900 | + var refundPerformance = await _db.Queryable<LqHytkHytkEntity>().Where(x => x.IsEffective == 1).Where(x => x.Tksj.HasValue && x.Tksj.Value.Date >= startDate.Date && x.Tksj.Value.Date <= endDate.Date).SumAsync(x => x.ActualRefundAmount) ?? 0m; | |
| 901 | + // 4. 计算实际开单业绩(开单业绩 - 退卡金额) | |
| 902 | + var actualPerformance = billingPerformance - refundPerformance; | |
| 903 | + // 5. 计算完成率(使用实际开单业绩) | |
| 935 | 904 | var completionRate = 0m; |
| 936 | 905 | if (targetPerformance > 0) |
| 937 | 906 | { |
| ... | ... | @@ -941,6 +910,8 @@ namespace NCC.Extend.LqStatistics |
| 941 | 910 | return new |
| 942 | 911 | { |
| 943 | 912 | TargetPerformance = targetPerformance, |
| 913 | + BillingPerformance = billingPerformance, | |
| 914 | + RefundPerformance = refundPerformance, | |
| 944 | 915 | ActualPerformance = actualPerformance, |
| 945 | 916 | CompletionRate = decimal.Round(completionRate, 2), |
| 946 | 917 | Month = now.ToString("yyyy年MM月"), |
| ... | ... | @@ -952,6 +923,8 @@ namespace NCC.Extend.LqStatistics |
| 952 | 923 | return new |
| 953 | 924 | { |
| 954 | 925 | TargetPerformance = 0m, |
| 926 | + BillingPerformance = 0m, | |
| 927 | + RefundPerformance = 0m, | |
| 955 | 928 | ActualPerformance = 0m, |
| 956 | 929 | CompletionRate = 0m, |
| 957 | 930 | Month = DateTime.Now.ToString("yyyy年MM月"), |
| ... | ... | @@ -3679,7 +3652,6 @@ namespace NCC.Extend.LqStatistics |
| 3679 | 3652 | /// - ConsumeProjectCount: 消耗项目数 |
| 3680 | 3653 | /// - ConsumeAchievement: 消耗业绩 |
| 3681 | 3654 | /// - OrderAchievement: 开单业绩(开卡业绩) |
| 3682 | - /// - OrderItemCount: 开单品项次数 | |
| 3683 | 3655 | /// - ConsumeItemCount: 耗卡品项次数 |
| 3684 | 3656 | /// - ConsumeLaborCost: 消耗手工费(耗卡手工费) |
| 3685 | 3657 | /// </remarks> |
| ... | ... | @@ -3689,92 +3661,45 @@ namespace NCC.Extend.LqStatistics |
| 3689 | 3661 | /// <response code="400">参数错误</response> |
| 3690 | 3662 | /// <response code="500">服务器内部错误</response> |
| 3691 | 3663 | [HttpPost("GetTechTeacherStatistics")] |
| 3692 | - [AllowAnonymous] | |
| 3693 | 3664 | public async Task<List<TechTeacherSimpleStatisticsOutput>> GetTechTeacherStatistics(TechTeacherStatisticsInput input) |
| 3694 | 3665 | { |
| 3666 | + TechTeacherSimpleStatisticsOutput result = new TechTeacherSimpleStatisticsOutput | |
| 3667 | + { | |
| 3668 | + DepartmentName = "科技部", | |
| 3669 | + TeacherName = "", | |
| 3670 | + OrderAchievement = 0m, | |
| 3671 | + ConsumeAchievement = 0m, | |
| 3672 | + ConsumeItemCount = 0, | |
| 3673 | + ConsumeProjectCount = 0, | |
| 3674 | + ConsumeLaborCost = 0m, | |
| 3675 | + RefundAchievement = 0m, | |
| 3676 | + }; | |
| 3695 | 3677 | try |
| 3696 | 3678 | { |
| 3697 | 3679 | // 1. 验证必须传入科技老师ID |
| 3698 | 3680 | if (string.IsNullOrEmpty(input.TeacherId)) |
| 3699 | 3681 | { |
| 3700 | - return new List<TechTeacherSimpleStatisticsOutput> | |
| 3701 | - { | |
| 3702 | - new TechTeacherSimpleStatisticsOutput | |
| 3703 | - { | |
| 3704 | - DepartmentName = "科技部", | |
| 3705 | - TeacherName = "", | |
| 3706 | - OrderAchievement = 0m, | |
| 3707 | - OrderItemCount = 0, | |
| 3708 | - ConsumeAchievement = 0m, | |
| 3709 | - ConsumeItemCount = 0, | |
| 3710 | - ConsumeProjectCount = 0, | |
| 3711 | - ConsumeLaborCost = 0m, | |
| 3712 | - RefundAchievement = 0m, | |
| 3713 | - } | |
| 3714 | - }; | |
| 3682 | + return new List<TechTeacherSimpleStatisticsOutput> { result }; | |
| 3715 | 3683 | } |
| 3716 | 3684 | |
| 3717 | 3685 | // 2. 获取科技老师信息 |
| 3718 | - var teacher = await _db.Queryable<UserEntity>() | |
| 3719 | - .Where(x => x.Gw == "科技老师" && x.Id == input.TeacherId) | |
| 3720 | - .Select(x => new | |
| 3721 | - { | |
| 3722 | - TeacherId = x.Id, | |
| 3723 | - TeacherName = x.RealName, | |
| 3724 | - TeacherAccount = x.Account, | |
| 3725 | - }) | |
| 3726 | - .FirstAsync(); | |
| 3727 | - | |
| 3728 | - if (teacher == null) | |
| 3686 | + var teacher = await _db.Queryable<UserEntity>().Where(x => x.Gw == "科技老师" && x.Id == input.TeacherId) | |
| 3687 | + .Select(x => new | |
| 3729 | 3688 | { |
| 3730 | - return new List<TechTeacherSimpleStatisticsOutput> | |
| 3731 | - { | |
| 3732 | - new TechTeacherSimpleStatisticsOutput | |
| 3733 | - { | |
| 3734 | - DepartmentName = "科技部", | |
| 3735 | - TeacherName = "", | |
| 3736 | - OrderAchievement = 0m, | |
| 3737 | - OrderItemCount = 0, | |
| 3738 | - ConsumeAchievement = 0m, | |
| 3739 | - ConsumeItemCount = 0, | |
| 3740 | - ConsumeProjectCount = 0, | |
| 3741 | - ConsumeLaborCost = 0m, | |
| 3742 | - RefundAchievement = 0m, | |
| 3743 | - } | |
| 3744 | - }; | |
| 3745 | - } | |
| 3746 | - | |
| 3747 | - // 3. 查询开单业绩(从 lq_kd_kjbsyj 关联 lq_kd_kdjlb 和 lq_kd_pxmx) | |
| 3748 | - var orderQuery = _db.Queryable<LqKdKjbsyjEntity, LqKdKdjlbEntity, LqKdPxmxEntity>( | |
| 3749 | - (kjbsyj, kdjlb, pxmx) => kjbsyj.Glkdbh == kdjlb.Id && kjbsyj.Kdpxid == pxmx.Id) | |
| 3750 | - .Where((kjbsyj, kdjlb, pxmx) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 3751 | - .Where((kjbsyj, kdjlb, pxmx) => kdjlb.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 3752 | - .Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Kjblszh == teacher.TeacherAccount); | |
| 3753 | - | |
| 3754 | - // 日期过滤 | |
| 3755 | - if (input.StartDate.HasValue) | |
| 3756 | - { | |
| 3757 | - orderQuery = orderQuery.Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Yjsj >= input.StartDate.Value); | |
| 3758 | - } | |
| 3689 | + TeacherId = x.Id, | |
| 3690 | + TeacherName = x.RealName, | |
| 3691 | + TeacherAccount = x.Account, | |
| 3692 | + }).FirstAsync(); | |
| 3759 | 3693 | |
| 3760 | - if (input.EndDate.HasValue) | |
| 3694 | + if (teacher == null) | |
| 3761 | 3695 | { |
| 3762 | - orderQuery = orderQuery.Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Yjsj <= input.EndDate.Value); | |
| 3696 | + return new List<TechTeacherSimpleStatisticsOutput> { result }; | |
| 3763 | 3697 | } |
| 3764 | - | |
| 3765 | - var orderStats = await orderQuery | |
| 3766 | - .Select((kjbsyj, kdjlb, pxmx) => new | |
| 3767 | - { | |
| 3768 | - OrderAchievement = SqlFunc.ToDecimal(kjbsyj.Kjblsyj), | |
| 3769 | - OrderItemCount = SqlFunc.ToInt32(pxmx.ProjectNumber), | |
| 3770 | - }) | |
| 3771 | - .ToListAsync(); | |
| 3698 | + // 3. 查询开单业绩(从 lq_kd_kjbsyj 表) | |
| 3699 | + var OrderAchievement = await _db.Queryable<LqKdKjbsyjEntity>().Where(x => x.Kjbls == teacher.TeacherId && x.IsEffective == StatusEnum.有效.GetHashCode() && x.Yjsj >= input.StartDate.Value && x.Yjsj <= input.EndDate.Value).SumAsync(x => x.Kjblsyj); | |
| 3772 | 3700 | |
| 3773 | 3701 | // 4. 查询耗卡业绩(从 lq_xh_kjbsyj 关联 lq_xh_hyhk 和 lq_xh_pxmx) |
| 3774 | - // 注意:lq_xh_kjbsyj.kjbls 字段存储的是健康师id,不是科技部老师id | |
| 3775 | - // 科技部老师信息在 kjblszh(账号)和 kjblsxm(姓名)字段 | |
| 3776 | - var consumeQuery = _db.Queryable<LqXhKjbsyjEntity, LqXhHyhkEntity, LqXhPxmxEntity>( | |
| 3777 | - (kjbsyj, hyhk, pxmx) => kjbsyj.Glkdbh == hyhk.Id && kjbsyj.Hkpxid == pxmx.Id) | |
| 3702 | + var consumeQuery = _db.Queryable<LqXhKjbsyjEntity, LqXhHyhkEntity, LqXhPxmxEntity>((kjbsyj, hyhk, pxmx) => kjbsyj.Glkdbh == hyhk.Id && kjbsyj.Hkpxid == pxmx.Id) | |
| 3778 | 3703 | .Where((kjbsyj, hyhk, pxmx) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode()) |
| 3779 | 3704 | .Where((kjbsyj, hyhk, pxmx) => hyhk.IsEffective == StatusEnum.有效.GetHashCode()) |
| 3780 | 3705 | .Where((kjbsyj, hyhk, pxmx) => kjbsyj.Kjblszh == teacher.TeacherAccount); |
| ... | ... | @@ -3799,69 +3724,230 @@ namespace NCC.Extend.LqStatistics |
| 3799 | 3724 | ConsumeLaborCost = kjbsyj.LaborCost, |
| 3800 | 3725 | }) |
| 3801 | 3726 | .ToListAsync(); |
| 3802 | - | |
| 3803 | 3727 | // 5. 查询退卡业绩(从 lq_hytk_kjbsyj 表) |
| 3804 | - var refundQuery = _db.Queryable<LqHytkKjbsyjEntity>() | |
| 3805 | - .Where(x => x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 3806 | - .Where(x => x.Kjblszh == teacher.TeacherAccount); | |
| 3728 | + var RefundAchievement = await _db.Queryable<LqHytkKjbsyjEntity>().Where(x => x.Kjbls == teacher.TeacherId && x.IsEffective == StatusEnum.有效.GetHashCode() && x.Tksj >= input.StartDate.Value && x.Tksj <= input.EndDate.Value).SumAsync(x => x.Kjblsyj); | |
| 3729 | + // 6. 统计并返回结果 | |
| 3730 | + result.TeacherName = teacher.TeacherName; | |
| 3731 | + result.OrderAchievement = OrderAchievement.ToDecimal(); | |
| 3732 | + result.ConsumeAchievement = consumeStats.Sum(x => x.ConsumeAchievement ?? 0m); | |
| 3733 | + result.ConsumeItemCount = consumeStats.Sum(x => x.ConsumeItemCount); | |
| 3734 | + result.ConsumeProjectCount = consumeStats.Sum(x => x.ConsumeProjectCount); | |
| 3735 | + result.ConsumeLaborCost = consumeStats.Sum(x => x.ConsumeLaborCost ?? 0m); | |
| 3736 | + result.RefundAchievement = RefundAchievement.ToDecimal(); | |
| 3737 | + return new List<TechTeacherSimpleStatisticsOutput> { result }; | |
| 3738 | + } | |
| 3739 | + catch (Exception) | |
| 3740 | + { | |
| 3741 | + return new List<TechTeacherSimpleStatisticsOutput> { result }; | |
| 3742 | + } | |
| 3743 | + } | |
| 3807 | 3744 | |
| 3808 | - // 日期过滤 | |
| 3809 | - if (input.StartDate.HasValue) | |
| 3810 | - { | |
| 3811 | - refundQuery = refundQuery.Where(x => x.Tksj >= input.StartDate.Value); | |
| 3812 | - } | |
| 3745 | + #endregion | |
| 3813 | 3746 | |
| 3814 | - if (input.EndDate.HasValue) | |
| 3747 | + #region 只买了女神卡的会员统计 | |
| 3748 | + /// <summary> | |
| 3749 | + /// 获取只买了女神卡的会员及其开单数据(分页) | |
| 3750 | + /// </summary> | |
| 3751 | + /// <remarks> | |
| 3752 | + /// 统计所有只购买了女神卡(品项编号为61)的会员,并返回这些会员的开单记录 | |
| 3753 | + /// | |
| 3754 | + /// 判断逻辑: | |
| 3755 | + /// 1. 会员必须有购买女神卡的记录 | |
| 3756 | + /// 2. 该会员的所有有效开单记录中,所有品项都必须是女神卡(px = "61") | |
| 3757 | + /// | |
| 3758 | + /// 返回说明: | |
| 3759 | + /// - list: 会员列表 | |
| 3760 | + /// - memberId: 会员ID | |
| 3761 | + /// - memberName: 会员名称 | |
| 3762 | + /// - phone: 手机号 | |
| 3763 | + /// - storeId: 归属门店ID | |
| 3764 | + /// - storeName: 归属门店名称 | |
| 3765 | + /// - billingList: 开单记录列表 | |
| 3766 | + /// - billingId: 开单编号 | |
| 3767 | + /// - billingDate: 开单日期 | |
| 3768 | + /// - actualPerformance: 实付业绩 | |
| 3769 | + /// - storeId: 门店ID | |
| 3770 | + /// - storeName: 门店名称 | |
| 3771 | + /// - itemList: 品项列表 | |
| 3772 | + /// - itemId: 品项明细ID | |
| 3773 | + /// - itemCode: 品项编号(如61) | |
| 3774 | + /// - itemName: 品项名称(如女神卡) | |
| 3775 | + /// - itemPrice: 品项价格 | |
| 3776 | + /// - sourceType: 来源类型 | |
| 3777 | + /// - projectNumber: 项目次数 | |
| 3778 | + /// - totalPrice: 总价 | |
| 3779 | + /// - actualPrice: 实付金额 | |
| 3780 | + /// - performanceTime: 业绩时间 | |
| 3781 | + /// - pagination: 分页信息 | |
| 3782 | + /// - pageIndex: 当前页码 | |
| 3783 | + /// - pageSize: 每页数量 | |
| 3784 | + /// - total: 总记录数 | |
| 3785 | + /// </remarks> | |
| 3786 | + /// <param name="input">查询参数</param> | |
| 3787 | + /// <returns>只买了女神卡的会员列表(分页)</returns> | |
| 3788 | + /// <response code="200">成功返回会员列表</response> | |
| 3789 | + /// <response code="500">服务器内部错误</response> | |
| 3790 | + [HttpPost("GetGoddessCardMembers")] | |
| 3791 | + public async Task<dynamic> GetGoddessCardMembers([FromBody] GoddessCardMemberListQueryInput input) | |
| 3792 | + { | |
| 3793 | + try | |
| 3794 | + { | |
| 3795 | + // 使用SQL一次性查询出符合条件的会员ID | |
| 3796 | + // 逻辑:会员有购买女神卡的记录,且该会员的所有开单记录的所有品项都是女神卡 | |
| 3797 | + var sql = @" | |
| 3798 | + SELECT DISTINCT kd1.Kdhy AS MemberId | |
| 3799 | + FROM lq_kd_pxmx pxmx1 | |
| 3800 | + INNER JOIN lq_kd_kdjlb kd1 ON pxmx1.glkdbh = kd1.F_Id | |
| 3801 | + WHERE pxmx1.px = '61' | |
| 3802 | + AND pxmx1.F_IsEffective = 1 | |
| 3803 | + AND kd1.F_IsEffective = 1 | |
| 3804 | + AND kd1.Kdhy IS NOT NULL | |
| 3805 | + AND kd1.Kdhy != '' | |
| 3806 | + AND NOT EXISTS ( | |
| 3807 | + -- 排除那些有非女神卡品项的会员 | |
| 3808 | + SELECT 1 | |
| 3809 | + FROM lq_kd_pxmx pxmx2 | |
| 3810 | + INNER JOIN lq_kd_kdjlb kd2 ON pxmx2.glkdbh = kd2.F_Id | |
| 3811 | + WHERE kd2.Kdhy = kd1.Kdhy | |
| 3812 | + AND pxmx2.F_IsEffective = 1 | |
| 3813 | + AND kd2.F_IsEffective = 1 | |
| 3814 | + AND pxmx2.px != '61' | |
| 3815 | + )"; | |
| 3816 | + | |
| 3817 | + var validMemberIds = await _db.Ado.SqlQueryAsync<string>(sql); | |
| 3818 | + | |
| 3819 | + if (!validMemberIds.Any()) | |
| 3815 | 3820 | { |
| 3816 | - refundQuery = refundQuery.Where(x => x.Tksj <= input.EndDate.Value); | |
| 3821 | + return new | |
| 3822 | + { | |
| 3823 | + list = new List<GoddessCardMemberOutput>(), | |
| 3824 | + pagination = new | |
| 3825 | + { | |
| 3826 | + pageIndex = input.PageIndex, | |
| 3827 | + pageSize = input.PageSize, | |
| 3828 | + total = 0 | |
| 3829 | + } | |
| 3830 | + }; | |
| 3817 | 3831 | } |
| 3818 | 3832 | |
| 3819 | - var refundStats = await refundQuery | |
| 3833 | + // 分页处理 | |
| 3834 | + var totalCount = validMemberIds.Count; | |
| 3835 | + var pagedMemberIds = validMemberIds | |
| 3836 | + .Skip((input.PageIndex - 1) * input.PageSize) | |
| 3837 | + .Take(input.PageSize) | |
| 3838 | + .ToList(); | |
| 3839 | + | |
| 3840 | + // 获取会员基本信息 | |
| 3841 | + var members = await _db.Queryable<LqKhxxEntity>() | |
| 3842 | + .Where(x => pagedMemberIds.Contains(x.Id)) | |
| 3820 | 3843 | .Select(x => new |
| 3821 | 3844 | { |
| 3822 | - RefundAchievement = x.Kjblsyj, | |
| 3845 | + x.Id, | |
| 3846 | + x.Khmc, | |
| 3847 | + x.Sjh, | |
| 3848 | + x.Gsmd | |
| 3823 | 3849 | }) |
| 3824 | 3850 | .ToListAsync(); |
| 3825 | 3851 | |
| 3826 | - // 6. 统计并返回结果 | |
| 3827 | - var result = new TechTeacherSimpleStatisticsOutput | |
| 3828 | - { | |
| 3829 | - DepartmentName = "科技部", | |
| 3830 | - TeacherName = teacher.TeacherName, | |
| 3831 | - OrderAchievement = orderStats.Sum(x => x.OrderAchievement != null && decimal.TryParse(x.OrderAchievement.ToString(), out var val) ? val : 0m), | |
| 3832 | - OrderItemCount = orderStats.Sum(x => x.OrderItemCount), | |
| 3833 | - ConsumeAchievement = consumeStats.Sum(x => x.ConsumeAchievement ?? 0m), | |
| 3834 | - ConsumeItemCount = consumeStats.Sum(x => x.ConsumeItemCount), | |
| 3835 | - ConsumeProjectCount = consumeStats.Sum(x => x.ConsumeProjectCount), | |
| 3836 | - ConsumeLaborCost = consumeStats.Sum(x => x.ConsumeLaborCost ?? 0m), | |
| 3837 | - RefundAchievement = refundStats.Sum(x => x.RefundAchievement ?? 0m), | |
| 3838 | - }; | |
| 3852 | + // 获取门店信息 | |
| 3853 | + var storeIds = members.Where(x => !string.IsNullOrEmpty(x.Gsmd)).Select(x => x.Gsmd).Distinct().ToList(); | |
| 3854 | + var stores = new Dictionary<string, string>(); | |
| 3855 | + if (storeIds.Any()) | |
| 3856 | + { | |
| 3857 | + var storeList = await _db.Queryable<LqMdxxEntity>() | |
| 3858 | + .Where(x => storeIds.Contains(x.Id)) | |
| 3859 | + .Select(x => new { x.Id, x.Dm }) | |
| 3860 | + .ToListAsync(); | |
| 3861 | + stores = storeList.ToDictionary(x => x.Id, x => x.Dm ?? ""); | |
| 3862 | + } | |
| 3839 | 3863 | |
| 3840 | - return new List<TechTeacherSimpleStatisticsOutput> { result }; | |
| 3841 | - } | |
| 3842 | - catch (Exception ex) | |
| 3843 | - { | |
| 3844 | - _logger.LogError(ex, "获取科技部老师业绩统计时发生错误"); | |
| 3845 | - // 发生错误时返回全0的结果,而不是抛出异常 | |
| 3846 | - return new List<TechTeacherSimpleStatisticsOutput> | |
| 3864 | + // 获取所有开单记录 | |
| 3865 | + var billings = await _db.Queryable<LqKdKdjlbEntity>().Where(x => pagedMemberIds.Contains(x.Kdhy) && x.IsEffective == StatusEnum.有效.GetHashCode()).ToListAsync(); | |
| 3866 | + | |
| 3867 | + // 获取开单记录的门店信息 | |
| 3868 | + var billingStoreIds = billings.Where(x => !string.IsNullOrEmpty(x.Djmd)).Select(x => x.Djmd).Distinct().ToList(); | |
| 3869 | + var billingStores = new Dictionary<string, string>(); | |
| 3870 | + if (billingStoreIds.Any()) | |
| 3871 | + { | |
| 3872 | + var billingStoreList = await _db.Queryable<LqMdxxEntity>() | |
| 3873 | + .Where(x => billingStoreIds.Contains(x.Id)) | |
| 3874 | + .Select(x => new { x.Id, x.Dm }) | |
| 3875 | + .ToListAsync(); | |
| 3876 | + billingStores = billingStoreList.ToDictionary(x => x.Id, x => x.Dm ?? ""); | |
| 3877 | + } | |
| 3878 | + | |
| 3879 | + // 获取所有开单的品项明细 | |
| 3880 | + var billingIds = billings.Select(x => x.Id).ToList(); | |
| 3881 | + var billingItems = await _db.Queryable<LqKdPxmxEntity>() | |
| 3882 | + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 3883 | + .ToListAsync(); | |
| 3884 | + | |
| 3885 | + // 按开单编号分组品项 | |
| 3886 | + var itemsByBilling = billingItems | |
| 3887 | + .GroupBy(x => x.Glkdbh) | |
| 3888 | + .ToDictionary(g => g.Key, g => g.ToList()); | |
| 3889 | + | |
| 3890 | + // 组装返回数据 | |
| 3891 | + var result = members.Select(member => | |
| 3892 | + { | |
| 3893 | + var memberBillings = billings.Where(x => x.Kdhy == member.Id).ToList(); | |
| 3894 | + | |
| 3895 | + return new GoddessCardMemberOutput | |
| 3896 | + { | |
| 3897 | + memberId = member.Id, | |
| 3898 | + memberName = member.Khmc ?? "", | |
| 3899 | + phone = member.Sjh ?? "", | |
| 3900 | + storeId = member.Gsmd ?? "", | |
| 3901 | + storeName = !string.IsNullOrEmpty(member.Gsmd) && stores.ContainsKey(member.Gsmd) ? stores[member.Gsmd] : "", | |
| 3902 | + billingList = memberBillings.Select(b => | |
| 3903 | + { | |
| 3904 | + var hasItems = itemsByBilling.ContainsKey(b.Id); | |
| 3905 | + var items = hasItems ? itemsByBilling[b.Id] : new List<LqKdPxmxEntity>(); | |
| 3906 | + | |
| 3907 | + return new GoddessCardBillingInfo | |
| 3908 | + { | |
| 3909 | + billingId = b.Id, | |
| 3910 | + billingDate = b.Kdrq, | |
| 3911 | + actualPerformance = b.Sfyj, | |
| 3912 | + storeId = b.Djmd ?? "", | |
| 3913 | + storeName = !string.IsNullOrEmpty(b.Djmd) && billingStores.ContainsKey(b.Djmd) ? billingStores[b.Djmd] : "", | |
| 3914 | + itemList = items.Select(item => new GoddessCardBillingItemInfo | |
| 3915 | + { | |
| 3916 | + itemId = item.Id ?? "", | |
| 3917 | + itemCode = item.Px ?? "", | |
| 3918 | + itemName = item.Pxmc ?? "", | |
| 3919 | + itemPrice = item.Pxjg, | |
| 3920 | + sourceType = item.SourceType ?? "", | |
| 3921 | + projectNumber = item.ProjectNumber, | |
| 3922 | + totalPrice = item.TotalPrice, | |
| 3923 | + actualPrice = item.ActualPrice, | |
| 3924 | + performanceTime = item.Yjsj | |
| 3925 | + }).ToList() | |
| 3926 | + }; | |
| 3927 | + }).ToList() | |
| 3928 | + }; | |
| 3929 | + }).ToList(); | |
| 3930 | + | |
| 3931 | + return new | |
| 3847 | 3932 | { |
| 3848 | - new TechTeacherSimpleStatisticsOutput | |
| 3933 | + list = result, | |
| 3934 | + pagination = new | |
| 3849 | 3935 | { |
| 3850 | - DepartmentName = "科技部", | |
| 3851 | - TeacherName = "", | |
| 3852 | - OrderAchievement = 0m, | |
| 3853 | - OrderItemCount = 0, | |
| 3854 | - ConsumeAchievement = 0m, | |
| 3855 | - ConsumeItemCount = 0, | |
| 3856 | - ConsumeProjectCount = 0, | |
| 3857 | - ConsumeLaborCost = 0m, | |
| 3858 | - RefundAchievement = 0m, | |
| 3936 | + pageIndex = input.PageIndex, | |
| 3937 | + pageSize = input.PageSize, | |
| 3938 | + total = totalCount | |
| 3859 | 3939 | } |
| 3860 | 3940 | }; |
| 3861 | 3941 | } |
| 3942 | + catch (Exception ex) | |
| 3943 | + { | |
| 3944 | + _logger.LogError(ex, "获取只买了女神卡的会员数据时发生错误"); | |
| 3945 | + throw NCCException.Oh($"获取数据失败:{ex.Message}"); | |
| 3946 | + } | |
| 3862 | 3947 | } |
| 3863 | - | |
| 3864 | 3948 | #endregion |
| 3865 | 3949 | |
| 3950 | + | |
| 3951 | + | |
| 3866 | 3952 | } |
| 3867 | 3953 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqStoreConsumableInventoryService.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Linq; | |
| 3 | +using System.Threading.Tasks; | |
| 4 | +using Microsoft.AspNetCore.Mvc; | |
| 5 | +using Microsoft.Extensions.Logging; | |
| 6 | +using NCC.Common.Core.Manager; | |
| 7 | +using NCC.Common.Enum; | |
| 8 | +using NCC.Common.Filter; | |
| 9 | +using NCC.Dependency; | |
| 10 | +using NCC.DynamicApiController; | |
| 11 | +using NCC.Extend.Entitys.Dto.LqStoreConsumableInventory; | |
| 12 | +using NCC.Extend.Entitys.Enum; | |
| 13 | +using NCC.Extend.Entitys.lq_mdxx; | |
| 14 | +using NCC.Extend.Entitys.lq_store_consumable_inventory; | |
| 15 | +using NCC.Extend.Interfaces.LqStoreConsumableInventory; | |
| 16 | +using NCC.FriendlyException; | |
| 17 | +using NCC.System.Entitys.Permission; | |
| 18 | +using SqlSugar; | |
| 19 | +using Yitter.IdGenerator; | |
| 20 | + | |
| 21 | +namespace NCC.Extend | |
| 22 | +{ | |
| 23 | + /// <summary> | |
| 24 | + /// 门店消耗品库存服务 | |
| 25 | + /// </summary> | |
| 26 | + [ApiDescriptionSettings(Tag = "绿纤门店消耗品库存管理", Name = "LqStoreConsumableInventory", Order = 200)] | |
| 27 | + [Route("api/Extend/LqStoreConsumableInventory")] | |
| 28 | + public class LqStoreConsumableInventoryService : IDynamicApiController, ITransient, ILqStoreConsumableInventoryService | |
| 29 | + { | |
| 30 | + private readonly IUserManager _userManager; | |
| 31 | + private readonly ILogger<LqStoreConsumableInventoryService> _logger; | |
| 32 | + private readonly ISqlSugarClient _db; | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// 构造函数 | |
| 36 | + /// </summary> | |
| 37 | + public LqStoreConsumableInventoryService(IUserManager userManager, ILogger<LqStoreConsumableInventoryService> logger, ISqlSugarClient db) | |
| 38 | + { | |
| 39 | + _userManager = userManager; | |
| 40 | + _logger = logger; | |
| 41 | + _db = db; | |
| 42 | + } | |
| 43 | + | |
| 44 | + #region 创建门店消耗品库存 | |
| 45 | + /// <summary> | |
| 46 | + /// 创建门店消耗品库存 | |
| 47 | + /// </summary> | |
| 48 | + /// <remarks> | |
| 49 | + /// 为指定门店创建消耗品库存记录 | |
| 50 | + /// | |
| 51 | + /// 示例请求: | |
| 52 | + /// ```json | |
| 53 | + /// { | |
| 54 | + /// "storeId": "门店ID", | |
| 55 | + /// "productType": "毛巾", | |
| 56 | + /// "quantity": 100 | |
| 57 | + /// } | |
| 58 | + /// ``` | |
| 59 | + /// </remarks> | |
| 60 | + /// <param name="input">创建输入</param> | |
| 61 | + /// <returns>创建结果</returns> | |
| 62 | + /// <response code="200">创建成功</response> | |
| 63 | + /// <response code="400">门店不存在或参数错误</response> | |
| 64 | + /// <response code="500">服务器错误</response> | |
| 65 | + [HttpPost("Create")] | |
| 66 | + public async Task CreateAsync([FromBody] LqStoreConsumableInventoryCrInput input) | |
| 67 | + { | |
| 68 | + try | |
| 69 | + { | |
| 70 | + // 验证门店是否存在 | |
| 71 | + var store = await _db.Queryable<LqMdxxEntity>() | |
| 72 | + .Where(x => x.Id == input.StoreId) | |
| 73 | + .FirstAsync(); | |
| 74 | + | |
| 75 | + if (store == null) | |
| 76 | + { | |
| 77 | + throw NCCException.Oh("门店不存在"); | |
| 78 | + } | |
| 79 | + | |
| 80 | + // 检查是否已存在相同门店和产品类型的记录 | |
| 81 | + var existing = await _db.Queryable<LqStoreConsumableInventoryEntity>() | |
| 82 | + .Where(x => x.StoreId == input.StoreId | |
| 83 | + && x.ProductType == input.ProductType | |
| 84 | + && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 85 | + .FirstAsync(); | |
| 86 | + | |
| 87 | + if (existing != null) | |
| 88 | + { | |
| 89 | + throw NCCException.Oh($"该门店已存在{input.ProductType}的库存记录,请使用更新功能"); | |
| 90 | + } | |
| 91 | + | |
| 92 | + // 创建库存记录 | |
| 93 | + var entity = new LqStoreConsumableInventoryEntity | |
| 94 | + { | |
| 95 | + Id = YitIdHelper.NextId().ToString(), | |
| 96 | + StoreId = input.StoreId, | |
| 97 | + ProductType = input.ProductType, | |
| 98 | + Quantity = input.Quantity, | |
| 99 | + IsEffective = StatusEnum.有效.GetHashCode(), | |
| 100 | + CreateUser = _userManager.UserId, | |
| 101 | + CreateTime = DateTime.Now | |
| 102 | + }; | |
| 103 | + | |
| 104 | + var isOk = await _db.Insertable(entity).ExecuteCommandAsync(); | |
| 105 | + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); | |
| 106 | + } | |
| 107 | + catch (Exception ex) | |
| 108 | + { | |
| 109 | + _logger.LogError(ex, "创建门店消耗品库存失败"); | |
| 110 | + throw NCCException.Oh($"创建失败:{ex.Message}"); | |
| 111 | + } | |
| 112 | + } | |
| 113 | + #endregion | |
| 114 | + | |
| 115 | + #region 更新门店消耗品库存 | |
| 116 | + /// <summary> | |
| 117 | + /// 更新门店消耗品库存 | |
| 118 | + /// </summary> | |
| 119 | + /// <remarks> | |
| 120 | + /// 更新指定门店的消耗品库存记录 | |
| 121 | + /// </remarks> | |
| 122 | + /// <param name="input">更新输入</param> | |
| 123 | + /// <returns>更新结果</returns> | |
| 124 | + /// <response code="200">更新成功</response> | |
| 125 | + /// <response code="400">记录不存在或参数错误</response> | |
| 126 | + /// <response code="500">服务器错误</response> | |
| 127 | + [HttpPut("Update")] | |
| 128 | + public async Task UpdateAsync([FromBody] LqStoreConsumableInventoryUpInput input) | |
| 129 | + { | |
| 130 | + try | |
| 131 | + { | |
| 132 | + var existing = await _db.Queryable<LqStoreConsumableInventoryEntity>() | |
| 133 | + .Where(x => x.Id == input.Id && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 134 | + .FirstAsync(); | |
| 135 | + | |
| 136 | + if (existing == null) | |
| 137 | + { | |
| 138 | + throw NCCException.Oh("库存记录不存在或已失效"); | |
| 139 | + } | |
| 140 | + | |
| 141 | + // 验证门店是否存在 | |
| 142 | + var store = await _db.Queryable<LqMdxxEntity>() | |
| 143 | + .Where(x => x.Id == input.StoreId) | |
| 144 | + .FirstAsync(); | |
| 145 | + | |
| 146 | + if (store == null) | |
| 147 | + { | |
| 148 | + throw NCCException.Oh("门店不存在"); | |
| 149 | + } | |
| 150 | + | |
| 151 | + // 如果门店或产品类型改变,检查是否冲突 | |
| 152 | + if (existing.StoreId != input.StoreId || existing.ProductType != input.ProductType) | |
| 153 | + { | |
| 154 | + var conflict = await _db.Queryable<LqStoreConsumableInventoryEntity>() | |
| 155 | + .Where(x => x.Id != input.Id | |
| 156 | + && x.StoreId == input.StoreId | |
| 157 | + && x.ProductType == input.ProductType | |
| 158 | + && x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 159 | + .FirstAsync(); | |
| 160 | + | |
| 161 | + if (conflict != null) | |
| 162 | + { | |
| 163 | + throw NCCException.Oh($"该门店已存在{input.ProductType}的库存记录"); | |
| 164 | + } | |
| 165 | + } | |
| 166 | + | |
| 167 | + // 更新记录 | |
| 168 | + existing.StoreId = input.StoreId; | |
| 169 | + existing.ProductType = input.ProductType; | |
| 170 | + existing.Quantity = input.Quantity; | |
| 171 | + existing.UpdateUser = _userManager.UserId; | |
| 172 | + existing.UpdateTime = DateTime.Now; | |
| 173 | + | |
| 174 | + var isOk = await _db.Updateable(existing).ExecuteCommandAsync(); | |
| 175 | + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); | |
| 176 | + } | |
| 177 | + catch (Exception ex) | |
| 178 | + { | |
| 179 | + _logger.LogError(ex, "更新门店消耗品库存失败"); | |
| 180 | + throw NCCException.Oh($"更新失败:{ex.Message}"); | |
| 181 | + } | |
| 182 | + } | |
| 183 | + #endregion | |
| 184 | + | |
| 185 | + #region 获取门店消耗品库存列表 | |
| 186 | + /// <summary> | |
| 187 | + /// 获取门店消耗品库存列表 | |
| 188 | + /// </summary> | |
| 189 | + /// <remarks> | |
| 190 | + /// 分页查询门店消耗品库存列表,支持按门店、产品类型筛选 | |
| 191 | + /// </remarks> | |
| 192 | + /// <param name="input">查询输入</param> | |
| 193 | + /// <returns>库存列表</returns> | |
| 194 | + /// <response code="200">查询成功</response> | |
| 195 | + /// <response code="500">服务器错误</response> | |
| 196 | + [HttpGet("GetList")] | |
| 197 | + public async Task<dynamic> GetListAsync([FromQuery] LqStoreConsumableInventoryListQueryInput input) | |
| 198 | + { | |
| 199 | + try | |
| 200 | + { | |
| 201 | + var sidx = string.IsNullOrEmpty(input.sidx) ? "createTime" : input.sidx; | |
| 202 | + var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; | |
| 203 | + | |
| 204 | + var data = await _db.Queryable<LqStoreConsumableInventoryEntity, LqMdxxEntity>( | |
| 205 | + (inv, store) => inv.StoreId == store.Id) | |
| 206 | + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (inv, store) => inv.StoreId == input.StoreId) | |
| 207 | + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductType), (inv, store) => inv.ProductType == input.ProductType) | |
| 208 | + .WhereIF(input.IsEffective.HasValue, (inv, store) => inv.IsEffective == input.IsEffective.Value) | |
| 209 | + .Select((inv, store) => new LqStoreConsumableInventoryListOutput | |
| 210 | + { | |
| 211 | + id = inv.Id, | |
| 212 | + storeId = inv.StoreId, | |
| 213 | + storeName = store.Dm ?? "", | |
| 214 | + productType = inv.ProductType, | |
| 215 | + quantity = inv.Quantity, | |
| 216 | + isEffective = inv.IsEffective, | |
| 217 | + createUser = inv.CreateUser, | |
| 218 | + createUserName = "", | |
| 219 | + createTime = inv.CreateTime, | |
| 220 | + updateUser = inv.UpdateUser, | |
| 221 | + updateUserName = "", | |
| 222 | + updateTime = inv.UpdateTime | |
| 223 | + }) | |
| 224 | + .MergeTable() | |
| 225 | + .OrderBy(sidx + " " + sort) | |
| 226 | + .ToPagedListAsync(input.currentPage, input.pageSize); | |
| 227 | + | |
| 228 | + // 补充用户名称信息 | |
| 229 | + var userIds = data.list.SelectMany(x => new[] { x.createUser, x.updateUser }) | |
| 230 | + .Where(x => !string.IsNullOrEmpty(x)) | |
| 231 | + .Distinct() | |
| 232 | + .ToList(); | |
| 233 | + | |
| 234 | + if (userIds.Any()) | |
| 235 | + { | |
| 236 | + var userList = await _db.Queryable<UserEntity>() | |
| 237 | + .Where(x => userIds.Contains(x.Id)) | |
| 238 | + .Select(x => new { x.Id, x.RealName }) | |
| 239 | + .ToListAsync(); | |
| 240 | + var userDict = userList.ToDictionary(k => k.Id, v => v.RealName); | |
| 241 | + | |
| 242 | + foreach (var item in data.list) | |
| 243 | + { | |
| 244 | + item.createUserName = userDict.ContainsKey(item.createUser) ? userDict[item.createUser] : ""; | |
| 245 | + item.updateUserName = !string.IsNullOrEmpty(item.updateUser) && userDict.ContainsKey(item.updateUser) ? userDict[item.updateUser] : ""; | |
| 246 | + } | |
| 247 | + } | |
| 248 | + | |
| 249 | + return PageResult<LqStoreConsumableInventoryListOutput>.SqlSugarPageResult(data); | |
| 250 | + } | |
| 251 | + catch (Exception ex) | |
| 252 | + { | |
| 253 | + _logger.LogError(ex, "获取门店消耗品库存列表失败"); | |
| 254 | + throw NCCException.Oh($"查询失败:{ex.Message}"); | |
| 255 | + } | |
| 256 | + } | |
| 257 | + #endregion | |
| 258 | + | |
| 259 | + #region 获取门店消耗品库存详情 | |
| 260 | + /// <summary> | |
| 261 | + /// 获取门店消耗品库存详情 | |
| 262 | + /// </summary> | |
| 263 | + /// <remarks> | |
| 264 | + /// 根据ID获取门店消耗品库存的详细信息 | |
| 265 | + /// </remarks> | |
| 266 | + /// <param name="id">库存ID</param> | |
| 267 | + /// <returns>库存详情</returns> | |
| 268 | + /// <response code="200">查询成功</response> | |
| 269 | + /// <response code="400">记录不存在</response> | |
| 270 | + /// <response code="500">服务器错误</response> | |
| 271 | + [HttpGet("{id}")] | |
| 272 | + public async Task<LqStoreConsumableInventoryInfoOutput> GetInfoAsync(string id) | |
| 273 | + { | |
| 274 | + try | |
| 275 | + { | |
| 276 | + var entity = await _db.Queryable<LqStoreConsumableInventoryEntity, LqMdxxEntity>( | |
| 277 | + (inv, store) => inv.StoreId == store.Id) | |
| 278 | + .Where((inv, store) => inv.Id == id) | |
| 279 | + .Select((inv, store) => new LqStoreConsumableInventoryInfoOutput | |
| 280 | + { | |
| 281 | + id = inv.Id, | |
| 282 | + storeId = inv.StoreId, | |
| 283 | + storeName = store.Dm ?? "", | |
| 284 | + productType = inv.ProductType, | |
| 285 | + quantity = inv.Quantity, | |
| 286 | + isEffective = inv.IsEffective, | |
| 287 | + createUser = inv.CreateUser, | |
| 288 | + createUserName = "", | |
| 289 | + createTime = inv.CreateTime, | |
| 290 | + updateUser = inv.UpdateUser, | |
| 291 | + updateUserName = "", | |
| 292 | + updateTime = inv.UpdateTime | |
| 293 | + }) | |
| 294 | + .FirstAsync(); | |
| 295 | + | |
| 296 | + if (entity == null) | |
| 297 | + { | |
| 298 | + throw NCCException.Oh("库存记录不存在"); | |
| 299 | + } | |
| 300 | + | |
| 301 | + // 补充用户名称 | |
| 302 | + if (!string.IsNullOrEmpty(entity.createUser)) | |
| 303 | + { | |
| 304 | + var createUser = await _db.Queryable<UserEntity>() | |
| 305 | + .Where(x => x.Id == entity.createUser) | |
| 306 | + .Select(x => x.RealName) | |
| 307 | + .FirstAsync(); | |
| 308 | + entity.createUserName = createUser ?? ""; | |
| 309 | + } | |
| 310 | + | |
| 311 | + if (!string.IsNullOrEmpty(entity.updateUser)) | |
| 312 | + { | |
| 313 | + var updateUser = await _db.Queryable<UserEntity>() | |
| 314 | + .Where(x => x.Id == entity.updateUser) | |
| 315 | + .Select(x => x.RealName) | |
| 316 | + .FirstAsync(); | |
| 317 | + entity.updateUserName = updateUser ?? ""; | |
| 318 | + } | |
| 319 | + | |
| 320 | + return entity; | |
| 321 | + } | |
| 322 | + catch (Exception ex) | |
| 323 | + { | |
| 324 | + _logger.LogError(ex, "获取门店消耗品库存详情失败"); | |
| 325 | + throw NCCException.Oh($"查询失败:{ex.Message}"); | |
| 326 | + } | |
| 327 | + } | |
| 328 | + #endregion | |
| 329 | + | |
| 330 | + #region 删除/作废门店消耗品库存 | |
| 331 | + /// <summary> | |
| 332 | + /// 删除/作废门店消耗品库存 | |
| 333 | + /// </summary> | |
| 334 | + /// <remarks> | |
| 335 | + /// 将库存记录标记为无效 | |
| 336 | + /// </remarks> | |
| 337 | + /// <param name="id">库存ID</param> | |
| 338 | + /// <returns>操作结果</returns> | |
| 339 | + /// <response code="200">操作成功</response> | |
| 340 | + /// <response code="400">记录不存在</response> | |
| 341 | + /// <response code="500">服务器错误</response> | |
| 342 | + [HttpDelete("{id}")] | |
| 343 | + public async Task DeleteAsync(string id) | |
| 344 | + { | |
| 345 | + try | |
| 346 | + { | |
| 347 | + var entity = await _db.Queryable<LqStoreConsumableInventoryEntity>() | |
| 348 | + .Where(x => x.Id == id) | |
| 349 | + .FirstAsync(); | |
| 350 | + | |
| 351 | + if (entity == null) | |
| 352 | + { | |
| 353 | + throw NCCException.Oh("库存记录不存在"); | |
| 354 | + } | |
| 355 | + | |
| 356 | + entity.IsEffective = StatusEnum.无效.GetHashCode(); | |
| 357 | + entity.UpdateUser = _userManager.UserId; | |
| 358 | + entity.UpdateTime = DateTime.Now; | |
| 359 | + | |
| 360 | + var isOk = await _db.Updateable(entity).ExecuteCommandAsync(); | |
| 361 | + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); | |
| 362 | + } | |
| 363 | + catch (Exception ex) | |
| 364 | + { | |
| 365 | + _logger.LogError(ex, "删除门店消耗品库存失败"); | |
| 366 | + throw NCCException.Oh($"删除失败:{ex.Message}"); | |
| 367 | + } | |
| 368 | + } | |
| 369 | + #endregion | |
| 370 | + } | |
| 371 | +} | |
| 372 | + | |
| 373 | + | ... | ... |
sql/创建清洗管理相关表.sql
0 → 100644
| 1 | +-- ============================================ | |
| 2 | +-- 创建清洗管理相关表 | |
| 3 | +-- ============================================ | |
| 4 | +-- 说明:包含门店消耗品库存表、清洗商表、清洗流水表 | |
| 5 | +-- ============================================ | |
| 6 | + | |
| 7 | +-- ============================================ | |
| 8 | +-- 1. 创建门店消耗品库存表(lq_store_consumable_inventory) | |
| 9 | +-- ============================================ | |
| 10 | +CREATE TABLE IF NOT EXISTS `lq_store_consumable_inventory` ( | |
| 11 | + `F_Id` VARCHAR(50) NOT NULL COMMENT '主键ID', | |
| 12 | + `F_StoreId` VARCHAR(50) NULL COMMENT '门店ID(关联lq_mdxx.F_Id)', | |
| 13 | + `F_ProductType` VARCHAR(50) NULL COMMENT '产品类型(枚举:毛巾、垫子等)', | |
| 14 | + `F_Quantity` INT NULL DEFAULT 0 COMMENT '当前库存数量', | |
| 15 | + `F_IsEffective` INT NULL DEFAULT 1 COMMENT '是否有效(1:有效 0:无效)', | |
| 16 | + `F_CreateUser` VARCHAR(50) NULL COMMENT '创建人ID', | |
| 17 | + `F_CreateTime` DATETIME NULL COMMENT '创建时间', | |
| 18 | + `F_UpdateUser` VARCHAR(50) NULL COMMENT '更新人ID', | |
| 19 | + `F_UpdateTime` DATETIME NULL COMMENT '更新时间', | |
| 20 | + PRIMARY KEY (`F_Id`), | |
| 21 | + INDEX `idx_store_id` (`F_StoreId`) COMMENT '门店ID索引', | |
| 22 | + INDEX `idx_product_type` (`F_ProductType`) COMMENT '产品类型索引', | |
| 23 | + INDEX `idx_store_product` (`F_StoreId`, `F_ProductType`) COMMENT '门店+产品类型联合索引' | |
| 24 | +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='门店消耗品库存表'; | |
| 25 | + | |
| 26 | +-- ============================================ | |
| 27 | +-- 2. 创建清洗商表(lq_laundry_supplier) | |
| 28 | +-- ============================================ | |
| 29 | +CREATE TABLE IF NOT EXISTS `lq_laundry_supplier` ( | |
| 30 | + `F_Id` VARCHAR(50) NOT NULL COMMENT '主键ID', | |
| 31 | + `F_SupplierName` VARCHAR(200) NULL COMMENT '清洗商名称', | |
| 32 | + `F_ProductType` VARCHAR(50) NULL COMMENT '产品类型(枚举:毛巾、垫子等)', | |
| 33 | + `F_LaundryPrice` DECIMAL(18,2) NULL DEFAULT 0 COMMENT '清洗价格(当前价格)', | |
| 34 | + `F_Remark` VARCHAR(1000) NULL COMMENT '备注', | |
| 35 | + `F_IsEffective` INT NULL DEFAULT 1 COMMENT '是否有效(1:有效 0:无效)', | |
| 36 | + `F_CreateUser` VARCHAR(50) NULL COMMENT '创建人ID', | |
| 37 | + `F_CreateTime` DATETIME NULL COMMENT '创建时间', | |
| 38 | + `F_UpdateUser` VARCHAR(50) NULL COMMENT '更新人ID', | |
| 39 | + `F_UpdateTime` DATETIME NULL COMMENT '更新时间', | |
| 40 | + PRIMARY KEY (`F_Id`), | |
| 41 | + INDEX `idx_supplier_name` (`F_SupplierName`) COMMENT '清洗商名称索引', | |
| 42 | + INDEX `idx_product_type` (`F_ProductType`) COMMENT '产品类型索引', | |
| 43 | + INDEX `idx_supplier_product` (`F_SupplierName`, `F_ProductType`) COMMENT '清洗商+产品类型联合索引' | |
| 44 | +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='清洗商表'; | |
| 45 | + | |
| 46 | +-- ============================================ | |
| 47 | +-- 3. 创建清洗流水表(lq_laundry_flow) | |
| 48 | +-- ============================================ | |
| 49 | +CREATE TABLE IF NOT EXISTS `lq_laundry_flow` ( | |
| 50 | + `F_Id` VARCHAR(50) NOT NULL COMMENT '主键ID(送出时作为批次号)', | |
| 51 | + `F_FlowType` INT NULL DEFAULT 0 COMMENT '流水类型(0:送出 1:送回)', | |
| 52 | + `F_BatchNumber` VARCHAR(50) NULL COMMENT '批次号(送出时=F_Id,送回时=对应的送出记录的F_Id)', | |
| 53 | + `F_StoreId` VARCHAR(50) NULL COMMENT '门店ID(关联lq_mdxx.F_Id)', | |
| 54 | + `F_ProductType` VARCHAR(50) NULL COMMENT '产品类型(枚举:毛巾、垫子等)', | |
| 55 | + `F_LaundrySupplierId` VARCHAR(50) NULL COMMENT '清洗商ID(关联lq_laundry_supplier.F_Id)', | |
| 56 | + `F_Quantity` INT NULL DEFAULT 0 COMMENT '数量', | |
| 57 | + `F_LaundryPrice` DECIMAL(18,2) NULL DEFAULT 0 COMMENT '清洗单价(记录历史价格)', | |
| 58 | + `F_TotalPrice` DECIMAL(18,2) NULL DEFAULT 0 COMMENT '总费用(数量 × 单价)', | |
| 59 | + `F_Remark` VARCHAR(1000) NULL COMMENT '备注(可说明差异原因,如损坏、丢失等)', | |
| 60 | + `F_IsEffective` INT NULL DEFAULT 1 COMMENT '是否有效(1:有效 0:无效)', | |
| 61 | + `F_CreateUser` VARCHAR(50) NULL COMMENT '创建人ID', | |
| 62 | + `F_CreateTime` DATETIME NULL COMMENT '创建时间', | |
| 63 | + PRIMARY KEY (`F_Id`), | |
| 64 | + INDEX `idx_flow_type` (`F_FlowType`) COMMENT '流水类型索引', | |
| 65 | + INDEX `idx_batch_number` (`F_BatchNumber`) COMMENT '批次号索引', | |
| 66 | + INDEX `idx_store_id` (`F_StoreId`) COMMENT '门店ID索引', | |
| 67 | + INDEX `idx_product_type` (`F_ProductType`) COMMENT '产品类型索引', | |
| 68 | + INDEX `idx_supplier_id` (`F_LaundrySupplierId`) COMMENT '清洗商ID索引', | |
| 69 | + INDEX `idx_create_time` (`F_CreateTime`) COMMENT '创建时间索引', | |
| 70 | + INDEX `idx_store_month` (`F_StoreId`, `F_CreateTime`) COMMENT '门店+时间联合索引(用于月度统计)' | |
| 71 | +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='清洗流水表'; | |
| 72 | + | ... | ... |