From b5ed92da95acbcdd4dd7676b53063b842c51690d Mon Sep 17 00:00:00 2001 From: “wangming” <“wangming@antissoft.com”> Date: Sat, 22 Nov 2025 21:17:04 +0800 Subject: [PATCH] feat: 修复转卡接口和开单品项明细查询接口问题 --- netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateInput.cs | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateOutput.cs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchInfoOutput.cs | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs | 5 +++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListQueryInput.cs | 5 +++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs | 10 ++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LaundryStatisticsInput.cs | 36 ++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowDifferenceOutput.cs | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowInfoOutput.cs | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListOutput.cs | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListQueryInput.cs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowReturnInput.cs | 43 +++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowSendInput.cs | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryStatisticsOutput.cs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierCrInput.cs | 43 +++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierInfoOutput.cs | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListOutput.cs | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListQueryInput.cs | 31 +++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierUpInput.cs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberListQueryInput.cs | 19 +++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberOutput.cs | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs | 5 ----- netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryCrInput.cs | 36 ++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryInfoOutput.cs | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListOutput.cs | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListQueryInput.cs | 31 +++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryUpInput.cs | 43 +++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage/LqInventoryUsageEntity.cs | 6 ++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_flow/LqLaundryFlowEntity.cs | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_supplier/LqLaundrySupplierEntity.cs | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_store_consumable_inventory/LqStoreConsumableInventoryEntity.cs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ConsumableProductTypeEnum.cs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundryFlow/ILqLaundryFlowService.cs | 11 +++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundrySupplier/ILqLaundrySupplierService.cs | 11 +++++++++++ netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqStoreConsumableInventory/ILqStoreConsumableInventoryService.cs | 11 +++++++++++ netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs | 10 ++++------ netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs | 293 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs | 58 ++++++++++++++++++++++++++++++++++------------------------ netcore/src/Modularity/Extend/NCC.Extend/LqLaundryFlowService.cs | 660 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend/LqLaundrySupplierService.cs | 353 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs | 400 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------------------------------------------- netcore/src/Modularity/Extend/NCC.Extend/LqStoreConsumableInventoryService.cs | 373 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sql/创建清洗管理相关表.sql | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 43 files changed, 3838 insertions(+), 192 deletions(-) create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchInfoOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LaundryStatisticsInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowDifferenceOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowInfoOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListQueryInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowReturnInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowSendInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryStatisticsOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierCrInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierInfoOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListQueryInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierUpInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberListQueryInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryCrInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryInfoOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListOutput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListQueryInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryUpInput.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_flow/LqLaundryFlowEntity.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_supplier/LqLaundrySupplierEntity.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_store_consumable_inventory/LqStoreConsumableInventoryEntity.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ConsumableProductTypeEnum.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundryFlow/ILqLaundryFlowService.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundrySupplier/ILqLaundrySupplierService.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqStoreConsumableInventory/ILqStoreConsumableInventoryService.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend/LqLaundryFlowService.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend/LqLaundrySupplierService.cs create mode 100644 netcore/src/Modularity/Extend/NCC.Extend/LqStoreConsumableInventoryService.cs create mode 100644 sql/创建清洗管理相关表.sql diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateInput.cs new file mode 100644 index 0000000..7c1b5b6 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateInput.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqInventoryUsage +{ + /// + /// 库存使用记录批量创建输入 + /// + public class LqInventoryUsageBatchCreateInput + { + /// + /// 使用记录列表 + /// + [Required(ErrorMessage = "使用记录列表不能为空")] + [MinLength(1, ErrorMessage = "至少需要添加一条使用记录")] + [Display(Name = "使用记录列表")] + public List UsageItems { get; set; } + + /// + /// 使用批次ID(可选,不传则自动生成) + /// + [StringLength(50, ErrorMessage = "批次ID长度不能超过50个字符")] + [Display(Name = "使用批次ID")] + public string BatchId { get; set; } + } + + /// + /// 库存使用记录项输入 + /// + public class LqInventoryUsageItemInput + { + /// + /// 产品ID + /// + [Required(ErrorMessage = "产品ID不能为空")] + [StringLength(50, ErrorMessage = "产品ID长度不能超过50个字符")] + [Display(Name = "产品ID")] + public string ProductId { get; set; } + + /// + /// 门店ID + /// + [Required(ErrorMessage = "门店ID不能为空")] + [StringLength(50, ErrorMessage = "门店ID长度不能超过50个字符")] + [Display(Name = "门店ID")] + public string StoreId { get; set; } + + /// + /// 使用时间 + /// + [Required(ErrorMessage = "使用时间不能为空")] + [Display(Name = "使用时间")] + public DateTime UsageTime { get; set; } + + /// + /// 使用数量 + /// + [Required(ErrorMessage = "使用数量不能为空")] + [Range(1, int.MaxValue, ErrorMessage = "使用数量必须大于0")] + [Display(Name = "使用数量")] + public int UsageQuantity { get; set; } + + /// + /// 关联消耗ID(可选) + /// + [StringLength(50, ErrorMessage = "关联消耗ID长度不能超过50个字符")] + [Display(Name = "关联消耗ID")] + public string RelatedConsumeId { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateOutput.cs new file mode 100644 index 0000000..def66e4 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchCreateOutput.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqInventoryUsage +{ + /// + /// 库存使用记录批量创建输出 + /// + public class LqInventoryUsageBatchCreateOutput + { + /// + /// 批次ID + /// + public string BatchId { get; set; } + + /// + /// 成功创建的数量 + /// + public int SuccessCount { get; set; } + + /// + /// 失败的数量 + /// + public int FailCount { get; set; } + + /// + /// 创建成功的记录ID列表 + /// + public List SuccessIds { get; set; } + + /// + /// 失败详情列表 + /// + public List FailItems { get; set; } + } + + /// + /// 批量创建失败项 + /// + public class BatchCreateFailItem + { + /// + /// 失败索引(对应输入列表的索引) + /// + public int Index { get; set; } + + /// + /// 产品ID + /// + public string ProductId { get; set; } + + /// + /// 失败原因 + /// + public string Reason { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchInfoOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchInfoOutput.cs new file mode 100644 index 0000000..b60804e --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageBatchInfoOutput.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqInventoryUsage +{ + /// + /// 库存使用记录批次信息输出 + /// + public class LqInventoryUsageBatchInfoOutput + { + /// + /// 批次ID + /// + public string BatchId { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreateTime { get; set; } + + /// + /// 创建人ID + /// + public string CreateUser { get; set; } + + /// + /// 创建人姓名 + /// + public string CreateUserName { get; set; } + + /// + /// 记录总数 + /// + public int TotalCount { get; set; } + + /// + /// 有效记录数 + /// + public int EffectiveCount { get; set; } + + /// + /// 无效记录数 + /// + public int IneffectiveCount { get; set; } + + /// + /// 使用总数量 + /// + public int TotalUsageQuantity { get; set; } + + /// + /// 使用总金额 + /// + public decimal TotalUsageAmount { get; set; } + + /// + /// 使用记录列表 + /// + public List UsageRecords { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs index 3891c30..9f1b9e1 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListOutput.cs @@ -96,5 +96,10 @@ namespace NCC.Extend.Entitys.Dto.LqInventoryUsage /// 使用总价值 /// public decimal usageTotalValue { get; set; } + + /// + /// 使用批次ID(同一批次申请的使用记录使用相同的批次ID) + /// + public string usageBatchId { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListQueryInput.cs index 23e1ea3..b63961b 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventoryUsage/LqInventoryUsageListQueryInput.cs @@ -51,5 +51,10 @@ namespace NCC.Extend.Entitys.Dto.LqInventoryUsage /// 是否有效 /// public int? IsEffective { get; set; } + + /// + /// 使用批次ID(用于查询同一批次的所有记录) + /// + public string UsageBatchId { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs index b5669e6..f9955be 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdKdjlb/BillingItemDetailListQueryInput.cs @@ -28,6 +28,16 @@ namespace NCC.Extend.Entitys.Dto.LqKdKdjlb public string EndBillingTime { get; set; } /// + /// 开始时间(兼容参数名) + /// + public string startTime { get; set; } + + /// + /// 结束时间(兼容参数名) + /// + public string endTime { get; set; } + + /// /// 营销活动ID /// public string ActivityId { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LaundryStatisticsInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LaundryStatisticsInput.cs new file mode 100644 index 0000000..7fcec65 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LaundryStatisticsInput.cs @@ -0,0 +1,36 @@ +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow +{ + /// + /// 清洗费用统计输入 + /// + public class LaundryStatisticsInput + { + /// + /// 开始月份(格式:YYYYMM,如202411) + /// + [Display(Name = "开始月份")] + public string StartMonth { get; set; } + + /// + /// 结束月份(格式:YYYYMM,如202412) + /// + [Display(Name = "结束月份")] + public string EndMonth { get; set; } + + /// + /// 门店ID(可选,门店统计时使用) + /// + [Display(Name = "门店ID")] + public string StoreId { get; set; } + + /// + /// 产品类型(可选,产品统计时使用) + /// + [Display(Name = "产品类型")] + public string ProductType { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowDifferenceOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowDifferenceOutput.cs new file mode 100644 index 0000000..a2f317d --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowDifferenceOutput.cs @@ -0,0 +1,73 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow +{ + /// + /// 清洗流水差异输出(送出数量 > 送回数量) + /// + public class LqLaundryFlowDifferenceOutput + { + /// + /// 批次号 + /// + [Display(Name = "批次号")] + public string batchNumber { get; set; } + + /// + /// 门店ID + /// + [Display(Name = "门店ID")] + public string storeId { get; set; } + + /// + /// 门店名称 + /// + [Display(Name = "门店名称")] + public string storeName { get; set; } + + /// + /// 产品类型 + /// + [Display(Name = "产品类型")] + public string productType { get; set; } + + /// + /// 送出数量 + /// + [Display(Name = "送出数量")] + public int sendQuantity { get; set; } + + /// + /// 送回数量 + /// + [Display(Name = "送回数量")] + public int returnQuantity { get; set; } + + /// + /// 差异数量 + /// + [Display(Name = "差异数量")] + public int differenceQuantity { get; set; } + + /// + /// 差异说明(备注) + /// + [Display(Name = "差异说明")] + public string differenceRemark { get; set; } + + /// + /// 送出时间 + /// + [Display(Name = "送出时间")] + public DateTime? sendTime { get; set; } + + /// + /// 送回时间 + /// + [Display(Name = "送回时间")] + public DateTime? returnTime { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowInfoOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowInfoOutput.cs new file mode 100644 index 0000000..09071e6 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowInfoOutput.cs @@ -0,0 +1,115 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow +{ + /// + /// 清洗流水详情输出 + /// + public class LqLaundryFlowInfoOutput + { + /// + /// 主键ID + /// + [Display(Name = "ID")] + public string id { get; set; } + + /// + /// 流水类型(0:送出 1:送回) + /// + [Display(Name = "流水类型")] + public int flowType { get; set; } + + /// + /// 流水类型名称 + /// + [Display(Name = "流水类型名称")] + public string flowTypeName { get; set; } + + /// + /// 批次号 + /// + [Display(Name = "批次号")] + public string batchNumber { get; set; } + + /// + /// 门店ID + /// + [Display(Name = "门店ID")] + public string storeId { get; set; } + + /// + /// 门店名称 + /// + [Display(Name = "门店名称")] + public string storeName { get; set; } + + /// + /// 产品类型 + /// + [Display(Name = "产品类型")] + public string productType { get; set; } + + /// + /// 清洗商ID + /// + [Display(Name = "清洗商ID")] + public string laundrySupplierId { get; set; } + + /// + /// 清洗商名称 + /// + [Display(Name = "清洗商名称")] + public string laundrySupplierName { get; set; } + + /// + /// 数量 + /// + [Display(Name = "数量")] + public int quantity { get; set; } + + /// + /// 清洗单价 + /// + [Display(Name = "清洗单价")] + public decimal laundryPrice { get; set; } + + /// + /// 总费用 + /// + [Display(Name = "总费用")] + public decimal totalPrice { get; set; } + + /// + /// 备注 + /// + [Display(Name = "备注")] + public string remark { get; set; } + + /// + /// 是否有效 + /// + [Display(Name = "是否有效")] + public int isEffective { get; set; } + + /// + /// 创建人ID + /// + [Display(Name = "创建人ID")] + public string createUser { get; set; } + + /// + /// 创建人姓名 + /// + [Display(Name = "创建人姓名")] + public string createUserName { get; set; } + + /// + /// 创建时间 + /// + [Display(Name = "创建时间")] + public DateTime createTime { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListOutput.cs new file mode 100644 index 0000000..e0176a3 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListOutput.cs @@ -0,0 +1,115 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow +{ + /// + /// 清洗流水列表输出 + /// + public class LqLaundryFlowListOutput + { + /// + /// 主键ID + /// + [Display(Name = "ID")] + public string id { get; set; } + + /// + /// 流水类型(0:送出 1:送回) + /// + [Display(Name = "流水类型")] + public int flowType { get; set; } + + /// + /// 流水类型名称 + /// + [Display(Name = "流水类型名称")] + public string flowTypeName { get; set; } + + /// + /// 批次号 + /// + [Display(Name = "批次号")] + public string batchNumber { get; set; } + + /// + /// 门店ID + /// + [Display(Name = "门店ID")] + public string storeId { get; set; } + + /// + /// 门店名称 + /// + [Display(Name = "门店名称")] + public string storeName { get; set; } + + /// + /// 产品类型 + /// + [Display(Name = "产品类型")] + public string productType { get; set; } + + /// + /// 清洗商ID + /// + [Display(Name = "清洗商ID")] + public string laundrySupplierId { get; set; } + + /// + /// 清洗商名称 + /// + [Display(Name = "清洗商名称")] + public string laundrySupplierName { get; set; } + + /// + /// 数量 + /// + [Display(Name = "数量")] + public int quantity { get; set; } + + /// + /// 清洗单价 + /// + [Display(Name = "清洗单价")] + public decimal laundryPrice { get; set; } + + /// + /// 总费用 + /// + [Display(Name = "总费用")] + public decimal totalPrice { get; set; } + + /// + /// 备注 + /// + [Display(Name = "备注")] + public string remark { get; set; } + + /// + /// 是否有效 + /// + [Display(Name = "是否有效")] + public int isEffective { get; set; } + + /// + /// 创建人ID + /// + [Display(Name = "创建人ID")] + public string createUser { get; set; } + + /// + /// 创建人姓名 + /// + [Display(Name = "创建人姓名")] + public string createUserName { get; set; } + + /// + /// 创建时间 + /// + [Display(Name = "创建时间")] + public DateTime createTime { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListQueryInput.cs new file mode 100644 index 0000000..116933a --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowListQueryInput.cs @@ -0,0 +1,62 @@ +using NCC.Common.Filter; +using System; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow +{ + /// + /// 清洗流水列表查询输入 + /// + public class LqLaundryFlowListQueryInput : PageInputBase + { + /// + /// 流水类型(0:送出 1:送回) + /// + [Display(Name = "流水类型", Description = "根据流水类型筛选")] + public int? FlowType { get; set; } + + /// + /// 批次号 + /// + [Display(Name = "批次号", Description = "根据批次号筛选")] + public string BatchNumber { get; set; } + + /// + /// 门店ID + /// + [Display(Name = "门店ID", Description = "根据门店ID筛选")] + public string StoreId { get; set; } + + /// + /// 产品类型 + /// + [Display(Name = "产品类型", Description = "根据产品类型筛选")] + public string ProductType { get; set; } + + /// + /// 清洗商ID + /// + [Display(Name = "清洗商ID", Description = "根据清洗商ID筛选")] + public string LaundrySupplierId { get; set; } + + /// + /// 开始时间 + /// + [Display(Name = "开始时间", Description = "根据创建时间范围筛选")] + public DateTime? StartTime { get; set; } + + /// + /// 结束时间 + /// + [Display(Name = "结束时间", Description = "根据创建时间范围筛选")] + public DateTime? EndTime { get; set; } + + /// + /// 是否有效 + /// + [Display(Name = "是否有效", Description = "根据是否有效筛选")] + public int? IsEffective { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowReturnInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowReturnInput.cs new file mode 100644 index 0000000..d3b642a --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowReturnInput.cs @@ -0,0 +1,43 @@ +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow +{ + /// + /// 清洗流水送回输入 + /// + public class LqLaundryFlowReturnInput + { + /// + /// 批次号(对应的送出记录的ID) + /// + [Required(ErrorMessage = "批次号不能为空")] + [StringLength(50, ErrorMessage = "批次号长度不能超过50个字符")] + [Display(Name = "批次号")] + public string BatchNumber { get; set; } + + /// + /// 清洗商ID(可能和送出的清洗商不同) + /// + [Required(ErrorMessage = "清洗商ID不能为空")] + [StringLength(50, ErrorMessage = "清洗商ID长度不能超过50个字符")] + [Display(Name = "清洗商ID")] + public string LaundrySupplierId { get; set; } + + /// + /// 送回数量 + /// + [Required(ErrorMessage = "送回数量不能为空")] + [Range(0, int.MaxValue, ErrorMessage = "送回数量不能小于0")] + [Display(Name = "送回数量")] + public int Quantity { get; set; } + + /// + /// 备注(可说明差异原因,如损坏、丢失等) + /// + [StringLength(1000, ErrorMessage = "备注长度不能超过1000个字符")] + [Display(Name = "备注")] + public string Remark { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowSendInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowSendInput.cs new file mode 100644 index 0000000..d647b0c --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryFlowSendInput.cs @@ -0,0 +1,51 @@ +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow +{ + /// + /// 清洗流水送出输入 + /// + public class LqLaundryFlowSendInput + { + /// + /// 门店ID + /// + [Required(ErrorMessage = "门店ID不能为空")] + [StringLength(50, ErrorMessage = "门店ID长度不能超过50个字符")] + [Display(Name = "门店ID")] + public string StoreId { get; set; } + + /// + /// 产品类型(枚举:毛巾、垫子等) + /// + [Required(ErrorMessage = "产品类型不能为空")] + [StringLength(50, ErrorMessage = "产品类型长度不能超过50个字符")] + [Display(Name = "产品类型")] + public string ProductType { get; set; } + + /// + /// 清洗商ID + /// + [Required(ErrorMessage = "清洗商ID不能为空")] + [StringLength(50, ErrorMessage = "清洗商ID长度不能超过50个字符")] + [Display(Name = "清洗商ID")] + public string LaundrySupplierId { get; set; } + + /// + /// 送出数量 + /// + [Required(ErrorMessage = "送出数量不能为空")] + [Range(1, int.MaxValue, ErrorMessage = "送出数量必须大于0")] + [Display(Name = "送出数量")] + public int Quantity { get; set; } + + /// + /// 备注 + /// + [StringLength(1000, ErrorMessage = "备注长度不能超过1000个字符")] + [Display(Name = "备注")] + public string Remark { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryStatisticsOutput.cs new file mode 100644 index 0000000..6866110 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundryFlow/LqLaundryStatisticsOutput.cs @@ -0,0 +1,49 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundryFlow +{ + /// + /// 清洗费用统计输出 + /// + public class LqLaundryStatisticsOutput + { + /// + /// 门店ID(门店统计时使用) + /// + [Display(Name = "门店ID")] + public string storeId { get; set; } + + /// + /// 门店名称(门店统计时使用) + /// + [Display(Name = "门店名称")] + public string storeName { get; set; } + + /// + /// 产品类型(产品统计时使用) + /// + [Display(Name = "产品类型")] + public string productType { get; set; } + + /// + /// 统计月份(格式:YYYYMM) + /// + [Display(Name = "统计月份")] + public string statisticsMonth { get; set; } + + /// + /// 总费用 + /// + [Display(Name = "总费用")] + public decimal totalPrice { get; set; } + + /// + /// 清洗次数 + /// + [Display(Name = "清洗次数")] + public int count { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierCrInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierCrInput.cs new file mode 100644 index 0000000..6996fef --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierCrInput.cs @@ -0,0 +1,43 @@ +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundrySupplier +{ + /// + /// 清洗商创建输入 + /// + public class LqLaundrySupplierCrInput + { + /// + /// 清洗商名称 + /// + [Required(ErrorMessage = "清洗商名称不能为空")] + [StringLength(200, ErrorMessage = "清洗商名称长度不能超过200个字符")] + [Display(Name = "清洗商名称")] + public string SupplierName { get; set; } + + /// + /// 产品类型(枚举:毛巾、垫子等) + /// + [Required(ErrorMessage = "产品类型不能为空")] + [StringLength(50, ErrorMessage = "产品类型长度不能超过50个字符")] + [Display(Name = "产品类型")] + public string ProductType { get; set; } + + /// + /// 清洗价格 + /// + [Required(ErrorMessage = "清洗价格不能为空")] + [Range(0, double.MaxValue, ErrorMessage = "清洗价格不能小于0")] + [Display(Name = "清洗价格")] + public decimal LaundryPrice { get; set; } + + /// + /// 备注 + /// + [StringLength(1000, ErrorMessage = "备注长度不能超过1000个字符")] + [Display(Name = "备注")] + public string Remark { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierInfoOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierInfoOutput.cs new file mode 100644 index 0000000..acfd131 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierInfoOutput.cs @@ -0,0 +1,85 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundrySupplier +{ + /// + /// 清洗商详情输出 + /// + public class LqLaundrySupplierInfoOutput + { + /// + /// 主键ID + /// + [Display(Name = "ID")] + public string id { get; set; } + + /// + /// 清洗商名称 + /// + [Display(Name = "清洗商名称")] + public string supplierName { get; set; } + + /// + /// 产品类型 + /// + [Display(Name = "产品类型")] + public string productType { get; set; } + + /// + /// 清洗价格 + /// + [Display(Name = "清洗价格")] + public decimal laundryPrice { get; set; } + + /// + /// 备注 + /// + [Display(Name = "备注")] + public string remark { get; set; } + + /// + /// 是否有效 + /// + [Display(Name = "是否有效")] + public int isEffective { get; set; } + + /// + /// 创建人ID + /// + [Display(Name = "创建人ID")] + public string createUser { get; set; } + + /// + /// 创建人姓名 + /// + [Display(Name = "创建人姓名")] + public string createUserName { get; set; } + + /// + /// 创建时间 + /// + [Display(Name = "创建时间")] + public DateTime createTime { get; set; } + + /// + /// 更新人ID + /// + [Display(Name = "更新人ID")] + public string updateUser { get; set; } + + /// + /// 更新人姓名 + /// + [Display(Name = "更新人姓名")] + public string updateUserName { get; set; } + + /// + /// 更新时间 + /// + [Display(Name = "更新时间")] + public DateTime? updateTime { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListOutput.cs new file mode 100644 index 0000000..efc5efc --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListOutput.cs @@ -0,0 +1,85 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundrySupplier +{ + /// + /// 清洗商列表输出 + /// + public class LqLaundrySupplierListOutput + { + /// + /// 主键ID + /// + [Display(Name = "ID")] + public string id { get; set; } + + /// + /// 清洗商名称 + /// + [Display(Name = "清洗商名称")] + public string supplierName { get; set; } + + /// + /// 产品类型 + /// + [Display(Name = "产品类型")] + public string productType { get; set; } + + /// + /// 清洗价格 + /// + [Display(Name = "清洗价格")] + public decimal laundryPrice { get; set; } + + /// + /// 备注 + /// + [Display(Name = "备注")] + public string remark { get; set; } + + /// + /// 是否有效 + /// + [Display(Name = "是否有效")] + public int isEffective { get; set; } + + /// + /// 创建人ID + /// + [Display(Name = "创建人ID")] + public string createUser { get; set; } + + /// + /// 创建人姓名 + /// + [Display(Name = "创建人姓名")] + public string createUserName { get; set; } + + /// + /// 创建时间 + /// + [Display(Name = "创建时间")] + public DateTime createTime { get; set; } + + /// + /// 更新人ID + /// + [Display(Name = "更新人ID")] + public string updateUser { get; set; } + + /// + /// 更新人姓名 + /// + [Display(Name = "更新人姓名")] + public string updateUserName { get; set; } + + /// + /// 更新时间 + /// + [Display(Name = "更新时间")] + public DateTime? updateTime { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListQueryInput.cs new file mode 100644 index 0000000..c60d6f4 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierListQueryInput.cs @@ -0,0 +1,31 @@ +using NCC.Common.Filter; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundrySupplier +{ + /// + /// 清洗商列表查询输入 + /// + public class LqLaundrySupplierListQueryInput : PageInputBase + { + /// + /// 清洗商名称(模糊查询) + /// + [Display(Name = "清洗商名称", Description = "根据清洗商名称筛选")] + public string SupplierName { get; set; } + + /// + /// 产品类型 + /// + [Display(Name = "产品类型", Description = "根据产品类型筛选")] + public string ProductType { get; set; } + + /// + /// 是否有效 + /// + [Display(Name = "是否有效", Description = "根据是否有效筛选")] + public int? IsEffective { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierUpInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierUpInput.cs new file mode 100644 index 0000000..ba744c5 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqLaundrySupplier/LqLaundrySupplierUpInput.cs @@ -0,0 +1,50 @@ +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqLaundrySupplier +{ + /// + /// 清洗商更新输入 + /// + public class LqLaundrySupplierUpInput + { + /// + /// 主键ID + /// + [Required(ErrorMessage = "ID不能为空")] + [Display(Name = "ID")] + public string Id { get; set; } + + /// + /// 清洗商名称 + /// + [Required(ErrorMessage = "清洗商名称不能为空")] + [StringLength(200, ErrorMessage = "清洗商名称长度不能超过200个字符")] + [Display(Name = "清洗商名称")] + public string SupplierName { get; set; } + + /// + /// 产品类型(枚举:毛巾、垫子等) + /// + [Required(ErrorMessage = "产品类型不能为空")] + [StringLength(50, ErrorMessage = "产品类型长度不能超过50个字符")] + [Display(Name = "产品类型")] + public string ProductType { get; set; } + + /// + /// 清洗价格 + /// + [Required(ErrorMessage = "清洗价格不能为空")] + [Range(0, double.MaxValue, ErrorMessage = "清洗价格不能小于0")] + [Display(Name = "清洗价格")] + public decimal LaundryPrice { get; set; } + + /// + /// 备注 + /// + [StringLength(1000, ErrorMessage = "备注长度不能超过1000个字符")] + [Display(Name = "备注")] + public string Remark { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberListQueryInput.cs new file mode 100644 index 0000000..cc62942 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberListQueryInput.cs @@ -0,0 +1,19 @@ +namespace NCC.Extend.Entitys.Dto.LqStatistics +{ + /// + /// 只买了女神卡的会员查询输入 + /// + public class GoddessCardMemberListQueryInput + { + /// + /// 当前页码(从1开始) + /// + public int PageIndex { get; set; } = 1; + + /// + /// 每页数量 + /// + public int PageSize { get; set; } = 20; + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberOutput.cs new file mode 100644 index 0000000..f5efe75 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/GoddessCardMemberOutput.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqStatistics +{ + /// + /// 只买了女神卡的会员输出 + /// + public class GoddessCardMemberOutput + { + /// + /// 会员ID + /// + public string memberId { get; set; } + + /// + /// 会员名称 + /// + public string memberName { get; set; } + + /// + /// 手机号 + /// + public string phone { get; set; } + + /// + /// 归属门店ID + /// + public string storeId { get; set; } + + /// + /// 归属门店名称 + /// + public string storeName { get; set; } + + /// + /// 开单记录列表 + /// + public List billingList { get; set; } + } + + /// + /// 女神卡开单信息 + /// + public class GoddessCardBillingInfo + { + /// + /// 开单编号 + /// + public string billingId { get; set; } + + /// + /// 开单日期 + /// + public DateTime? billingDate { get; set; } + + /// + /// 实付业绩 + /// + public decimal actualPerformance { get; set; } + + /// + /// 门店ID + /// + public string storeId { get; set; } + + /// + /// 门店名称 + /// + public string storeName { get; set; } + + /// + /// 品项列表 + /// + public List itemList { get; set; } + } + + /// + /// 女神卡开单品项信息 + /// + public class GoddessCardBillingItemInfo + { + /// + /// 品项明细ID + /// + public string itemId { get; set; } + + /// + /// 品项编号 + /// + public string itemCode { get; set; } + + /// + /// 品项名称 + /// + public string itemName { get; set; } + + /// + /// 品项价格 + /// + public decimal itemPrice { get; set; } + + /// + /// 来源类型 + /// + public string sourceType { get; set; } + + /// + /// 项目次数 + /// + public decimal projectNumber { get; set; } + + /// + /// 总价 + /// + public decimal totalPrice { get; set; } + + /// + /// 实付金额 + /// + public decimal actualPrice { get; set; } + + /// + /// 业绩时间 + /// + public DateTime? performanceTime { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs index 36f3e5c..365d95f 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/TechTeacherSimpleStatisticsOutput.cs @@ -33,11 +33,6 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics public decimal OrderAchievement { get; set; } /// - /// 开卡品项次数 - /// - public int OrderItemCount { get; set; } - - /// /// 耗卡品项次数 /// public int ConsumeItemCount { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryCrInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryCrInput.cs new file mode 100644 index 0000000..11c9bec --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryCrInput.cs @@ -0,0 +1,36 @@ +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqStoreConsumableInventory +{ + /// + /// 门店消耗品库存创建输入 + /// + public class LqStoreConsumableInventoryCrInput + { + /// + /// 门店ID + /// + [Required(ErrorMessage = "门店ID不能为空")] + [StringLength(50, ErrorMessage = "门店ID长度不能超过50个字符")] + [Display(Name = "门店ID")] + public string StoreId { get; set; } + + /// + /// 产品类型(枚举:毛巾、垫子等) + /// + [Required(ErrorMessage = "产品类型不能为空")] + [StringLength(50, ErrorMessage = "产品类型长度不能超过50个字符")] + [Display(Name = "产品类型")] + public string ProductType { get; set; } + + /// + /// 库存数量 + /// + [Required(ErrorMessage = "库存数量不能为空")] + [Range(0, int.MaxValue, ErrorMessage = "库存数量不能小于0")] + [Display(Name = "库存数量")] + public int Quantity { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryInfoOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryInfoOutput.cs new file mode 100644 index 0000000..3866b07 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryInfoOutput.cs @@ -0,0 +1,85 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqStoreConsumableInventory +{ + /// + /// 门店消耗品库存详情输出 + /// + public class LqStoreConsumableInventoryInfoOutput + { + /// + /// 主键ID + /// + [Display(Name = "ID")] + public string id { get; set; } + + /// + /// 门店ID + /// + [Display(Name = "门店ID")] + public string storeId { get; set; } + + /// + /// 门店名称 + /// + [Display(Name = "门店名称")] + public string storeName { get; set; } + + /// + /// 产品类型 + /// + [Display(Name = "产品类型")] + public string productType { get; set; } + + /// + /// 库存数量 + /// + [Display(Name = "库存数量")] + public int quantity { get; set; } + + /// + /// 是否有效 + /// + [Display(Name = "是否有效")] + public int isEffective { get; set; } + + /// + /// 创建人ID + /// + [Display(Name = "创建人ID")] + public string createUser { get; set; } + + /// + /// 创建人姓名 + /// + [Display(Name = "创建人姓名")] + public string createUserName { get; set; } + + /// + /// 创建时间 + /// + [Display(Name = "创建时间")] + public DateTime createTime { get; set; } + + /// + /// 更新人ID + /// + [Display(Name = "更新人ID")] + public string updateUser { get; set; } + + /// + /// 更新人姓名 + /// + [Display(Name = "更新人姓名")] + public string updateUserName { get; set; } + + /// + /// 更新时间 + /// + [Display(Name = "更新时间")] + public DateTime? updateTime { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListOutput.cs new file mode 100644 index 0000000..18c0068 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListOutput.cs @@ -0,0 +1,85 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqStoreConsumableInventory +{ + /// + /// 门店消耗品库存列表输出 + /// + public class LqStoreConsumableInventoryListOutput + { + /// + /// 主键ID + /// + [Display(Name = "ID")] + public string id { get; set; } + + /// + /// 门店ID + /// + [Display(Name = "门店ID")] + public string storeId { get; set; } + + /// + /// 门店名称 + /// + [Display(Name = "门店名称")] + public string storeName { get; set; } + + /// + /// 产品类型 + /// + [Display(Name = "产品类型")] + public string productType { get; set; } + + /// + /// 库存数量 + /// + [Display(Name = "库存数量")] + public int quantity { get; set; } + + /// + /// 是否有效 + /// + [Display(Name = "是否有效")] + public int isEffective { get; set; } + + /// + /// 创建人ID + /// + [Display(Name = "创建人ID")] + public string createUser { get; set; } + + /// + /// 创建人姓名 + /// + [Display(Name = "创建人姓名")] + public string createUserName { get; set; } + + /// + /// 创建时间 + /// + [Display(Name = "创建时间")] + public DateTime createTime { get; set; } + + /// + /// 更新人ID + /// + [Display(Name = "更新人ID")] + public string updateUser { get; set; } + + /// + /// 更新人姓名 + /// + [Display(Name = "更新人姓名")] + public string updateUserName { get; set; } + + /// + /// 更新时间 + /// + [Display(Name = "更新时间")] + public DateTime? updateTime { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListQueryInput.cs new file mode 100644 index 0000000..2bb8299 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryListQueryInput.cs @@ -0,0 +1,31 @@ +using NCC.Common.Filter; +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqStoreConsumableInventory +{ + /// + /// 门店消耗品库存列表查询输入 + /// + public class LqStoreConsumableInventoryListQueryInput : PageInputBase + { + /// + /// 门店ID + /// + [Display(Name = "门店ID", Description = "根据门店ID筛选")] + public string StoreId { get; set; } + + /// + /// 产品类型 + /// + [Display(Name = "产品类型", Description = "根据产品类型筛选")] + public string ProductType { get; set; } + + /// + /// 是否有效 + /// + [Display(Name = "是否有效", Description = "根据是否有效筛选")] + public int? IsEffective { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryUpInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryUpInput.cs new file mode 100644 index 0000000..54fec19 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStoreConsumableInventory/LqStoreConsumableInventoryUpInput.cs @@ -0,0 +1,43 @@ +using System.ComponentModel.DataAnnotations; + +namespace NCC.Extend.Entitys.Dto.LqStoreConsumableInventory +{ + /// + /// 门店消耗品库存更新输入 + /// + public class LqStoreConsumableInventoryUpInput + { + /// + /// 主键ID + /// + [Required(ErrorMessage = "ID不能为空")] + [Display(Name = "ID")] + public string Id { get; set; } + + /// + /// 门店ID + /// + [Required(ErrorMessage = "门店ID不能为空")] + [StringLength(50, ErrorMessage = "门店ID长度不能超过50个字符")] + [Display(Name = "门店ID")] + public string StoreId { get; set; } + + /// + /// 产品类型(枚举:毛巾、垫子等) + /// + [Required(ErrorMessage = "产品类型不能为空")] + [StringLength(50, ErrorMessage = "产品类型长度不能超过50个字符")] + [Display(Name = "产品类型")] + public string ProductType { get; set; } + + /// + /// 库存数量 + /// + [Required(ErrorMessage = "库存数量不能为空")] + [Range(0, int.MaxValue, ErrorMessage = "库存数量不能小于0")] + [Display(Name = "库存数量")] + public int Quantity { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage/LqInventoryUsageEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage/LqInventoryUsageEntity.cs index 745b1a9..66babf8 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage/LqInventoryUsageEntity.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory_usage/LqInventoryUsageEntity.cs @@ -48,6 +48,12 @@ namespace NCC.Extend.Entitys.lq_inventory_usage public string RelatedConsumeId { get; set; } /// + /// 使用批次ID(同一批次申请的使用记录使用相同的批次ID) + /// + [SugarColumn(ColumnName = "F_UsageBatchId")] + public string UsageBatchId { get; set; } + + /// /// 创建人ID /// [SugarColumn(ColumnName = "F_CreateUser")] diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_flow/LqLaundryFlowEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_flow/LqLaundryFlowEntity.cs new file mode 100644 index 0000000..3fc4e2a --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_flow/LqLaundryFlowEntity.cs @@ -0,0 +1,94 @@ +using System; +using NCC.Common.Const; +using SqlSugar; + +namespace NCC.Extend.Entitys.lq_laundry_flow +{ + /// + /// 清洗流水表 + /// + [SugarTable("lq_laundry_flow")] + [Tenant(ClaimConst.TENANT_ID)] + public class LqLaundryFlowEntity + { + /// + /// 主键ID(送出时作为批次号) + /// + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)] + public string Id { get; set; } + + /// + /// 流水类型(0:送出 1:送回) + /// + [SugarColumn(ColumnName = "F_FlowType")] + public int FlowType { get; set; } = 0; + + /// + /// 批次号(送出时=F_Id,送回时=对应的送出记录的F_Id) + /// + [SugarColumn(ColumnName = "F_BatchNumber")] + public string BatchNumber { get; set; } + + /// + /// 门店ID(关联lq_mdxx.F_Id) + /// + [SugarColumn(ColumnName = "F_StoreId")] + public string StoreId { get; set; } + + /// + /// 产品类型(枚举:毛巾、垫子等) + /// + [SugarColumn(ColumnName = "F_ProductType")] + public string ProductType { get; set; } + + /// + /// 清洗商ID(关联lq_laundry_supplier.F_Id) + /// + [SugarColumn(ColumnName = "F_LaundrySupplierId")] + public string LaundrySupplierId { get; set; } + + /// + /// 数量 + /// + [SugarColumn(ColumnName = "F_Quantity")] + public int Quantity { get; set; } = 0; + + /// + /// 清洗单价(记录历史价格) + /// + [SugarColumn(ColumnName = "F_LaundryPrice")] + public decimal LaundryPrice { get; set; } = 0; + + /// + /// 总费用(数量 × 单价) + /// + [SugarColumn(ColumnName = "F_TotalPrice")] + public decimal TotalPrice { get; set; } = 0; + + /// + /// 备注(可说明差异原因,如损坏、丢失等) + /// + [SugarColumn(ColumnName = "F_Remark")] + public string Remark { get; set; } + + /// + /// 是否有效(1:有效 0:无效) + /// + [SugarColumn(ColumnName = "F_IsEffective")] + public int IsEffective { get; set; } = 1; + + /// + /// 创建人ID + /// + [SugarColumn(ColumnName = "F_CreateUser")] + public string CreateUser { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "F_CreateTime")] + public DateTime CreateTime { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_supplier/LqLaundrySupplierEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_supplier/LqLaundrySupplierEntity.cs new file mode 100644 index 0000000..ba1c15d --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_laundry_supplier/LqLaundrySupplierEntity.cs @@ -0,0 +1,76 @@ +using System; +using NCC.Common.Const; +using SqlSugar; + +namespace NCC.Extend.Entitys.lq_laundry_supplier +{ + /// + /// 清洗商表 + /// + [SugarTable("lq_laundry_supplier")] + [Tenant(ClaimConst.TENANT_ID)] + public class LqLaundrySupplierEntity + { + /// + /// 主键ID + /// + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)] + public string Id { get; set; } + + /// + /// 清洗商名称 + /// + [SugarColumn(ColumnName = "F_SupplierName")] + public string SupplierName { get; set; } + + /// + /// 产品类型(枚举:毛巾、垫子等) + /// + [SugarColumn(ColumnName = "F_ProductType")] + public string ProductType { get; set; } + + /// + /// 清洗价格(当前价格) + /// + [SugarColumn(ColumnName = "F_LaundryPrice")] + public decimal LaundryPrice { get; set; } = 0; + + /// + /// 备注 + /// + [SugarColumn(ColumnName = "F_Remark")] + public string Remark { get; set; } + + /// + /// 是否有效(1:有效 0:无效) + /// + [SugarColumn(ColumnName = "F_IsEffective")] + public int IsEffective { get; set; } = 1; + + /// + /// 创建人ID + /// + [SugarColumn(ColumnName = "F_CreateUser")] + public string CreateUser { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "F_CreateTime")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人ID + /// + [SugarColumn(ColumnName = "F_UpdateUser")] + public string UpdateUser { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "F_UpdateTime")] + public DateTime? UpdateTime { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_store_consumable_inventory/LqStoreConsumableInventoryEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_store_consumable_inventory/LqStoreConsumableInventoryEntity.cs new file mode 100644 index 0000000..32f43e0 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_store_consumable_inventory/LqStoreConsumableInventoryEntity.cs @@ -0,0 +1,70 @@ +using System; +using NCC.Common.Const; +using SqlSugar; + +namespace NCC.Extend.Entitys.lq_store_consumable_inventory +{ + /// + /// 门店消耗品库存表 + /// + [SugarTable("lq_store_consumable_inventory")] + [Tenant(ClaimConst.TENANT_ID)] + public class LqStoreConsumableInventoryEntity + { + /// + /// 主键ID + /// + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)] + public string Id { get; set; } + + /// + /// 门店ID(关联lq_mdxx.F_Id) + /// + [SugarColumn(ColumnName = "F_StoreId")] + public string StoreId { get; set; } + + /// + /// 产品类型(枚举:毛巾、垫子等) + /// + [SugarColumn(ColumnName = "F_ProductType")] + public string ProductType { get; set; } + + /// + /// 当前库存数量 + /// + [SugarColumn(ColumnName = "F_Quantity")] + public int Quantity { get; set; } = 0; + + /// + /// 是否有效(1:有效 0:无效) + /// + [SugarColumn(ColumnName = "F_IsEffective")] + public int IsEffective { get; set; } = 1; + + /// + /// 创建人ID + /// + [SugarColumn(ColumnName = "F_CreateUser")] + public string CreateUser { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "F_CreateTime")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人ID + /// + [SugarColumn(ColumnName = "F_UpdateUser")] + public string UpdateUser { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "F_UpdateTime")] + public DateTime? UpdateTime { get; set; } + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ConsumableProductTypeEnum.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ConsumableProductTypeEnum.cs new file mode 100644 index 0000000..eabc34e --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Enum/ConsumableProductTypeEnum.cs @@ -0,0 +1,47 @@ +using System.ComponentModel; + +namespace NCC.Extend.Entitys.Enum +{ + /// + /// 消耗品产品类型枚举 + /// + public enum ConsumableProductTypeEnum + { + /// + /// 毛巾 + /// + [Description("毛巾")] + 毛巾 = 1, + + /// + /// 垫子 + /// + [Description("垫子")] + 垫子 = 2, + + /// + /// 浴巾 + /// + [Description("浴巾")] + 浴巾 = 3, + + /// + /// 床单 + /// + [Description("床单")] + 床单 = 4, + + /// + /// 枕套 + /// + [Description("枕套")] + 枕套 = 5, + + /// + /// 其他 + /// + [Description("其他")] + 其他 = 99 + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundryFlow/ILqLaundryFlowService.cs b/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundryFlow/ILqLaundryFlowService.cs new file mode 100644 index 0000000..6edc903 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundryFlow/ILqLaundryFlowService.cs @@ -0,0 +1,11 @@ +namespace NCC.Extend.Interfaces.LqLaundryFlow +{ + /// + /// 清洗流水服务接口 + /// + public interface ILqLaundryFlowService + { + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundrySupplier/ILqLaundrySupplierService.cs b/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundrySupplier/ILqLaundrySupplierService.cs new file mode 100644 index 0000000..a7bdfb4 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqLaundrySupplier/ILqLaundrySupplierService.cs @@ -0,0 +1,11 @@ +namespace NCC.Extend.Interfaces.LqLaundrySupplier +{ + /// + /// 清洗商服务接口 + /// + public interface ILqLaundrySupplierService + { + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqStoreConsumableInventory/ILqStoreConsumableInventoryService.cs b/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqStoreConsumableInventory/ILqStoreConsumableInventoryService.cs new file mode 100644 index 0000000..97aca8d --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqStoreConsumableInventory/ILqStoreConsumableInventoryService.cs @@ -0,0 +1,11 @@ +namespace NCC.Extend.Interfaces.LqStoreConsumableInventory +{ + /// + /// 门店消耗品库存服务接口 + /// + public interface ILqStoreConsumableInventoryService + { + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs index 557b462..c23dda0 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs @@ -265,8 +265,8 @@ namespace NCC.Extend FROM lq_kd_kdjlb billing WHERE billing.djmd = store.F_Id AND billing.F_IsEffective = 1 - AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd}' - AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd}' + AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd 00:00:00}' + AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd 23:59:59}' ), 0) as BillingPerformance, -- 退款业绩总和(退卡业绩) COALESCE(( @@ -274,8 +274,8 @@ namespace NCC.Extend FROM lq_hytk_hytk refund WHERE refund.md = store.F_Id AND refund.F_IsEffective = 1 - AND DATE(refund.tksj) >= '{startDate:yyyy-MM-dd}' - AND DATE(refund.tksj) <= '{endDate:yyyy-MM-dd}' + AND DATE(refund.tksj) >= '{startDate:yyyy-MM-dd 00:00:00}' + AND DATE(refund.tksj) <= '{endDate:yyyy-MM-dd 23:59:59}' ), 0) as RefundPerformance FROM lq_mdxx store 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 } #endregion - - #region 获取储值扣减金额统计 /// /// 获取储值扣减金额统计 diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs index 3cfaf01..fdcdfd3 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; @@ -117,6 +118,173 @@ namespace NCC.Extend } #endregion + #region 批量添加库存使用记录 + /// + /// 批量添加库存使用记录 + /// + /// + /// 一次性添加多条库存使用记录,同一批次的所有记录使用相同的批次ID + /// + /// 示例请求: + /// ```json + /// { + /// "batchId": "可选,不传则自动生成", + /// "usageItems": [ + /// { + /// "productId": "产品ID", + /// "storeId": "门店ID", + /// "usageTime": "2024-01-01T10:00:00", + /// "usageQuantity": 10, + /// "relatedConsumeId": "关联消耗ID(可选)" + /// } + /// ] + /// } + /// ``` + /// + /// 参数说明: + /// - batchId: 批次ID,可选。如果不传,系统会自动生成一个唯一的批次ID + /// - usageItems: 使用记录列表,至少需要一条记录 + /// - productId: 产品ID(必填) + /// - storeId: 门店ID(必填) + /// - usageTime: 使用时间(必填) + /// - usageQuantity: 使用数量(必填,必须大于0) + /// - relatedConsumeId: 关联消耗ID(可选) + /// + /// 批量创建输入 + /// 批量创建结果,包含批次ID和成功/失败信息 + /// 批量创建成功,返回批次ID和创建结果 + /// 输入参数错误或库存不足 + /// 服务器错误 + [HttpPost("BatchCreate")] + public async Task BatchCreateAsync([FromBody] LqInventoryUsageBatchCreateInput input) + { + try + { + if (input == null || input.UsageItems == null || !input.UsageItems.Any()) + { + throw NCCException.Oh("使用记录列表不能为空"); + } + + // 生成批次ID(如果未提供) + var batchId = string.IsNullOrWhiteSpace(input.BatchId) + ? YitIdHelper.NextId().ToString() + : input.BatchId; + + var successIds = new List(); + var failItems = new List(); + + _db.Ado.BeginTran(); + + try + { + // 按产品ID分组,批量验证库存 + var productGroups = input.UsageItems + .Select((item, index) => new { Item = item, Index = index }) + .GroupBy(x => x.Item.ProductId) + .ToList(); + + // 计算每个产品的总需求并检查库存 + foreach (var productGroup in productGroups) + { + var productId = productGroup.Key; + var totalRequired = productGroup.Sum(x => x.Item.UsageQuantity); + + // 计算该产品的总库存数量 + var totalInventory = await _db.Queryable() + .Where(x => x.ProductId == productId && x.IsEffective == StatusEnum.有效.GetHashCode()) + .SumAsync(x => (int?)x.Quantity) ?? 0; + + // 计算该产品的已使用数量 + var totalUsage = await _db.Queryable() + .Where(x => x.ProductId == productId && x.IsEffective == StatusEnum.有效.GetHashCode()) + .SumAsync(x => (int?)x.UsageQuantity) ?? 0; + + // 计算可用库存 + var availableInventory = totalInventory - totalUsage; + + // 检查库存是否足够 + if (availableInventory < totalRequired) + { + var failIndices = productGroup.Select(x => x.Index).ToList(); + + foreach (var index in failIndices) + { + failItems.Add(new BatchCreateFailItem + { + Index = index, + ProductId = productId, + Reason = $"库存不足,当前可用库存:{availableInventory},需要数量:{totalRequired}" + }); + } + } + } + + // 创建成功的使用记录 + var entitiesToInsert = new List(); + for (int i = 0; i < input.UsageItems.Count; i++) + { + var item = input.UsageItems[i]; + + // 跳过失败项 + if (failItems.Any(x => x.Index == i)) + { + continue; + } + + var usageEntity = new LqInventoryUsageEntity + { + Id = YitIdHelper.NextId().ToString(), + ProductId = item.ProductId, + StoreId = item.StoreId, + UsageTime = item.UsageTime, + UsageQuantity = item.UsageQuantity, + RelatedConsumeId = item.RelatedConsumeId, + UsageBatchId = batchId, + CreateUser = _userManager.UserId, + CreateTime = DateTime.Now, + IsEffective = StatusEnum.有效.GetHashCode() + }; + + entitiesToInsert.Add(usageEntity); + successIds.Add(usageEntity.Id); + } + + // 批量插入 + if (entitiesToInsert.Any()) + { + var insertCount = await _db.Insertable(entitiesToInsert).ExecuteCommandAsync(); + if (insertCount != entitiesToInsert.Count) + { + throw NCCException.Oh($"批量插入失败,预期插入{entitiesToInsert.Count}条,实际插入{insertCount}条"); + } + } + + _db.Ado.CommitTran(); + + return new LqInventoryUsageBatchCreateOutput + { + BatchId = batchId, + SuccessCount = successIds.Count, + FailCount = failItems.Count, + SuccessIds = successIds, + FailItems = failItems + }; + } + catch + { + _db.Ado.RollbackTran(); + throw; + } + } + catch (Exception ex) + { + _db.Ado.RollbackTran(); + _logger.LogError(ex, "批量添加库存使用记录失败"); + throw NCCException.Oh($"批量添加失败:{ex.Message}"); + } + } + #endregion + #region 作废库存使用记录 /// /// 作废库存使用记录 @@ -185,6 +353,7 @@ namespace NCC.Extend .WhereIF(input.UsageStartTime.HasValue, (usage, product) => usage.UsageTime >= input.UsageStartTime.Value) .WhereIF(input.UsageEndTime.HasValue, (usage, product) => usage.UsageTime <= input.UsageEndTime.Value) .WhereIF(!string.IsNullOrWhiteSpace(input.RelatedConsumeId), (usage, product) => usage.RelatedConsumeId == input.RelatedConsumeId) + .WhereIF(!string.IsNullOrWhiteSpace(input.UsageBatchId), (usage, product) => usage.UsageBatchId == input.UsageBatchId) .WhereIF(input.IsEffective.HasValue, (usage, product) => usage.IsEffective == input.IsEffective.Value) .Select((usage, product) => new LqInventoryUsageListOutput { @@ -198,6 +367,7 @@ namespace NCC.Extend usageTime = usage.UsageTime, usageQuantity = usage.UsageQuantity, relatedConsumeId = usage.RelatedConsumeId, + usageBatchId = usage.UsageBatchId, createUser = usage.CreateUser, createUserName = "", createTime = usage.CreateTime, @@ -258,6 +428,129 @@ namespace NCC.Extend } #endregion + #region 根据批次号获取批次信息 + /// + /// 根据批次号获取批次信息 + /// + /// + /// 根据批次ID查询该批次的所有使用记录信息,包括批次基本信息和详细的使用记录列表 + /// + /// 返回数据结构: + /// - 批次基本信息:批次ID、创建时间、创建人、统计信息等 + /// - 使用记录列表:该批次的所有使用记录详情 + /// + /// 参数说明: + /// - batchId: 批次ID(必填) + /// + /// 批次ID + /// 批次信息,包含该批次的所有使用记录 + /// 查询成功,返回批次信息和使用记录列表 + /// 批次ID不能为空 + /// 批次不存在 + /// 服务器错误 + [HttpGet("GetBatchInfo")] + public async Task GetBatchInfoAsync([FromQuery] string batchId) + { + try + { + if (string.IsNullOrWhiteSpace(batchId)) + { + throw NCCException.Oh("批次ID不能为空"); + } + + // 查询该批次的所有使用记录 + var usageRecords = await _db.Queryable( + (usage, product) => usage.ProductId == product.Id) + .LeftJoin((usage, product, store) => usage.StoreId == store.Id) + .Where((usage, product, store) => usage.UsageBatchId == batchId) + .Select((usage, product, store) => new LqInventoryUsageListOutput + { + id = usage.Id, + productId = usage.ProductId, + productName = product.ProductName, + productCategory = product.ProductCategory, + productPrice = product.Price, + storeId = usage.StoreId, + storeName = store.Dm, + usageTime = usage.UsageTime, + usageQuantity = usage.UsageQuantity, + relatedConsumeId = usage.RelatedConsumeId, + usageBatchId = usage.UsageBatchId, + createUser = usage.CreateUser, + createUserName = "", + createTime = usage.CreateTime, + updateUser = usage.UpdateUser, + updateUserName = "", + updateTime = usage.UpdateTime, + isEffective = usage.IsEffective + }) + .MergeTable() + .OrderBy("createTime") + .ToListAsync(); + + if (!usageRecords.Any()) + { + throw NCCException.Oh("批次不存在或该批次下没有使用记录"); + } + + // 补充用户信息 + var userIds = usageRecords.SelectMany(x => new[] { x.createUser, x.updateUser }) + .Where(x => !string.IsNullOrEmpty(x)) + .Distinct() + .ToList(); + + if (userIds.Any()) + { + var userList = await _db.Queryable() + .Where(x => userIds.Contains(x.Id)) + .Select(x => new { x.Id, x.RealName }) + .ToListAsync(); + var userDict = userList.ToDictionary(k => k.Id, v => v.RealName); + + foreach (var item in usageRecords) + { + if (!string.IsNullOrEmpty(item.createUser) && userDict.ContainsKey(item.createUser)) + item.createUserName = userDict[item.createUser]; + if (!string.IsNullOrEmpty(item.updateUser) && userDict.ContainsKey(item.updateUser)) + item.updateUserName = userDict[item.updateUser]; + } + } + + // 计算使用总金额 + foreach (var record in usageRecords) + { + record.usageTotalValue = record.usageQuantity * record.productPrice; + } + + // 获取批次基本信息(使用第一条记录的创建信息) + var firstRecord = usageRecords.OrderBy(x => x.createTime).First(); + var effectiveRecords = usageRecords.Where(x => x.isEffective == StatusEnum.有效.GetHashCode()).ToList(); + var ineffectiveRecords = usageRecords.Where(x => x.isEffective == StatusEnum.无效.GetHashCode()).ToList(); + + var batchInfo = new LqInventoryUsageBatchInfoOutput + { + BatchId = batchId, + CreateTime = firstRecord.createTime, + CreateUser = firstRecord.createUser, + CreateUserName = firstRecord.createUserName, + TotalCount = usageRecords.Count, + EffectiveCount = effectiveRecords.Count, + IneffectiveCount = ineffectiveRecords.Count, + TotalUsageQuantity = effectiveRecords.Sum(x => x.usageQuantity), + TotalUsageAmount = effectiveRecords.Sum(x => x.usageTotalValue), + UsageRecords = usageRecords + }; + + return batchInfo; + } + catch (Exception ex) + { + _logger.LogError(ex, "获取批次信息失败"); + throw NCCException.Oh($"获取批次信息失败:{ex.Message}"); + } + } + #endregion + #region 统计时间周期内每个产品的使用数量 /// /// 统计时间周期内每个产品的使用数量 diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs index eab8a42..cc72fb8 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs @@ -3099,22 +3099,22 @@ namespace NCC.Extend.LqKdKdjlb // 查询购买数量 var purchasedCount = await _db.Queryable() .Where(x => x.Id == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()) - .SumAsync(x => x.ProjectNumber); + .SumAsync(x => (decimal?)x.ProjectNumber) ?? 0m; // 查询消费数量 var consumedCount = await _db.Queryable() .Where(x => x.BillingItemId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()) - .SumAsync(x => x.OriginalProjectNumber); + .SumAsync(x => x.OriginalProjectNumber) ?? 0m; // 查询退卡数量 var refundedCount = await _db.Queryable() .Where(x => x.BillingItemId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()) - .SumAsync(x => x.ProjectNumber); + .SumAsync(x => (decimal?)x.ProjectNumber) ?? 0m; // 查询储扣数量 var deductCount = await _db.Queryable() .Where(x => x.DeductId == billingItemId && x.IsEffective == StatusEnum.有效.GetHashCode()) - .SumAsync(x => x.ProjectNumber) ?? 0; + .SumAsync(x => (decimal?)x.ProjectNumber) ?? 0m; // 计算剩余数量 var remainingCount = (int)(purchasedCount - consumedCount - refundedCount - deductCount); @@ -3460,15 +3460,34 @@ namespace NCC.Extend.LqKdKdjlb var sidx = input.sidx == null ? "yjsj" : input.sidx; var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort; - // 处理开单时间范围 - List queryBillingTime = null; + // 处理开单时间范围(兼容 StartBillingTime/EndBillingTime 和 startTime/endTime 两种参数名) DateTime? startBillingTime = null; DateTime? endBillingTime = null; - if (!string.IsNullOrEmpty(input.StartBillingTime) && !string.IsNullOrEmpty(input.EndBillingTime)) + + // 优先使用 StartBillingTime/EndBillingTime,如果没有则使用 startTime/endTime + string startTimeStr = !string.IsNullOrEmpty(input.StartBillingTime) ? input.StartBillingTime : input.startTime; + string endTimeStr = !string.IsNullOrEmpty(input.EndBillingTime) ? input.EndBillingTime : input.endTime; + + if (!string.IsNullOrEmpty(startTimeStr) && !string.IsNullOrEmpty(endTimeStr)) { - queryBillingTime = new List { input.StartBillingTime, input.EndBillingTime }; - startBillingTime = Ext.GetDateTime(queryBillingTime.First()); - endBillingTime = Ext.GetDateTime(queryBillingTime.Last()); + // 尝试解析日期字符串(支持多种格式) + if (DateTime.TryParse(startTimeStr, out DateTime startDate)) + { + startBillingTime = startDate; + } + else + { + throw NCCException.Oh($"开始时间格式错误:{startTimeStr}"); + } + + if (DateTime.TryParse(endTimeStr, out DateTime endDate)) + { + endBillingTime = endDate; + } + else + { + throw NCCException.Oh($"结束时间格式错误:{endTimeStr}"); + } } // 优化查询:先分页查询主表,再批量查询关联数据,避免子查询性能问题 @@ -3477,18 +3496,18 @@ namespace NCC.Extend.LqKdKdjlb .Where(pxmx => pxmx.IsEffective == StatusEnum.有效.GetHashCode()) .WhereIF(!string.IsNullOrEmpty(input.Id), pxmx => pxmx.Id == input.Id) .WhereIF(!string.IsNullOrEmpty(input.BillingId), pxmx => pxmx.Glkdbh == input.BillingId) - .WhereIF(queryBillingTime != null && startBillingTime.HasValue, pxmx => pxmx.Yjsj >= new DateTime(startBillingTime.Value.Year, startBillingTime.Value.Month, startBillingTime.Value.Day, 0, 0, 0)) - .WhereIF(queryBillingTime != null && endBillingTime.HasValue, pxmx => pxmx.Yjsj <= new DateTime(endBillingTime.Value.Year, endBillingTime.Value.Month, endBillingTime.Value.Day, 23, 59, 59)) + .WhereIF(startBillingTime.HasValue, pxmx => pxmx.Yjsj >= new DateTime(startBillingTime.Value.Year, startBillingTime.Value.Month, startBillingTime.Value.Day, 0, 0, 0)) + .WhereIF(endBillingTime.HasValue, pxmx => pxmx.Yjsj <= new DateTime(endBillingTime.Value.Year, endBillingTime.Value.Month, endBillingTime.Value.Day, 23, 59, 59)) .WhereIF(!string.IsNullOrEmpty(input.ActivityId), pxmx => pxmx.ActivityId == input.ActivityId) .WhereIF(!string.IsNullOrEmpty(input.MemberId), pxmx => pxmx.MemberId == input.MemberId) .WhereIF(!string.IsNullOrEmpty(input.ItemId), pxmx => pxmx.Px == input.ItemId) .WhereIF(!string.IsNullOrEmpty(input.ItemName), pxmx => pxmx.Pxmc != null && pxmx.Pxmc.Contains(input.ItemName)) - .WhereIF(!string.IsNullOrEmpty(input.SourceType), pxmx => pxmx.SourceType == input.SourceType); + .WhereIF(!string.IsNullOrEmpty(input.SourceType), pxmx => pxmx.SourceType == input.SourceType) + .WhereIF(!string.IsNullOrEmpty(input.ItemType), pxmx => pxmx.ItemCategory == input.ItemType); // 2. 通过 EXISTS 子查询筛选关联字段(在分页前筛选,确保分页准确) baseQuery = baseQuery.WhereIF(!string.IsNullOrEmpty(input.MemberName), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.MemberId && x.Khmc != null && x.Khmc.Contains(input.MemberName)).Any()) .WhereIF(!string.IsNullOrEmpty(input.MemberPhone), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.MemberId && x.Sjh == input.MemberPhone).Any()) - .WhereIF(!string.IsNullOrEmpty(input.ItemType), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.Px && x.Fl4 == input.ItemType).Any()) .WhereIF(!string.IsNullOrEmpty(input.StoreId), pxmx => SqlFunc.Subqueryable().Where(x => x.Id == pxmx.Glkdbh && x.Djmd == input.StoreId).Any()); // 3. 先分页查询主表数据(查询实体类,提高性能) @@ -3498,7 +3517,6 @@ namespace NCC.Extend.LqKdKdjlb var itemIds = pagedData.list.Select(x => x.Id).ToList(); var memberIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.MemberId)).Select(x => x.MemberId).Distinct().ToList(); var activityIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.ActivityId)).Select(x => x.ActivityId).Distinct().ToList(); - var projectIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.Px)).Select(x => x.Px).Distinct().ToList(); var billingIds = pagedData.list.Where(x => !string.IsNullOrEmpty(x.Glkdbh)).Select(x => x.Glkdbh).Distinct().ToList(); // 批量查询会员信息 @@ -3517,14 +3535,6 @@ namespace NCC.Extend.LqKdKdjlb activityDict = activities.ToDictionary(x => x.Id, x => x.ActivityName ?? ""); } - // 批量查询项目资料 - var projectDict = new Dictionary(); - if (projectIds.Any()) - { - var projects = await _db.Queryable().Where(x => projectIds.Contains(x.Id)).Select(x => new { x.Id, x.Qt2 }).ToListAsync(); - projectDict = projects.ToDictionary(x => x.Id, x => x.Qt2 ?? ""); - } - // 批量查询开单记录,获取门店ID var billingStoreDict = new Dictionary(); if (billingIds.Any()) @@ -3552,7 +3562,7 @@ namespace NCC.Extend.LqKdKdjlb memberName = pxmx.MemberId != null && memberDict.ContainsKey(pxmx.MemberId) ? memberDict[pxmx.MemberId].Name : "", memberPhone = pxmx.MemberId != null && memberDict.ContainsKey(pxmx.MemberId) ? memberDict[pxmx.MemberId].Phone : "", itemName = pxmx.Pxmc, - itemType = pxmx.Px != null && projectDict.ContainsKey(pxmx.Px) ? projectDict[pxmx.Px] : "", + itemType = pxmx.ItemCategory, actualPrice = pxmx.ActualPrice, projectNumber = pxmx.ProjectNumber, sourceType = pxmx.SourceType, diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqLaundryFlowService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqLaundryFlowService.cs new file mode 100644 index 0000000..4455261 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqLaundryFlowService.cs @@ -0,0 +1,660 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using NCC.Common.Core.Manager; +using NCC.Common.Enum; +using NCC.Common.Filter; +using NCC.Dependency; +using NCC.DynamicApiController; +using NCC.Extend.Entitys.Dto.LqLaundryFlow; +using NCC.Extend.Entitys.Enum; +using NCC.Extend.Entitys.lq_laundry_flow; +using NCC.Extend.Entitys.lq_laundry_supplier; +using NCC.Extend.Entitys.lq_mdxx; +using NCC.Extend.Interfaces.LqLaundryFlow; +using NCC.FriendlyException; +using NCC.System.Entitys.Permission; +using SqlSugar; +using Yitter.IdGenerator; + +namespace NCC.Extend +{ + /// + /// 清洗流水服务 + /// + [ApiDescriptionSettings(Tag = "绿纤清洗流水管理", Name = "LqLaundryFlow", Order = 200)] + [Route("api/Extend/LqLaundryFlow")] + public class LqLaundryFlowService : IDynamicApiController, ITransient, ILqLaundryFlowService + { + private readonly IUserManager _userManager; + private readonly ILogger _logger; + private readonly ISqlSugarClient _db; + + /// + /// 构造函数 + /// + public LqLaundryFlowService(IUserManager userManager, ILogger logger, ISqlSugarClient db) + { + _userManager = userManager; + _logger = logger; + _db = db; + } + + #region 创建送出记录 + /// + /// 创建送出记录 + /// + /// + /// 门店选择清洗商和产品,填写送出数量,创建送出记录 + /// + /// 示例请求: + /// ```json + /// { + /// "storeId": "门店ID", + /// "productType": "毛巾", + /// "laundrySupplierId": "清洗商ID", + /// "quantity": 100, + /// "remark": "备注" + /// } + /// ``` + /// + /// 送出输入 + /// 创建结果(包含批次号) + /// 创建成功 + /// 参数错误或清洗商不存在 + /// 服务器错误 + [HttpPost("Send")] + public async Task SendAsync([FromBody] LqLaundryFlowSendInput input) + { + try + { + // 验证门店是否存在 + var store = await _db.Queryable() + .Where(x => x.Id == input.StoreId) + .FirstAsync(); + + if (store == null) + { + throw NCCException.Oh("门店不存在"); + } + + // 验证清洗商是否存在 + var supplier = await _db.Queryable() + .Where(x => x.Id == input.LaundrySupplierId && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (supplier == null) + { + throw NCCException.Oh("清洗商不存在或已失效"); + } + + // 验证产品类型是否匹配 + if (supplier.ProductType != input.ProductType) + { + throw NCCException.Oh($"清洗商【{supplier.SupplierName}】不支持清洗产品类型【{input.ProductType}】"); + } + + // 生成批次号(使用ID) + var batchId = YitIdHelper.NextId().ToString(); + + // 创建送出记录 + var entity = new LqLaundryFlowEntity + { + Id = batchId, + FlowType = 0, // 送出 + BatchNumber = batchId, // 批次号等于ID + StoreId = input.StoreId, + ProductType = input.ProductType, + LaundrySupplierId = input.LaundrySupplierId, + Quantity = input.Quantity, + LaundryPrice = supplier.LaundryPrice, // 记录历史价格 + TotalPrice = 0, // 送出时总费用为0 + Remark = input.Remark, + IsEffective = StatusEnum.有效.GetHashCode(), + CreateUser = _userManager.UserId, + CreateTime = DateTime.Now + }; + + var isOk = await _db.Insertable(entity).ExecuteCommandAsync(); + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); + + return new { batchNumber = batchId, message = "送出记录创建成功" }; + } + catch (Exception ex) + { + _logger.LogError(ex, "创建送出记录失败"); + throw NCCException.Oh($"创建失败:{ex.Message}"); + } + } + #endregion + + #region 创建送回记录 + /// + /// 创建送回记录 + /// + /// + /// 清洗完毕后,填写送回清洗商、送回数量,创建送回记录 + /// + /// 示例请求: + /// ```json + /// { + /// "batchNumber": "批次号(对应的送出记录的ID)", + /// "laundrySupplierId": "清洗商ID", + /// "quantity": 95, + /// "remark": "5条损坏" + /// } + /// ``` + /// + /// 送回输入 + /// 创建结果 + /// 创建成功 + /// 批次号不存在或参数错误 + /// 服务器错误 + [HttpPost("Return")] + public async Task ReturnAsync([FromBody] LqLaundryFlowReturnInput input) + { + try + { + // 验证对应的送出记录是否存在 + var sendRecord = await _db.Queryable() + .Where(x => x.BatchNumber == input.BatchNumber && x.FlowType == 0 && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (sendRecord == null) + { + throw NCCException.Oh("对应的送出记录不存在或已失效"); + } + + // 检查是否已经存在送回记录 + var existingReturn = await _db.Queryable() + .Where(x => x.BatchNumber == input.BatchNumber && x.FlowType == 1 && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (existingReturn != null) + { + throw NCCException.Oh("该批次已存在送回记录"); + } + + // 验证清洗商是否存在 + var supplier = await _db.Queryable() + .Where(x => x.Id == input.LaundrySupplierId && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (supplier == null) + { + throw NCCException.Oh("清洗商不存在或已失效"); + } + + // 验证产品类型是否匹配 + if (supplier.ProductType != sendRecord.ProductType) + { + throw NCCException.Oh($"清洗商【{supplier.SupplierName}】不支持清洗产品类型【{sendRecord.ProductType}】"); + } + + // 计算总费用(送回数量 × 清洗单价) + var totalPrice = input.Quantity * supplier.LaundryPrice; + + // 创建送回记录 + var entity = new LqLaundryFlowEntity + { + Id = YitIdHelper.NextId().ToString(), + FlowType = 1, // 送回 + BatchNumber = input.BatchNumber, // 使用送出记录的批次号 + StoreId = sendRecord.StoreId, + ProductType = sendRecord.ProductType, + LaundrySupplierId = input.LaundrySupplierId, + Quantity = input.Quantity, + LaundryPrice = supplier.LaundryPrice, // 记录历史价格(可能已变化) + TotalPrice = totalPrice, + Remark = input.Remark, + IsEffective = StatusEnum.有效.GetHashCode(), + CreateUser = _userManager.UserId, + CreateTime = DateTime.Now + }; + + var isOk = await _db.Insertable(entity).ExecuteCommandAsync(); + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); + + return new { message = "送回记录创建成功", totalPrice = totalPrice }; + } + catch (Exception ex) + { + _logger.LogError(ex, "创建送回记录失败"); + throw NCCException.Oh($"创建失败:{ex.Message}"); + } + } + #endregion + + #region 获取清洗流水列表 + /// + /// 获取清洗流水列表 + /// + /// + /// 分页查询清洗流水列表,支持按流水类型、批次号、门店、产品类型、清洗商、时间范围筛选 + /// + /// 查询输入 + /// 清洗流水列表 + /// 查询成功 + /// 服务器错误 + [HttpGet("GetList")] + public async Task GetListAsync([FromQuery] LqLaundryFlowListQueryInput input) + { + try + { + var sidx = string.IsNullOrEmpty(input.sidx) ? "createTime" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; + + var data = await _db.Queryable( + (flow, store, supplier) => flow.StoreId == store.Id && flow.LaundrySupplierId == supplier.Id) + .WhereIF(input.FlowType.HasValue, (flow, store, supplier) => flow.FlowType == input.FlowType.Value) + .WhereIF(!string.IsNullOrWhiteSpace(input.BatchNumber), (flow, store, supplier) => flow.BatchNumber == input.BatchNumber) + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (flow, store, supplier) => flow.StoreId == input.StoreId) + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductType), (flow, store, supplier) => flow.ProductType == input.ProductType) + .WhereIF(!string.IsNullOrWhiteSpace(input.LaundrySupplierId), (flow, store, supplier) => flow.LaundrySupplierId == input.LaundrySupplierId) + .WhereIF(input.StartTime.HasValue, (flow, store, supplier) => flow.CreateTime >= input.StartTime.Value) + .WhereIF(input.EndTime.HasValue, (flow, store, supplier) => flow.CreateTime <= input.EndTime.Value) + .WhereIF(input.IsEffective.HasValue, (flow, store, supplier) => flow.IsEffective == input.IsEffective.Value) + .Select((flow, store, supplier) => new LqLaundryFlowListOutput + { + id = flow.Id, + flowType = flow.FlowType, + flowTypeName = flow.FlowType == 0 ? "送出" : "送回", + batchNumber = flow.BatchNumber, + storeId = flow.StoreId, + storeName = store.Dm ?? "", + productType = flow.ProductType, + laundrySupplierId = flow.LaundrySupplierId, + laundrySupplierName = supplier.SupplierName ?? "", + quantity = flow.Quantity, + laundryPrice = flow.LaundryPrice, + totalPrice = flow.TotalPrice, + remark = flow.Remark, + isEffective = flow.IsEffective, + createUser = flow.CreateUser, + createUserName = "", + createTime = flow.CreateTime + }) + .MergeTable() + .OrderBy(sidx + " " + sort) + .ToPagedListAsync(input.currentPage, input.pageSize); + + // 补充用户名称信息 + var userIds = data.list.Select(x => x.createUser) + .Where(x => !string.IsNullOrEmpty(x)) + .Distinct() + .ToList(); + + if (userIds.Any()) + { + var userList = await _db.Queryable() + .Where(x => userIds.Contains(x.Id)) + .Select(x => new { x.Id, x.RealName }) + .ToListAsync(); + var userDict = userList.ToDictionary(k => k.Id, v => v.RealName); + + foreach (var item in data.list) + { + item.createUserName = userDict.ContainsKey(item.createUser) ? userDict[item.createUser] : ""; + } + } + + return PageResult.SqlSugarPageResult(data); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取清洗流水列表失败"); + throw NCCException.Oh($"查询失败:{ex.Message}"); + } + } + #endregion + + #region 获取清洗流水详情 + /// + /// 获取清洗流水详情 + /// + /// + /// 根据ID获取清洗流水的详细信息 + /// + /// 流水ID + /// 流水详情 + /// 查询成功 + /// 记录不存在 + /// 服务器错误 + [HttpGet("{id}")] + public async Task GetInfoAsync(string id) + { + try + { + var entity = await _db.Queryable( + (flow, store, supplier) => flow.StoreId == store.Id && flow.LaundrySupplierId == supplier.Id) + .Where((flow, store, supplier) => flow.Id == id) + .Select((flow, store, supplier) => new LqLaundryFlowInfoOutput + { + id = flow.Id, + flowType = flow.FlowType, + flowTypeName = flow.FlowType == 0 ? "送出" : "送回", + batchNumber = flow.BatchNumber, + storeId = flow.StoreId, + storeName = store.Dm ?? "", + productType = flow.ProductType, + laundrySupplierId = flow.LaundrySupplierId, + laundrySupplierName = supplier.SupplierName ?? "", + quantity = flow.Quantity, + laundryPrice = flow.LaundryPrice, + totalPrice = flow.TotalPrice, + remark = flow.Remark, + isEffective = flow.IsEffective, + createUser = flow.CreateUser, + createUserName = "", + createTime = flow.CreateTime + }) + .FirstAsync(); + + if (entity == null) + { + throw NCCException.Oh("流水记录不存在"); + } + + // 补充用户名称 + if (!string.IsNullOrEmpty(entity.createUser)) + { + var createUser = await _db.Queryable() + .Where(x => x.Id == entity.createUser) + .Select(x => x.RealName) + .FirstAsync(); + entity.createUserName = createUser ?? ""; + } + + return entity; + } + catch (Exception ex) + { + _logger.LogError(ex, "获取清洗流水详情失败"); + throw NCCException.Oh($"查询失败:{ex.Message}"); + } + } + #endregion + + #region 查询差异记录 + /// + /// 查询差异记录(送出数量 > 送回数量) + /// + /// + /// 查询所有送出数量大于送回数量的记录,用于追踪差异来源 + /// + /// 查询输入(支持分页) + /// 差异记录列表 + /// 查询成功 + /// 服务器错误 + [HttpPost("GetDifferenceList")] + public async Task GetDifferenceListAsync([FromBody] LqLaundryFlowListQueryInput input) + { + try + { + // 查询所有送出记录 + var sendRecords = await _db.Queryable( + (flow, store) => flow.StoreId == store.Id) + .Where((flow, store) => flow.FlowType == 0 && flow.IsEffective == StatusEnum.有效.GetHashCode()) + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (flow, store) => flow.StoreId == input.StoreId) + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductType), (flow, store) => flow.ProductType == input.ProductType) + .WhereIF(input.StartTime.HasValue, (flow, store) => flow.CreateTime >= input.StartTime.Value) + .WhereIF(input.EndTime.HasValue, (flow, store) => flow.CreateTime <= input.EndTime.Value) + .Select((flow, store) => new + { + flow.BatchNumber, + flow.StoreId, + StoreName = store.Dm ?? "", + flow.ProductType, + SendQuantity = flow.Quantity, + SendTime = flow.CreateTime + }) + .ToListAsync(); + + if (!sendRecords.Any()) + { + return new + { + list = new List(), + pagination = new + { + page = input.currentPage, + pageSize = input.pageSize, + total = 0 + } + }; + } + + // 查询所有送回记录 + var returnRecords = await _db.Queryable() + .Where(x => x.FlowType == 1 && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new + { + x.BatchNumber, + ReturnQuantity = x.Quantity, + ReturnTime = x.CreateTime, + x.Remark + }) + .ToListAsync(); + + var returnDict = returnRecords + .GroupBy(x => x.BatchNumber) + .ToDictionary(g => g.Key, g => g.First()); + + // 计算差异 + var differenceList = sendRecords + .Select(send => new LqLaundryFlowDifferenceOutput + { + batchNumber = send.BatchNumber, + storeId = send.StoreId, + storeName = send.StoreName, + productType = send.ProductType, + sendQuantity = send.SendQuantity, + returnQuantity = returnDict.ContainsKey(send.BatchNumber) ? returnDict[send.BatchNumber].ReturnQuantity : 0, + differenceQuantity = send.SendQuantity - (returnDict.ContainsKey(send.BatchNumber) ? returnDict[send.BatchNumber].ReturnQuantity : 0), + differenceRemark = returnDict.ContainsKey(send.BatchNumber) ? returnDict[send.BatchNumber].Remark : "", + sendTime = send.SendTime, + returnTime = returnDict.ContainsKey(send.BatchNumber) ? returnDict[send.BatchNumber].ReturnTime : (DateTime?)null + }) + .Where(x => x.differenceQuantity > 0) + .ToList(); + + // 手动分页 + var totalCount = differenceList.Count; + var pagedList = differenceList + .Skip((input.currentPage - 1) * input.pageSize) + .Take(input.pageSize) + .ToList(); + + return new + { + list = pagedList, + pagination = new + { + page = input.currentPage, + pageSize = input.pageSize, + total = totalCount + } + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "查询差异记录失败"); + throw NCCException.Oh($"查询失败:{ex.Message}"); + } + } + #endregion + + #region 门店每月清洗费用统计 + /// + /// 门店每月清洗费用统计 + /// + /// + /// 统计每个门店每月的清洗费用(只统计送回记录) + /// + /// 示例请求: + /// ```json + /// { + /// "startMonth": "202411", + /// "endMonth": "202412", + /// "storeId": "门店ID(可选)" + /// } + /// ``` + /// + /// 统计输入 + /// 统计结果 + /// 统计成功 + /// 服务器错误 + [HttpPost("GetStoreMonthlyStatistics")] + public async Task> GetStoreMonthlyStatisticsAsync([FromBody] LaundryStatisticsInput input) + { + try + { + // 构建月份过滤条件 + var startDate = (DateTime?)null; + var endDate = (DateTime?)null; + + if (!string.IsNullOrWhiteSpace(input.StartMonth) && input.StartMonth.Length == 6) + { + var year = int.Parse(input.StartMonth.Substring(0, 4)); + var month = int.Parse(input.StartMonth.Substring(4, 2)); + startDate = new DateTime(year, month, 1); + } + + if (!string.IsNullOrWhiteSpace(input.EndMonth) && input.EndMonth.Length == 6) + { + var year = int.Parse(input.EndMonth.Substring(0, 4)); + var month = int.Parse(input.EndMonth.Substring(4, 2)); + endDate = new DateTime(year, month, DateTime.DaysInMonth(year, month), 23, 59, 59); + } + + var query = _db.Queryable( + (flow, store) => flow.StoreId == store.Id) + .Where((flow, store) => flow.FlowType == 1 && flow.IsEffective == StatusEnum.有效.GetHashCode()) + .WhereIF(startDate.HasValue, (flow, store) => flow.CreateTime >= startDate.Value) + .WhereIF(endDate.HasValue, (flow, store) => flow.CreateTime <= endDate.Value) + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (flow, store) => flow.StoreId == input.StoreId); + + var allRecords = await query + .Select((flow, store) => new + { + flow.StoreId, + StoreName = store.Dm ?? "", + flow.CreateTime, + flow.TotalPrice, + flow.Id + }) + .ToListAsync(); + + // 在内存中分组统计 + var result = allRecords + .GroupBy(x => new { x.StoreId, x.StoreName, Month = x.CreateTime.ToString("yyyyMM") }) + .Select(g => new LqLaundryStatisticsOutput + { + storeId = g.Key.StoreId, + storeName = g.Key.StoreName, + statisticsMonth = g.Key.Month, + totalPrice = g.Sum(x => x.TotalPrice), + count = g.Count() + }) + .OrderBy(x => x.storeId) + .ThenBy(x => x.statisticsMonth) + .ToList(); + + return result; + } + catch (Exception ex) + { + _logger.LogError(ex, "门店每月清洗费用统计失败"); + throw NCCException.Oh($"统计失败:{ex.Message}"); + } + } + #endregion + + #region 产品每月清洗费用统计 + /// + /// 产品每月清洗费用统计 + /// + /// + /// 统计每个产品每月的清洗费用(只统计送回记录) + /// + /// 示例请求: + /// ```json + /// { + /// "startMonth": "202411", + /// "endMonth": "202412", + /// "productType": "毛巾(可选)" + /// } + /// ``` + /// + /// 统计输入 + /// 统计结果 + /// 统计成功 + /// 服务器错误 + [HttpPost("GetProductMonthlyStatistics")] + public async Task> GetProductMonthlyStatisticsAsync([FromBody] LaundryStatisticsInput input) + { + try + { + // 构建月份过滤条件 + var startDate = (DateTime?)null; + var endDate = (DateTime?)null; + + if (!string.IsNullOrWhiteSpace(input.StartMonth) && input.StartMonth.Length == 6) + { + var year = int.Parse(input.StartMonth.Substring(0, 4)); + var month = int.Parse(input.StartMonth.Substring(4, 2)); + startDate = new DateTime(year, month, 1); + } + + if (!string.IsNullOrWhiteSpace(input.EndMonth) && input.EndMonth.Length == 6) + { + var year = int.Parse(input.EndMonth.Substring(0, 4)); + var month = int.Parse(input.EndMonth.Substring(4, 2)); + endDate = new DateTime(year, month, DateTime.DaysInMonth(year, month), 23, 59, 59); + } + + var query = _db.Queryable() + .Where(x => x.FlowType == 1 && x.IsEffective == StatusEnum.有效.GetHashCode()) + .WhereIF(startDate.HasValue, x => x.CreateTime >= startDate.Value) + .WhereIF(endDate.HasValue, x => x.CreateTime <= endDate.Value) + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductType), x => x.ProductType == input.ProductType); + + var allRecords = await query + .Select(x => new + { + x.ProductType, + x.CreateTime, + x.TotalPrice, + x.Id + }) + .ToListAsync(); + + // 在内存中分组统计 + var result = allRecords + .GroupBy(x => new { x.ProductType, Month = x.CreateTime.ToString("yyyyMM") }) + .Select(g => new LqLaundryStatisticsOutput + { + productType = g.Key.ProductType, + statisticsMonth = g.Key.Month, + totalPrice = g.Sum(x => x.TotalPrice), + count = g.Count() + }) + .OrderBy(x => x.productType) + .ThenBy(x => x.statisticsMonth) + .ToList(); + + return result; + } + catch (Exception ex) + { + _logger.LogError(ex, "产品每月清洗费用统计失败"); + throw NCCException.Oh($"统计失败:{ex.Message}"); + } + } + #endregion + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqLaundrySupplierService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqLaundrySupplierService.cs new file mode 100644 index 0000000..213546a --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqLaundrySupplierService.cs @@ -0,0 +1,353 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using NCC.Common.Core.Manager; +using NCC.Common.Enum; +using NCC.Common.Filter; +using NCC.Dependency; +using NCC.DynamicApiController; +using NCC.Extend.Entitys.Dto.LqLaundrySupplier; +using NCC.Extend.Entitys.Enum; +using NCC.Extend.Entitys.lq_laundry_supplier; +using NCC.Extend.Interfaces.LqLaundrySupplier; +using NCC.FriendlyException; +using NCC.System.Entitys.Permission; +using SqlSugar; +using Yitter.IdGenerator; + +namespace NCC.Extend +{ + /// + /// 清洗商服务 + /// + [ApiDescriptionSettings(Tag = "绿纤清洗商管理", Name = "LqLaundrySupplier", Order = 200)] + [Route("api/Extend/LqLaundrySupplier")] + public class LqLaundrySupplierService : IDynamicApiController, ITransient, ILqLaundrySupplierService + { + private readonly IUserManager _userManager; + private readonly ILogger _logger; + private readonly ISqlSugarClient _db; + + /// + /// 构造函数 + /// + public LqLaundrySupplierService(IUserManager userManager, ILogger logger, ISqlSugarClient db) + { + _userManager = userManager; + _logger = logger; + _db = db; + } + + #region 创建清洗商 + /// + /// 创建清洗商 + /// + /// + /// 创建清洗商记录,一个清洗商对应一个产品类型一条记录 + /// + /// 示例请求: + /// ```json + /// { + /// "supplierName": "清洗商A", + /// "productType": "毛巾", + /// "laundryPrice": 5.00, + /// "remark": "备注信息" + /// } + /// ``` + /// + /// 创建输入 + /// 创建结果 + /// 创建成功 + /// 清洗商已存在或参数错误 + /// 服务器错误 + [HttpPost("Create")] + public async Task CreateAsync([FromBody] LqLaundrySupplierCrInput input) + { + try + { + // 检查是否已存在相同清洗商和产品类型的记录 + var existing = await _db.Queryable() + .Where(x => x.SupplierName == input.SupplierName + && x.ProductType == input.ProductType + && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (existing != null) + { + throw NCCException.Oh($"清洗商【{input.SupplierName}】已存在{input.ProductType}的记录"); + } + + // 创建清洗商记录 + var entity = new LqLaundrySupplierEntity + { + Id = YitIdHelper.NextId().ToString(), + SupplierName = input.SupplierName, + ProductType = input.ProductType, + LaundryPrice = input.LaundryPrice, + Remark = input.Remark, + IsEffective = StatusEnum.有效.GetHashCode(), + CreateUser = _userManager.UserId, + CreateTime = DateTime.Now + }; + + var isOk = await _db.Insertable(entity).ExecuteCommandAsync(); + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); + } + catch (Exception ex) + { + _logger.LogError(ex, "创建清洗商失败"); + throw NCCException.Oh($"创建失败:{ex.Message}"); + } + } + #endregion + + #region 更新清洗商 + /// + /// 更新清洗商 + /// + /// + /// 更新清洗商信息,包括价格(更新价格不影响历史流水记录的价格) + /// + /// 更新输入 + /// 更新结果 + /// 更新成功 + /// 记录不存在或参数错误 + /// 服务器错误 + [HttpPut("Update")] + public async Task UpdateAsync([FromBody] LqLaundrySupplierUpInput input) + { + try + { + var existing = await _db.Queryable() + .Where(x => x.Id == input.Id && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (existing == null) + { + throw NCCException.Oh("清洗商记录不存在或已失效"); + } + + // 如果清洗商名称或产品类型改变,检查是否冲突 + if (existing.SupplierName != input.SupplierName || existing.ProductType != input.ProductType) + { + var conflict = await _db.Queryable() + .Where(x => x.Id != input.Id + && x.SupplierName == input.SupplierName + && x.ProductType == input.ProductType + && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (conflict != null) + { + throw NCCException.Oh($"清洗商【{input.SupplierName}】已存在{input.ProductType}的记录"); + } + } + + // 更新记录 + existing.SupplierName = input.SupplierName; + existing.ProductType = input.ProductType; + existing.LaundryPrice = input.LaundryPrice; + existing.Remark = input.Remark; + existing.UpdateUser = _userManager.UserId; + existing.UpdateTime = DateTime.Now; + + var isOk = await _db.Updateable(existing).ExecuteCommandAsync(); + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); + } + catch (Exception ex) + { + _logger.LogError(ex, "更新清洗商失败"); + throw NCCException.Oh($"更新失败:{ex.Message}"); + } + } + #endregion + + #region 获取清洗商列表 + /// + /// 获取清洗商列表 + /// + /// + /// 分页查询清洗商列表,支持按清洗商名称、产品类型筛选 + /// + /// 查询输入 + /// 清洗商列表 + /// 查询成功 + /// 服务器错误 + [HttpGet("GetList")] + public async Task GetListAsync([FromQuery] LqLaundrySupplierListQueryInput input) + { + try + { + var sidx = string.IsNullOrEmpty(input.sidx) ? "createTime" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; + + var data = await _db.Queryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.SupplierName), x => x.SupplierName.Contains(input.SupplierName)) + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductType), x => x.ProductType == input.ProductType) + .WhereIF(input.IsEffective.HasValue, x => x.IsEffective == input.IsEffective.Value) + .Select(x => new LqLaundrySupplierListOutput + { + id = x.Id, + supplierName = x.SupplierName, + productType = x.ProductType, + laundryPrice = x.LaundryPrice, + remark = x.Remark, + isEffective = x.IsEffective, + createUser = x.CreateUser, + createUserName = "", + createTime = x.CreateTime, + updateUser = x.UpdateUser, + updateUserName = "", + updateTime = x.UpdateTime + }) + .MergeTable() + .OrderBy(sidx + " " + sort) + .ToPagedListAsync(input.currentPage, input.pageSize); + + // 补充用户名称信息 + var userIds = data.list.SelectMany(x => new[] { x.createUser, x.updateUser }) + .Where(x => !string.IsNullOrEmpty(x)) + .Distinct() + .ToList(); + + if (userIds.Any()) + { + var userList = await _db.Queryable() + .Where(x => userIds.Contains(x.Id)) + .Select(x => new { x.Id, x.RealName }) + .ToListAsync(); + var userDict = userList.ToDictionary(k => k.Id, v => v.RealName); + + foreach (var item in data.list) + { + item.createUserName = userDict.ContainsKey(item.createUser) ? userDict[item.createUser] : ""; + item.updateUserName = !string.IsNullOrEmpty(item.updateUser) && userDict.ContainsKey(item.updateUser) ? userDict[item.updateUser] : ""; + } + } + + return PageResult.SqlSugarPageResult(data); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取清洗商列表失败"); + throw NCCException.Oh($"查询失败:{ex.Message}"); + } + } + #endregion + + #region 获取清洗商详情 + /// + /// 获取清洗商详情 + /// + /// + /// 根据ID获取清洗商的详细信息 + /// + /// 清洗商ID + /// 清洗商详情 + /// 查询成功 + /// 记录不存在 + /// 服务器错误 + [HttpGet("{id}")] + public async Task GetInfoAsync(string id) + { + try + { + var entity = await _db.Queryable() + .Where(x => x.Id == id) + .Select(x => new LqLaundrySupplierInfoOutput + { + id = x.Id, + supplierName = x.SupplierName, + productType = x.ProductType, + laundryPrice = x.LaundryPrice, + remark = x.Remark, + isEffective = x.IsEffective, + createUser = x.CreateUser, + createUserName = "", + createTime = x.CreateTime, + updateUser = x.UpdateUser, + updateUserName = "", + updateTime = x.UpdateTime + }) + .FirstAsync(); + + if (entity == null) + { + throw NCCException.Oh("清洗商记录不存在"); + } + + // 补充用户名称 + if (!string.IsNullOrEmpty(entity.createUser)) + { + var createUser = await _db.Queryable() + .Where(x => x.Id == entity.createUser) + .Select(x => x.RealName) + .FirstAsync(); + entity.createUserName = createUser ?? ""; + } + + if (!string.IsNullOrEmpty(entity.updateUser)) + { + var updateUser = await _db.Queryable() + .Where(x => x.Id == entity.updateUser) + .Select(x => x.RealName) + .FirstAsync(); + entity.updateUserName = updateUser ?? ""; + } + + return entity; + } + catch (Exception ex) + { + _logger.LogError(ex, "获取清洗商详情失败"); + throw NCCException.Oh($"查询失败:{ex.Message}"); + } + } + #endregion + + #region 删除/作废清洗商 + /// + /// 删除/作废清洗商 + /// + /// + /// 将清洗商记录标记为无效 + /// + /// 清洗商ID + /// 操作结果 + /// 操作成功 + /// 记录不存在 + /// 服务器错误 + [HttpDelete("{id}")] + public async Task DeleteAsync(string id) + { + try + { + var entity = await _db.Queryable() + .Where(x => x.Id == id) + .FirstAsync(); + + if (entity == null) + { + throw NCCException.Oh("清洗商记录不存在"); + } + + entity.IsEffective = StatusEnum.无效.GetHashCode(); + entity.UpdateUser = _userManager.UserId; + entity.UpdateTime = DateTime.Now; + + var isOk = await _db.Updateable(entity).ExecuteCommandAsync(); + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); + } + catch (Exception ex) + { + _logger.LogError(ex, "删除清洗商失败"); + throw NCCException.Oh($"删除失败:{ex.Message}"); + } + } + #endregion + } +} + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs index d2b781a..77942db 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs @@ -26,6 +26,8 @@ using NCC.Extend.Entitys.lq_kd_jksyj; using NCC.Extend.Entitys.lq_kd_kdjlb; using NCC.Extend.Entitys.lq_kd_kjbsyj; using NCC.Extend.Entitys.lq_mdxx; +using NCC.Extend.Entitys.lq_md_target; +using NCC.Extend.Entitys.lq_hytk_hytk; using NCC.Extend.Entitys.lq_md_xdbhsj; using NCC.Extend.Entitys.lq_xh_kjbsyj; using NCC.Extend.Entitys.lq_xh_hyhk; @@ -50,6 +52,7 @@ using NCC.System.Entitys.Permission; using SqlSugar; using Yitter.IdGenerator; using NCC.Extend.Entitys.lq_kd_pxmx; +using NCC.Extend.Entitys.lq_khxx; namespace NCC.Extend.LqStatistics { @@ -886,52 +889,18 @@ namespace NCC.Extend.LqStatistics var now = DateTime.Now; var startDate = new DateTime(now.Year, now.Month, 1); var endDate = startDate.AddMonths(1).AddDays(-1); - // 获取当前月份(YYYYMM格式) var currentMonth = now.ToString("yyyyMM"); - // 1. 获取本月的门店目标业绩总和(从门店目标表获取 F_StoreTarget 字段,按月份过滤) - var targetPerformanceSql = @" - SELECT - COALESCE(SUM(F_StoreTarget), 0) AS TotalTargetPerformance - FROM lq_md_target - WHERE F_Month = @month"; - - var targetParameters = new Dictionary - { - { "@month", currentMonth } - }; - - var targetResult = await _db.Ado.SqlQueryAsync(targetPerformanceSql, targetParameters); - var targetPerformance = 0m; - if (targetResult != null && targetResult.Any()) - { - targetPerformance = Convert.ToDecimal(targetResult.FirstOrDefault()?.TotalTargetPerformance ?? 0); - } - + var targetPerformance = await _db.Queryable().Where(x => x.Month == currentMonth).SumAsync(x => (decimal?)x.StoreTarget) ?? 0m; // 2. 从开单记录表获取本月实付金额的总和(sfyj 字段) - var actualPerformanceSql = @" - SELECT - COALESCE(SUM(sfyj), 0) AS TotalActualPerformance - FROM lq_kd_kdjlb - WHERE F_IsEffective = 1 - AND kdrq >= @startDate - AND kdrq <= @endDate"; - - var parameters = new Dictionary - { - { "@startDate", startDate.ToString("yyyy-MM-dd 00:00:00") }, - { "@endDate", endDate.ToString("yyyy-MM-dd 23:59:59") } - }; - - var actualResult = await _db.Ado.SqlQueryAsync(actualPerformanceSql, parameters); - var actualPerformance = 0m; - if (actualResult != null && actualResult.Any()) - { - actualPerformance = Convert.ToDecimal(actualResult.FirstOrDefault()?.TotalActualPerformance ?? 0); - } - - // 3. 计算完成率 + var endDateTime = endDate.Date.AddDays(1).AddSeconds(-1); // 结束日期的23:59:59 + var billingPerformance = await _db.Queryable().Where(x => x.IsEffective == 1).Where(x => x.Kdrq.HasValue && x.Kdrq.Value >= startDate && x.Kdrq.Value <= endDateTime).SumAsync(x => (decimal?)x.Sfyj) ?? 0m; + // 3. 从退卡记录表获取本月退卡金额的总和(F_ActualRefundAmount 字段) + var refundPerformance = await _db.Queryable().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; + // 4. 计算实际开单业绩(开单业绩 - 退卡金额) + var actualPerformance = billingPerformance - refundPerformance; + // 5. 计算完成率(使用实际开单业绩) var completionRate = 0m; if (targetPerformance > 0) { @@ -941,6 +910,8 @@ namespace NCC.Extend.LqStatistics return new { TargetPerformance = targetPerformance, + BillingPerformance = billingPerformance, + RefundPerformance = refundPerformance, ActualPerformance = actualPerformance, CompletionRate = decimal.Round(completionRate, 2), Month = now.ToString("yyyy年MM月"), @@ -952,6 +923,8 @@ namespace NCC.Extend.LqStatistics return new { TargetPerformance = 0m, + BillingPerformance = 0m, + RefundPerformance = 0m, ActualPerformance = 0m, CompletionRate = 0m, Month = DateTime.Now.ToString("yyyy年MM月"), @@ -3679,7 +3652,6 @@ namespace NCC.Extend.LqStatistics /// - ConsumeProjectCount: 消耗项目数 /// - ConsumeAchievement: 消耗业绩 /// - OrderAchievement: 开单业绩(开卡业绩) - /// - OrderItemCount: 开单品项次数 /// - ConsumeItemCount: 耗卡品项次数 /// - ConsumeLaborCost: 消耗手工费(耗卡手工费) /// @@ -3689,92 +3661,45 @@ namespace NCC.Extend.LqStatistics /// 参数错误 /// 服务器内部错误 [HttpPost("GetTechTeacherStatistics")] - [AllowAnonymous] public async Task> GetTechTeacherStatistics(TechTeacherStatisticsInput input) { + TechTeacherSimpleStatisticsOutput result = new TechTeacherSimpleStatisticsOutput + { + DepartmentName = "科技部", + TeacherName = "", + OrderAchievement = 0m, + ConsumeAchievement = 0m, + ConsumeItemCount = 0, + ConsumeProjectCount = 0, + ConsumeLaborCost = 0m, + RefundAchievement = 0m, + }; try { // 1. 验证必须传入科技老师ID if (string.IsNullOrEmpty(input.TeacherId)) { - return new List - { - new TechTeacherSimpleStatisticsOutput - { - DepartmentName = "科技部", - TeacherName = "", - OrderAchievement = 0m, - OrderItemCount = 0, - ConsumeAchievement = 0m, - ConsumeItemCount = 0, - ConsumeProjectCount = 0, - ConsumeLaborCost = 0m, - RefundAchievement = 0m, - } - }; + return new List { result }; } // 2. 获取科技老师信息 - var teacher = await _db.Queryable() - .Where(x => x.Gw == "科技老师" && x.Id == input.TeacherId) - .Select(x => new - { - TeacherId = x.Id, - TeacherName = x.RealName, - TeacherAccount = x.Account, - }) - .FirstAsync(); - - if (teacher == null) + var teacher = await _db.Queryable().Where(x => x.Gw == "科技老师" && x.Id == input.TeacherId) + .Select(x => new { - return new List - { - new TechTeacherSimpleStatisticsOutput - { - DepartmentName = "科技部", - TeacherName = "", - OrderAchievement = 0m, - OrderItemCount = 0, - ConsumeAchievement = 0m, - ConsumeItemCount = 0, - ConsumeProjectCount = 0, - ConsumeLaborCost = 0m, - RefundAchievement = 0m, - } - }; - } - - // 3. 查询开单业绩(从 lq_kd_kjbsyj 关联 lq_kd_kdjlb 和 lq_kd_pxmx) - var orderQuery = _db.Queryable( - (kjbsyj, kdjlb, pxmx) => kjbsyj.Glkdbh == kdjlb.Id && kjbsyj.Kdpxid == pxmx.Id) - .Where((kjbsyj, kdjlb, pxmx) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode()) - .Where((kjbsyj, kdjlb, pxmx) => kdjlb.IsEffective == StatusEnum.有效.GetHashCode()) - .Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Kjblszh == teacher.TeacherAccount); - - // 日期过滤 - if (input.StartDate.HasValue) - { - orderQuery = orderQuery.Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Yjsj >= input.StartDate.Value); - } + TeacherId = x.Id, + TeacherName = x.RealName, + TeacherAccount = x.Account, + }).FirstAsync(); - if (input.EndDate.HasValue) + if (teacher == null) { - orderQuery = orderQuery.Where((kjbsyj, kdjlb, pxmx) => kjbsyj.Yjsj <= input.EndDate.Value); + return new List { result }; } - - var orderStats = await orderQuery - .Select((kjbsyj, kdjlb, pxmx) => new - { - OrderAchievement = SqlFunc.ToDecimal(kjbsyj.Kjblsyj), - OrderItemCount = SqlFunc.ToInt32(pxmx.ProjectNumber), - }) - .ToListAsync(); + // 3. 查询开单业绩(从 lq_kd_kjbsyj 表) + var OrderAchievement = await _db.Queryable().Where(x => x.Kjbls == teacher.TeacherId && x.IsEffective == StatusEnum.有效.GetHashCode() && x.Yjsj >= input.StartDate.Value && x.Yjsj <= input.EndDate.Value).SumAsync(x => x.Kjblsyj); // 4. 查询耗卡业绩(从 lq_xh_kjbsyj 关联 lq_xh_hyhk 和 lq_xh_pxmx) - // 注意:lq_xh_kjbsyj.kjbls 字段存储的是健康师id,不是科技部老师id - // 科技部老师信息在 kjblszh(账号)和 kjblsxm(姓名)字段 - var consumeQuery = _db.Queryable( - (kjbsyj, hyhk, pxmx) => kjbsyj.Glkdbh == hyhk.Id && kjbsyj.Hkpxid == pxmx.Id) + var consumeQuery = _db.Queryable((kjbsyj, hyhk, pxmx) => kjbsyj.Glkdbh == hyhk.Id && kjbsyj.Hkpxid == pxmx.Id) .Where((kjbsyj, hyhk, pxmx) => kjbsyj.IsEffective == StatusEnum.有效.GetHashCode()) .Where((kjbsyj, hyhk, pxmx) => hyhk.IsEffective == StatusEnum.有效.GetHashCode()) .Where((kjbsyj, hyhk, pxmx) => kjbsyj.Kjblszh == teacher.TeacherAccount); @@ -3799,69 +3724,230 @@ namespace NCC.Extend.LqStatistics ConsumeLaborCost = kjbsyj.LaborCost, }) .ToListAsync(); - // 5. 查询退卡业绩(从 lq_hytk_kjbsyj 表) - var refundQuery = _db.Queryable() - .Where(x => x.IsEffective == StatusEnum.有效.GetHashCode()) - .Where(x => x.Kjblszh == teacher.TeacherAccount); + var RefundAchievement = await _db.Queryable().Where(x => x.Kjbls == teacher.TeacherId && x.IsEffective == StatusEnum.有效.GetHashCode() && x.Tksj >= input.StartDate.Value && x.Tksj <= input.EndDate.Value).SumAsync(x => x.Kjblsyj); + // 6. 统计并返回结果 + result.TeacherName = teacher.TeacherName; + result.OrderAchievement = OrderAchievement.ToDecimal(); + result.ConsumeAchievement = consumeStats.Sum(x => x.ConsumeAchievement ?? 0m); + result.ConsumeItemCount = consumeStats.Sum(x => x.ConsumeItemCount); + result.ConsumeProjectCount = consumeStats.Sum(x => x.ConsumeProjectCount); + result.ConsumeLaborCost = consumeStats.Sum(x => x.ConsumeLaborCost ?? 0m); + result.RefundAchievement = RefundAchievement.ToDecimal(); + return new List { result }; + } + catch (Exception) + { + return new List { result }; + } + } - // 日期过滤 - if (input.StartDate.HasValue) - { - refundQuery = refundQuery.Where(x => x.Tksj >= input.StartDate.Value); - } + #endregion - if (input.EndDate.HasValue) + #region 只买了女神卡的会员统计 + /// + /// 获取只买了女神卡的会员及其开单数据(分页) + /// + /// + /// 统计所有只购买了女神卡(品项编号为61)的会员,并返回这些会员的开单记录 + /// + /// 判断逻辑: + /// 1. 会员必须有购买女神卡的记录 + /// 2. 该会员的所有有效开单记录中,所有品项都必须是女神卡(px = "61") + /// + /// 返回说明: + /// - list: 会员列表 + /// - memberId: 会员ID + /// - memberName: 会员名称 + /// - phone: 手机号 + /// - storeId: 归属门店ID + /// - storeName: 归属门店名称 + /// - billingList: 开单记录列表 + /// - billingId: 开单编号 + /// - billingDate: 开单日期 + /// - actualPerformance: 实付业绩 + /// - storeId: 门店ID + /// - storeName: 门店名称 + /// - itemList: 品项列表 + /// - itemId: 品项明细ID + /// - itemCode: 品项编号(如61) + /// - itemName: 品项名称(如女神卡) + /// - itemPrice: 品项价格 + /// - sourceType: 来源类型 + /// - projectNumber: 项目次数 + /// - totalPrice: 总价 + /// - actualPrice: 实付金额 + /// - performanceTime: 业绩时间 + /// - pagination: 分页信息 + /// - pageIndex: 当前页码 + /// - pageSize: 每页数量 + /// - total: 总记录数 + /// + /// 查询参数 + /// 只买了女神卡的会员列表(分页) + /// 成功返回会员列表 + /// 服务器内部错误 + [HttpPost("GetGoddessCardMembers")] + public async Task GetGoddessCardMembers([FromBody] GoddessCardMemberListQueryInput input) + { + try + { + // 使用SQL一次性查询出符合条件的会员ID + // 逻辑:会员有购买女神卡的记录,且该会员的所有开单记录的所有品项都是女神卡 + var sql = @" + SELECT DISTINCT kd1.Kdhy AS MemberId + FROM lq_kd_pxmx pxmx1 + INNER JOIN lq_kd_kdjlb kd1 ON pxmx1.glkdbh = kd1.F_Id + WHERE pxmx1.px = '61' + AND pxmx1.F_IsEffective = 1 + AND kd1.F_IsEffective = 1 + AND kd1.Kdhy IS NOT NULL + AND kd1.Kdhy != '' + AND NOT EXISTS ( + -- 排除那些有非女神卡品项的会员 + SELECT 1 + FROM lq_kd_pxmx pxmx2 + INNER JOIN lq_kd_kdjlb kd2 ON pxmx2.glkdbh = kd2.F_Id + WHERE kd2.Kdhy = kd1.Kdhy + AND pxmx2.F_IsEffective = 1 + AND kd2.F_IsEffective = 1 + AND pxmx2.px != '61' + )"; + + var validMemberIds = await _db.Ado.SqlQueryAsync(sql); + + if (!validMemberIds.Any()) { - refundQuery = refundQuery.Where(x => x.Tksj <= input.EndDate.Value); + return new + { + list = new List(), + pagination = new + { + pageIndex = input.PageIndex, + pageSize = input.PageSize, + total = 0 + } + }; } - var refundStats = await refundQuery + // 分页处理 + var totalCount = validMemberIds.Count; + var pagedMemberIds = validMemberIds + .Skip((input.PageIndex - 1) * input.PageSize) + .Take(input.PageSize) + .ToList(); + + // 获取会员基本信息 + var members = await _db.Queryable() + .Where(x => pagedMemberIds.Contains(x.Id)) .Select(x => new { - RefundAchievement = x.Kjblsyj, + x.Id, + x.Khmc, + x.Sjh, + x.Gsmd }) .ToListAsync(); - // 6. 统计并返回结果 - var result = new TechTeacherSimpleStatisticsOutput - { - DepartmentName = "科技部", - TeacherName = teacher.TeacherName, - OrderAchievement = orderStats.Sum(x => x.OrderAchievement != null && decimal.TryParse(x.OrderAchievement.ToString(), out var val) ? val : 0m), - OrderItemCount = orderStats.Sum(x => x.OrderItemCount), - ConsumeAchievement = consumeStats.Sum(x => x.ConsumeAchievement ?? 0m), - ConsumeItemCount = consumeStats.Sum(x => x.ConsumeItemCount), - ConsumeProjectCount = consumeStats.Sum(x => x.ConsumeProjectCount), - ConsumeLaborCost = consumeStats.Sum(x => x.ConsumeLaborCost ?? 0m), - RefundAchievement = refundStats.Sum(x => x.RefundAchievement ?? 0m), - }; + // 获取门店信息 + var storeIds = members.Where(x => !string.IsNullOrEmpty(x.Gsmd)).Select(x => x.Gsmd).Distinct().ToList(); + var stores = new Dictionary(); + if (storeIds.Any()) + { + var storeList = await _db.Queryable() + .Where(x => storeIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Dm }) + .ToListAsync(); + stores = storeList.ToDictionary(x => x.Id, x => x.Dm ?? ""); + } - return new List { result }; - } - catch (Exception ex) - { - _logger.LogError(ex, "获取科技部老师业绩统计时发生错误"); - // 发生错误时返回全0的结果,而不是抛出异常 - return new List + // 获取所有开单记录 + var billings = await _db.Queryable().Where(x => pagedMemberIds.Contains(x.Kdhy) && x.IsEffective == StatusEnum.有效.GetHashCode()).ToListAsync(); + + // 获取开单记录的门店信息 + var billingStoreIds = billings.Where(x => !string.IsNullOrEmpty(x.Djmd)).Select(x => x.Djmd).Distinct().ToList(); + var billingStores = new Dictionary(); + if (billingStoreIds.Any()) + { + var billingStoreList = await _db.Queryable() + .Where(x => billingStoreIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Dm }) + .ToListAsync(); + billingStores = billingStoreList.ToDictionary(x => x.Id, x => x.Dm ?? ""); + } + + // 获取所有开单的品项明细 + var billingIds = billings.Select(x => x.Id).ToList(); + var billingItems = await _db.Queryable() + .Where(x => billingIds.Contains(x.Glkdbh) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .ToListAsync(); + + // 按开单编号分组品项 + var itemsByBilling = billingItems + .GroupBy(x => x.Glkdbh) + .ToDictionary(g => g.Key, g => g.ToList()); + + // 组装返回数据 + var result = members.Select(member => + { + var memberBillings = billings.Where(x => x.Kdhy == member.Id).ToList(); + + return new GoddessCardMemberOutput + { + memberId = member.Id, + memberName = member.Khmc ?? "", + phone = member.Sjh ?? "", + storeId = member.Gsmd ?? "", + storeName = !string.IsNullOrEmpty(member.Gsmd) && stores.ContainsKey(member.Gsmd) ? stores[member.Gsmd] : "", + billingList = memberBillings.Select(b => + { + var hasItems = itemsByBilling.ContainsKey(b.Id); + var items = hasItems ? itemsByBilling[b.Id] : new List(); + + return new GoddessCardBillingInfo + { + billingId = b.Id, + billingDate = b.Kdrq, + actualPerformance = b.Sfyj, + storeId = b.Djmd ?? "", + storeName = !string.IsNullOrEmpty(b.Djmd) && billingStores.ContainsKey(b.Djmd) ? billingStores[b.Djmd] : "", + itemList = items.Select(item => new GoddessCardBillingItemInfo + { + itemId = item.Id ?? "", + itemCode = item.Px ?? "", + itemName = item.Pxmc ?? "", + itemPrice = item.Pxjg, + sourceType = item.SourceType ?? "", + projectNumber = item.ProjectNumber, + totalPrice = item.TotalPrice, + actualPrice = item.ActualPrice, + performanceTime = item.Yjsj + }).ToList() + }; + }).ToList() + }; + }).ToList(); + + return new { - new TechTeacherSimpleStatisticsOutput + list = result, + pagination = new { - DepartmentName = "科技部", - TeacherName = "", - OrderAchievement = 0m, - OrderItemCount = 0, - ConsumeAchievement = 0m, - ConsumeItemCount = 0, - ConsumeProjectCount = 0, - ConsumeLaborCost = 0m, - RefundAchievement = 0m, + pageIndex = input.PageIndex, + pageSize = input.PageSize, + total = totalCount } }; } + catch (Exception ex) + { + _logger.LogError(ex, "获取只买了女神卡的会员数据时发生错误"); + throw NCCException.Oh($"获取数据失败:{ex.Message}"); + } } - #endregion + + } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqStoreConsumableInventoryService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqStoreConsumableInventoryService.cs new file mode 100644 index 0000000..367f998 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqStoreConsumableInventoryService.cs @@ -0,0 +1,373 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using NCC.Common.Core.Manager; +using NCC.Common.Enum; +using NCC.Common.Filter; +using NCC.Dependency; +using NCC.DynamicApiController; +using NCC.Extend.Entitys.Dto.LqStoreConsumableInventory; +using NCC.Extend.Entitys.Enum; +using NCC.Extend.Entitys.lq_mdxx; +using NCC.Extend.Entitys.lq_store_consumable_inventory; +using NCC.Extend.Interfaces.LqStoreConsumableInventory; +using NCC.FriendlyException; +using NCC.System.Entitys.Permission; +using SqlSugar; +using Yitter.IdGenerator; + +namespace NCC.Extend +{ + /// + /// 门店消耗品库存服务 + /// + [ApiDescriptionSettings(Tag = "绿纤门店消耗品库存管理", Name = "LqStoreConsumableInventory", Order = 200)] + [Route("api/Extend/LqStoreConsumableInventory")] + public class LqStoreConsumableInventoryService : IDynamicApiController, ITransient, ILqStoreConsumableInventoryService + { + private readonly IUserManager _userManager; + private readonly ILogger _logger; + private readonly ISqlSugarClient _db; + + /// + /// 构造函数 + /// + public LqStoreConsumableInventoryService(IUserManager userManager, ILogger logger, ISqlSugarClient db) + { + _userManager = userManager; + _logger = logger; + _db = db; + } + + #region 创建门店消耗品库存 + /// + /// 创建门店消耗品库存 + /// + /// + /// 为指定门店创建消耗品库存记录 + /// + /// 示例请求: + /// ```json + /// { + /// "storeId": "门店ID", + /// "productType": "毛巾", + /// "quantity": 100 + /// } + /// ``` + /// + /// 创建输入 + /// 创建结果 + /// 创建成功 + /// 门店不存在或参数错误 + /// 服务器错误 + [HttpPost("Create")] + public async Task CreateAsync([FromBody] LqStoreConsumableInventoryCrInput input) + { + try + { + // 验证门店是否存在 + var store = await _db.Queryable() + .Where(x => x.Id == input.StoreId) + .FirstAsync(); + + if (store == null) + { + throw NCCException.Oh("门店不存在"); + } + + // 检查是否已存在相同门店和产品类型的记录 + var existing = await _db.Queryable() + .Where(x => x.StoreId == input.StoreId + && x.ProductType == input.ProductType + && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (existing != null) + { + throw NCCException.Oh($"该门店已存在{input.ProductType}的库存记录,请使用更新功能"); + } + + // 创建库存记录 + var entity = new LqStoreConsumableInventoryEntity + { + Id = YitIdHelper.NextId().ToString(), + StoreId = input.StoreId, + ProductType = input.ProductType, + Quantity = input.Quantity, + IsEffective = StatusEnum.有效.GetHashCode(), + CreateUser = _userManager.UserId, + CreateTime = DateTime.Now + }; + + var isOk = await _db.Insertable(entity).ExecuteCommandAsync(); + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); + } + catch (Exception ex) + { + _logger.LogError(ex, "创建门店消耗品库存失败"); + throw NCCException.Oh($"创建失败:{ex.Message}"); + } + } + #endregion + + #region 更新门店消耗品库存 + /// + /// 更新门店消耗品库存 + /// + /// + /// 更新指定门店的消耗品库存记录 + /// + /// 更新输入 + /// 更新结果 + /// 更新成功 + /// 记录不存在或参数错误 + /// 服务器错误 + [HttpPut("Update")] + public async Task UpdateAsync([FromBody] LqStoreConsumableInventoryUpInput input) + { + try + { + var existing = await _db.Queryable() + .Where(x => x.Id == input.Id && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (existing == null) + { + throw NCCException.Oh("库存记录不存在或已失效"); + } + + // 验证门店是否存在 + var store = await _db.Queryable() + .Where(x => x.Id == input.StoreId) + .FirstAsync(); + + if (store == null) + { + throw NCCException.Oh("门店不存在"); + } + + // 如果门店或产品类型改变,检查是否冲突 + if (existing.StoreId != input.StoreId || existing.ProductType != input.ProductType) + { + var conflict = await _db.Queryable() + .Where(x => x.Id != input.Id + && x.StoreId == input.StoreId + && x.ProductType == input.ProductType + && x.IsEffective == StatusEnum.有效.GetHashCode()) + .FirstAsync(); + + if (conflict != null) + { + throw NCCException.Oh($"该门店已存在{input.ProductType}的库存记录"); + } + } + + // 更新记录 + existing.StoreId = input.StoreId; + existing.ProductType = input.ProductType; + existing.Quantity = input.Quantity; + existing.UpdateUser = _userManager.UserId; + existing.UpdateTime = DateTime.Now; + + var isOk = await _db.Updateable(existing).ExecuteCommandAsync(); + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); + } + catch (Exception ex) + { + _logger.LogError(ex, "更新门店消耗品库存失败"); + throw NCCException.Oh($"更新失败:{ex.Message}"); + } + } + #endregion + + #region 获取门店消耗品库存列表 + /// + /// 获取门店消耗品库存列表 + /// + /// + /// 分页查询门店消耗品库存列表,支持按门店、产品类型筛选 + /// + /// 查询输入 + /// 库存列表 + /// 查询成功 + /// 服务器错误 + [HttpGet("GetList")] + public async Task GetListAsync([FromQuery] LqStoreConsumableInventoryListQueryInput input) + { + try + { + var sidx = string.IsNullOrEmpty(input.sidx) ? "createTime" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; + + var data = await _db.Queryable( + (inv, store) => inv.StoreId == store.Id) + .WhereIF(!string.IsNullOrWhiteSpace(input.StoreId), (inv, store) => inv.StoreId == input.StoreId) + .WhereIF(!string.IsNullOrWhiteSpace(input.ProductType), (inv, store) => inv.ProductType == input.ProductType) + .WhereIF(input.IsEffective.HasValue, (inv, store) => inv.IsEffective == input.IsEffective.Value) + .Select((inv, store) => new LqStoreConsumableInventoryListOutput + { + id = inv.Id, + storeId = inv.StoreId, + storeName = store.Dm ?? "", + productType = inv.ProductType, + quantity = inv.Quantity, + isEffective = inv.IsEffective, + createUser = inv.CreateUser, + createUserName = "", + createTime = inv.CreateTime, + updateUser = inv.UpdateUser, + updateUserName = "", + updateTime = inv.UpdateTime + }) + .MergeTable() + .OrderBy(sidx + " " + sort) + .ToPagedListAsync(input.currentPage, input.pageSize); + + // 补充用户名称信息 + var userIds = data.list.SelectMany(x => new[] { x.createUser, x.updateUser }) + .Where(x => !string.IsNullOrEmpty(x)) + .Distinct() + .ToList(); + + if (userIds.Any()) + { + var userList = await _db.Queryable() + .Where(x => userIds.Contains(x.Id)) + .Select(x => new { x.Id, x.RealName }) + .ToListAsync(); + var userDict = userList.ToDictionary(k => k.Id, v => v.RealName); + + foreach (var item in data.list) + { + item.createUserName = userDict.ContainsKey(item.createUser) ? userDict[item.createUser] : ""; + item.updateUserName = !string.IsNullOrEmpty(item.updateUser) && userDict.ContainsKey(item.updateUser) ? userDict[item.updateUser] : ""; + } + } + + return PageResult.SqlSugarPageResult(data); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取门店消耗品库存列表失败"); + throw NCCException.Oh($"查询失败:{ex.Message}"); + } + } + #endregion + + #region 获取门店消耗品库存详情 + /// + /// 获取门店消耗品库存详情 + /// + /// + /// 根据ID获取门店消耗品库存的详细信息 + /// + /// 库存ID + /// 库存详情 + /// 查询成功 + /// 记录不存在 + /// 服务器错误 + [HttpGet("{id}")] + public async Task GetInfoAsync(string id) + { + try + { + var entity = await _db.Queryable( + (inv, store) => inv.StoreId == store.Id) + .Where((inv, store) => inv.Id == id) + .Select((inv, store) => new LqStoreConsumableInventoryInfoOutput + { + id = inv.Id, + storeId = inv.StoreId, + storeName = store.Dm ?? "", + productType = inv.ProductType, + quantity = inv.Quantity, + isEffective = inv.IsEffective, + createUser = inv.CreateUser, + createUserName = "", + createTime = inv.CreateTime, + updateUser = inv.UpdateUser, + updateUserName = "", + updateTime = inv.UpdateTime + }) + .FirstAsync(); + + if (entity == null) + { + throw NCCException.Oh("库存记录不存在"); + } + + // 补充用户名称 + if (!string.IsNullOrEmpty(entity.createUser)) + { + var createUser = await _db.Queryable() + .Where(x => x.Id == entity.createUser) + .Select(x => x.RealName) + .FirstAsync(); + entity.createUserName = createUser ?? ""; + } + + if (!string.IsNullOrEmpty(entity.updateUser)) + { + var updateUser = await _db.Queryable() + .Where(x => x.Id == entity.updateUser) + .Select(x => x.RealName) + .FirstAsync(); + entity.updateUserName = updateUser ?? ""; + } + + return entity; + } + catch (Exception ex) + { + _logger.LogError(ex, "获取门店消耗品库存详情失败"); + throw NCCException.Oh($"查询失败:{ex.Message}"); + } + } + #endregion + + #region 删除/作废门店消耗品库存 + /// + /// 删除/作废门店消耗品库存 + /// + /// + /// 将库存记录标记为无效 + /// + /// 库存ID + /// 操作结果 + /// 操作成功 + /// 记录不存在 + /// 服务器错误 + [HttpDelete("{id}")] + public async Task DeleteAsync(string id) + { + try + { + var entity = await _db.Queryable() + .Where(x => x.Id == id) + .FirstAsync(); + + if (entity == null) + { + throw NCCException.Oh("库存记录不存在"); + } + + entity.IsEffective = StatusEnum.无效.GetHashCode(); + entity.UpdateUser = _userManager.UserId; + entity.UpdateTime = DateTime.Now; + + var isOk = await _db.Updateable(entity).ExecuteCommandAsync(); + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); + } + catch (Exception ex) + { + _logger.LogError(ex, "删除门店消耗品库存失败"); + throw NCCException.Oh($"删除失败:{ex.Message}"); + } + } + #endregion + } +} + + diff --git a/sql/创建清洗管理相关表.sql b/sql/创建清洗管理相关表.sql new file mode 100644 index 0000000..e90f1ec --- /dev/null +++ b/sql/创建清洗管理相关表.sql @@ -0,0 +1,72 @@ +-- ============================================ +-- 创建清洗管理相关表 +-- ============================================ +-- 说明:包含门店消耗品库存表、清洗商表、清洗流水表 +-- ============================================ + +-- ============================================ +-- 1. 创建门店消耗品库存表(lq_store_consumable_inventory) +-- ============================================ +CREATE TABLE IF NOT EXISTS `lq_store_consumable_inventory` ( + `F_Id` VARCHAR(50) NOT NULL COMMENT '主键ID', + `F_StoreId` VARCHAR(50) NULL COMMENT '门店ID(关联lq_mdxx.F_Id)', + `F_ProductType` VARCHAR(50) NULL COMMENT '产品类型(枚举:毛巾、垫子等)', + `F_Quantity` INT NULL DEFAULT 0 COMMENT '当前库存数量', + `F_IsEffective` INT NULL DEFAULT 1 COMMENT '是否有效(1:有效 0:无效)', + `F_CreateUser` VARCHAR(50) NULL COMMENT '创建人ID', + `F_CreateTime` DATETIME NULL COMMENT '创建时间', + `F_UpdateUser` VARCHAR(50) NULL COMMENT '更新人ID', + `F_UpdateTime` DATETIME NULL COMMENT '更新时间', + PRIMARY KEY (`F_Id`), + INDEX `idx_store_id` (`F_StoreId`) COMMENT '门店ID索引', + INDEX `idx_product_type` (`F_ProductType`) COMMENT '产品类型索引', + INDEX `idx_store_product` (`F_StoreId`, `F_ProductType`) COMMENT '门店+产品类型联合索引' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='门店消耗品库存表'; + +-- ============================================ +-- 2. 创建清洗商表(lq_laundry_supplier) +-- ============================================ +CREATE TABLE IF NOT EXISTS `lq_laundry_supplier` ( + `F_Id` VARCHAR(50) NOT NULL COMMENT '主键ID', + `F_SupplierName` VARCHAR(200) NULL COMMENT '清洗商名称', + `F_ProductType` VARCHAR(50) NULL COMMENT '产品类型(枚举:毛巾、垫子等)', + `F_LaundryPrice` DECIMAL(18,2) NULL DEFAULT 0 COMMENT '清洗价格(当前价格)', + `F_Remark` VARCHAR(1000) NULL COMMENT '备注', + `F_IsEffective` INT NULL DEFAULT 1 COMMENT '是否有效(1:有效 0:无效)', + `F_CreateUser` VARCHAR(50) NULL COMMENT '创建人ID', + `F_CreateTime` DATETIME NULL COMMENT '创建时间', + `F_UpdateUser` VARCHAR(50) NULL COMMENT '更新人ID', + `F_UpdateTime` DATETIME NULL COMMENT '更新时间', + PRIMARY KEY (`F_Id`), + INDEX `idx_supplier_name` (`F_SupplierName`) COMMENT '清洗商名称索引', + INDEX `idx_product_type` (`F_ProductType`) COMMENT '产品类型索引', + INDEX `idx_supplier_product` (`F_SupplierName`, `F_ProductType`) COMMENT '清洗商+产品类型联合索引' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='清洗商表'; + +-- ============================================ +-- 3. 创建清洗流水表(lq_laundry_flow) +-- ============================================ +CREATE TABLE IF NOT EXISTS `lq_laundry_flow` ( + `F_Id` VARCHAR(50) NOT NULL COMMENT '主键ID(送出时作为批次号)', + `F_FlowType` INT NULL DEFAULT 0 COMMENT '流水类型(0:送出 1:送回)', + `F_BatchNumber` VARCHAR(50) NULL COMMENT '批次号(送出时=F_Id,送回时=对应的送出记录的F_Id)', + `F_StoreId` VARCHAR(50) NULL COMMENT '门店ID(关联lq_mdxx.F_Id)', + `F_ProductType` VARCHAR(50) NULL COMMENT '产品类型(枚举:毛巾、垫子等)', + `F_LaundrySupplierId` VARCHAR(50) NULL COMMENT '清洗商ID(关联lq_laundry_supplier.F_Id)', + `F_Quantity` INT NULL DEFAULT 0 COMMENT '数量', + `F_LaundryPrice` DECIMAL(18,2) NULL DEFAULT 0 COMMENT '清洗单价(记录历史价格)', + `F_TotalPrice` DECIMAL(18,2) NULL DEFAULT 0 COMMENT '总费用(数量 × 单价)', + `F_Remark` VARCHAR(1000) NULL COMMENT '备注(可说明差异原因,如损坏、丢失等)', + `F_IsEffective` INT NULL DEFAULT 1 COMMENT '是否有效(1:有效 0:无效)', + `F_CreateUser` VARCHAR(50) NULL COMMENT '创建人ID', + `F_CreateTime` DATETIME NULL COMMENT '创建时间', + PRIMARY KEY (`F_Id`), + INDEX `idx_flow_type` (`F_FlowType`) COMMENT '流水类型索引', + INDEX `idx_batch_number` (`F_BatchNumber`) COMMENT '批次号索引', + INDEX `idx_store_id` (`F_StoreId`) COMMENT '门店ID索引', + INDEX `idx_product_type` (`F_ProductType`) COMMENT '产品类型索引', + INDEX `idx_supplier_id` (`F_LaundrySupplierId`) COMMENT '清洗商ID索引', + INDEX `idx_create_time` (`F_CreateTime`) COMMENT '创建时间索引', + INDEX `idx_store_month` (`F_StoreId`, `F_CreateTime`) COMMENT '门店+时间联合索引(用于月度统计)' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='清洗流水表'; + -- libgit2 0.21.4