diff --git a/PROJECT_RULES.md b/PROJECT_RULES.md
index 908782f..7e26d21 100644
--- a/PROJECT_RULES.md
+++ b/PROJECT_RULES.md
@@ -143,6 +143,44 @@ Id = Guid.NewGuid().ToString()
- 必须包含所有可能的HTTP状态码响应说明
- 复杂接口必须提供完整的请求示例
+### 接口测试规范
+- **必须测试**: 所有新开发的接口或修改的接口都必须进行测试
+- **测试要求**:
+ - 使用实际数据测试接口功能
+ - 验证接口返回数据的正确性
+ - 测试边界情况和异常情况
+ - 验证接口性能和响应时间
+ - 确保接口符合业务逻辑要求
+- **测试方式**: 可以使用 curl、Postman、Swagger 等工具进行接口测试
+- **测试通过**: 只有测试通过的接口才能提交代码
+- **测试token获取**:
+ - **接口地址**: `/api/oauth/Login`
+ - **请求方式**: POST
+ - **Content-Type**: `application/x-www-form-urlencoded`
+ - **请求参数**:
+ - `account`: `admin`
+ - `password`: `e10adc3949ba59abbe56e057f20f883e`
+ - **curl示例**:
+ ```bash
+ curl -X POST "http://localhost:2011/api/oauth/Login" \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "account=admin&password=e10adc3949ba59abbe56e057f20f883e"
+ ```
+ - **返回格式**:
+ ```json
+ {
+ "code": 200,
+ "msg": "操作成功",
+ "data": {
+ "theme": "functional",
+ "token": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
+ "user": null
+ }
+ }
+ ```
+ - **token使用**: 返回的token已包含"Bearer "前缀,可直接在请求头中使用:`Authorization: {data.token}`
+
+
## 📊 数据一致性规范
### 统计与列表数据
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys.Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys.Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs
deleted file mode 100644
index c50954a..0000000
--- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys.Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System;
-
-namespace NCC.Extend.Entitys.Dto.LqTechTeacherSalary
-{
- ///
- /// 科技部老师统计数据输出
- ///
- public class TechTeacherStatisticsOutput
- {
- ///
- /// 员工ID
- ///
- public string EmployeeId { get; set; }
-
- ///
- /// 员工姓名
- ///
- public string EmployeeName { get; set; }
-
- ///
- /// 开单业绩
- ///
- public decimal OrderAchievement { get; set; }
-
- ///
- /// 消耗业绩
- ///
- public decimal ConsumeAchievement { get; set; }
-
- ///
- /// 退卡业绩
- ///
- public decimal RefundAchievement { get; set; }
-
- ///
- /// 人头(按月份+客户去重统计)
- ///
- public int PersonCount { get; set; }
-
- ///
- /// 人次(按日期+客户去重统计)
- ///
- public decimal PersonTimes { get; set; }
-
- ///
- /// 手工费
- ///
- public decimal LaborCost { get; set; }
- }
-}
-
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqGenerateInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqGenerateInput.cs
new file mode 100644
index 0000000..0d93d4c
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqGenerateInput.cs
@@ -0,0 +1,13 @@
+namespace NCC.Extend.Entitys.Dto.LqShareStatisticsHq
+{
+ ///
+ /// 总部股份统计生成输入
+ ///
+ public class ShareStatisticsHqGenerateInput
+ {
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ public string StatisticsMonth { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqOutput.cs
new file mode 100644
index 0000000..9a41bbd
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqOutput.cs
@@ -0,0 +1,70 @@
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqShareStatisticsHq
+{
+ ///
+ /// 总部股份统计输出
+ ///
+ public class ShareStatisticsHqOutput
+ {
+ ///
+ /// 主键ID
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 统计月份
+ ///
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 收入-全部
+ ///
+ public decimal IncomeGeneral { get; set; }
+
+ ///
+ /// 收入-科技部
+ ///
+ public decimal IncomeTechDept { get; set; }
+
+ ///
+ /// 成本-报销
+ ///
+ public decimal CostReimbursement { get; set; }
+
+ ///
+ /// 成本-人工
+ ///
+ public decimal CostLabor { get; set; }
+
+ ///
+ /// 成本-教育部房租
+ ///
+ public decimal CostEducationRent { get; set; }
+
+ ///
+ /// 成本-仓库房租
+ ///
+ public decimal CostWarehouseRent { get; set; }
+
+ ///
+ /// 成本-总部房租
+ ///
+ public decimal CostHQRent { get; set; }
+
+ ///
+ /// 运营利润
+ ///
+ public decimal OperationalProfit { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ public DateTime? UpdateTime { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqQueryInput.cs
new file mode 100644
index 0000000..c099f26
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqQueryInput.cs
@@ -0,0 +1,13 @@
+namespace NCC.Extend.Entitys.Dto.LqShareStatisticsHq
+{
+ ///
+ /// 总部股份统计查询输入
+ ///
+ public class ShareStatisticsHqQueryInput
+ {
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ public string StatisticsMonth { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreGenerateInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreGenerateInput.cs
new file mode 100644
index 0000000..abb1f72
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreGenerateInput.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqShareStatisticsStore
+{
+ ///
+ /// 门店股份统计生成输入
+ ///
+ public class ShareStatisticsStoreGenerateInput
+ {
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 门店ID(可选,为空则生成所有门店)
+ ///
+ public string StoreId { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreOutput.cs
new file mode 100644
index 0000000..dbbeacb
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreOutput.cs
@@ -0,0 +1,268 @@
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqShareStatisticsStore
+{
+ ///
+ /// 门店股份统计输出
+ ///
+ public class ShareStatisticsStoreOutput
+ {
+ ///
+ /// 主键ID
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 门店ID
+ ///
+ public string StoreId { get; set; }
+
+ ///
+ /// 门店名称
+ ///
+ public string StoreName { get; set; }
+
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ public string StatisticsMonth { get; set; }
+
+ // 收入部分
+ ///
+ /// 主营收入(消耗业绩-对应退款)
+ ///
+ public decimal MainIncome { get; set; }
+
+ ///
+ /// 其他收入(退款差额>0)
+ ///
+ public decimal OtherIncome { get; set; }
+
+ ///
+ /// 预收款(开单实付)
+ ///
+ public decimal AdvanceReceipt { get; set; }
+
+ ///
+ /// 实际退款(实退业绩)
+ ///
+ public decimal Refund { get; set; }
+
+ ///
+ /// 应收(合作医院)
+ ///
+ public decimal Receivables { get; set; }
+
+ ///
+ /// 银行存款(开单实付-应收)
+ ///
+ public decimal BankDeposit { get; set; }
+
+ // 成本部分
+ ///
+ /// 主营成本-产品(仓库领取)
+ ///
+ public decimal CostProduct { get; set; }
+
+ ///
+ /// 主营成本-福田(福田仓库领取)
+ ///
+ public decimal CostFutian { get; set; }
+
+ ///
+ /// 主营成本-毛巾(清洗送出)
+ ///
+ public decimal CostTowel { get; set; }
+
+ ///
+ /// 主营成本-科技部(科美业绩30%)
+ ///
+ public decimal CostTechDept { get; set; }
+
+ ///
+ /// 主营成本-管理费(总业绩9%)
+ ///
+ public decimal CostManagementFee { get; set; }
+
+ ///
+ /// 主营成本-合作(保留)
+ ///
+ public decimal CostCooperation { get; set; }
+
+ ///
+ /// 主营成本-大项目(保留)
+ ///
+ public decimal CostMajorProject { get; set; }
+
+ ///
+ /// 其他成本(退款差额<0)
+ ///
+ public decimal CostOther { get; set; }
+
+ // 人工工资部分
+ ///
+ /// 人工工资-健康师底薪
+ ///
+ public decimal SalaryBaseHealthCoach { get; set; }
+
+ ///
+ /// 人工工资-店助底薪
+ ///
+ public decimal SalaryBaseAssistant { get; set; }
+
+ ///
+ /// 人工工资-店助主任底薪
+ ///
+ public decimal SalaryBaseDirector { get; set; }
+
+ ///
+ /// 人工工资-店长底薪
+ ///
+ public decimal SalaryBaseStoreManager { get; set; }
+
+ ///
+ /// 人工工资-总经理/经理底薪
+ ///
+ public decimal SalaryBaseGeneralManager { get; set; }
+
+ ///
+ /// 人工工资-健康师提成
+ ///
+ public decimal SalaryCommissionHealthCoach { get; set; }
+
+ ///
+ /// 人工工资-店助提成
+ ///
+ public decimal SalaryCommissionAssistant { get; set; }
+
+ ///
+ /// 人工工资-店助主任提成
+ ///
+ public decimal SalaryCommissionDirector { get; set; }
+
+ ///
+ /// 人工工资-店长提成
+ ///
+ public decimal SalaryCommissionStoreManager { get; set; }
+
+ ///
+ /// 人工工资-总经理/经理提成
+ ///
+ public decimal SalaryCommissionGeneralManager { get; set; }
+
+ ///
+ /// 人工工资-手工
+ ///
+ public decimal SalaryManual { get; set; }
+
+ ///
+ /// 人工工资-出勤(保留)
+ ///
+ public decimal SalaryAttendance { get; set; }
+
+ ///
+ /// 人工工资-岗位-手机保管费
+ ///
+ public decimal SalaryPhoneCustody { get; set; }
+
+ ///
+ /// 人工工资-岗位-人头
+ ///
+ public decimal SalaryHeadcountReward { get; set; }
+
+ ///
+ /// 人工工资-门店T区
+ ///
+ public decimal SalaryTZone { get; set; }
+
+ // 费用与其他
+ ///
+ /// 社保(保留)
+ ///
+ public decimal SocialSecurity { get; set; }
+
+ ///
+ /// 门店房租
+ ///
+ public decimal StoreRent { get; set; }
+
+ ///
+ /// 宿舍房租(保留)
+ ///
+ public decimal DormRent { get; set; }
+
+ ///
+ /// 当期费用(报销)
+ ///
+ public decimal CurrentPeriodExpense { get; set; }
+
+ ///
+ /// 当前费用-秦董(保留)
+ ///
+ public decimal CurrentPeriodExpenseQin { get; set; }
+
+ ///
+ /// 财务费用(保留)
+ ///
+ public decimal FinancialFee { get; set; }
+
+ // 奖励
+ ///
+ /// 奖励-医美(保留)
+ ///
+ public decimal RewardMedicalBeauty { get; set; }
+
+ ///
+ /// 奖励-其他(保留)
+ ///
+ public decimal RewardOther { get; set; }
+
+ ///
+ /// 奖励-大单奖(保留)
+ ///
+ public decimal RewardLargeOrder { get; set; }
+
+ ///
+ /// 奖励-首单奖(保留)
+ ///
+ public decimal RewardFirstOrder { get; set; }
+
+ ///
+ /// 奖励(保留)
+ ///
+ public decimal RewardGeneral { get; set; }
+
+ // 其他保留字段
+ ///
+ /// 其他1(保留)
+ ///
+ public decimal Other1 { get; set; }
+
+ ///
+ /// 其他2(保留)
+ ///
+ public decimal Other2 { get; set; }
+
+ // 利润结果
+ ///
+ /// 利润(预收-实退-主营成本-人工工资[分项汇总]-房租-费用-奖励-其他)
+ ///
+ public decimal Profit { get; set; }
+
+ ///
+ /// 财务利润(主营-其他收入-主营成本-人工工资[分项汇总]-房租-费用-奖励-其他)
+ ///
+ public decimal FinancialProfit { get; set; }
+
+ // 基础字段
+ ///
+ /// 创建时间
+ ///
+ public DateTime? CreateTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ public DateTime? UpdateTime { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreQueryInput.cs
new file mode 100644
index 0000000..9ad52ee
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreQueryInput.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqShareStatisticsStore
+{
+ ///
+ /// 门店股份统计查询输入
+ ///
+ public class ShareStatisticsStoreQueryInput
+ {
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 门店ID(可选)
+ ///
+ public string StoreId { get; set; }
+
+ ///
+ /// 门店名称(可选,模糊查询)
+ ///
+ public string StoreName { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptGenerateInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptGenerateInput.cs
new file mode 100644
index 0000000..e0b29ed
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptGenerateInput.cs
@@ -0,0 +1,18 @@
+namespace NCC.Extend.Entitys.Dto.LqShareStatisticsTechDept
+{
+ ///
+ /// 科技部股份统计生成输入
+ ///
+ public class ShareStatisticsTechDeptGenerateInput
+ {
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 部门名称(科技一部/科技二部,为空则生成两个部门)
+ ///
+ public string DepartmentName { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptOutput.cs
new file mode 100644
index 0000000..6674655
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptOutput.cs
@@ -0,0 +1,105 @@
+using System;
+
+namespace NCC.Extend.Entitys.Dto.LqShareStatisticsTechDept
+{
+ ///
+ /// 科技部股份统计输出
+ ///
+ public class ShareStatisticsTechDeptOutput
+ {
+ ///
+ /// 主键ID
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 部门名称
+ ///
+ public string DepartmentName { get; set; }
+
+ ///
+ /// 统计月份
+ ///
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 收入
+ ///
+ public decimal Income { get; set; }
+
+ ///
+ /// 成本-报销
+ ///
+ public decimal CostReimbursement { get; set; }
+
+ ///
+ /// 成本-人工-老师底薪
+ ///
+ public decimal CostTeacherBase { get; set; }
+
+ ///
+ /// 成本-人工-手工费
+ ///
+ public decimal CostTeacherManual { get; set; }
+
+ ///
+ /// 成本-人工-开单提成
+ ///
+ public decimal CostTeacherBillingComm { get; set; }
+
+ ///
+ /// 成本-人工-消耗提成
+ ///
+ public decimal CostTeacherConsumeComm { get; set; }
+
+ ///
+ /// 成本-人工-专家提成
+ ///
+ public decimal CostTeacherExpertComm { get; set; }
+
+ ///
+ /// 成本-人工-加班
+ ///
+ public decimal CostTeacherOvertime { get; set; }
+
+ ///
+ /// 成本-人工-总经理底薪
+ ///
+ public decimal CostGMBase { get; set; }
+
+ ///
+ /// 成本-人工-总经理提成
+ ///
+ public decimal CostGMComm { get; set; }
+
+ ///
+ /// 奖励-科技部
+ ///
+ public decimal RewardTechDept { get; set; }
+
+ ///
+ /// 成本-其他1
+ ///
+ public decimal CostOther1 { get; set; }
+
+ ///
+ /// 成本-其他2
+ ///
+ public decimal CostOther2 { get; set; }
+
+ ///
+ /// 利润
+ ///
+ public decimal Profit { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ public DateTime? UpdateTime { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptQueryInput.cs
new file mode 100644
index 0000000..573e7be
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptQueryInput.cs
@@ -0,0 +1,18 @@
+namespace NCC.Extend.Entitys.Dto.LqShareStatisticsTechDept
+{
+ ///
+ /// 科技部股份统计查询输入
+ ///
+ public class ShareStatisticsTechDeptQueryInput
+ {
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 部门名称
+ ///
+ public string DepartmentName { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_hq/LqShareStatisticsHqEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_hq/LqShareStatisticsHqEntity.cs
new file mode 100644
index 0000000..b7c81e4
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_hq/LqShareStatisticsHqEntity.cs
@@ -0,0 +1,104 @@
+using System;
+using NCC.Common.Const;
+using SqlSugar;
+
+namespace NCC.Extend.Entitys.lq_share_statistics_hq
+{
+ ///
+ /// 总部股份统计表
+ ///
+ [SugarTable("lq_share_statistics_hq")]
+ [Tenant(ClaimConst.TENANT_ID)]
+ public class LqShareStatisticsHqEntity
+ {
+ ///
+ /// 主键ID
+ ///
+ [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
+ public string Id { get; set; }
+
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ [SugarColumn(ColumnName = "F_StatisticsMonth")]
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 收入-全部(开单业绩9%)
+ ///
+ [SugarColumn(ColumnName = "F_IncomeGeneral")]
+ public decimal IncomeGeneral { get; set; }
+
+ ///
+ /// 收入-科技部(科美30%的9%)
+ ///
+ [SugarColumn(ColumnName = "F_IncomeTechDept")]
+ public decimal IncomeTechDept { get; set; }
+
+ ///
+ /// 成本-报销(总部费用)
+ ///
+ [SugarColumn(ColumnName = "F_CostReimbursement")]
+ public decimal CostReimbursement { get; set; }
+
+ ///
+ /// 成本-人工(保留)
+ ///
+ [SugarColumn(ColumnName = "F_CostLabor")]
+ public decimal CostLabor { get; set; }
+
+ ///
+ /// 成本-教育部房租
+ ///
+ [SugarColumn(ColumnName = "F_CostEducationRent")]
+ public decimal CostEducationRent { get; set; }
+
+ ///
+ /// 成本-仓库房租
+ ///
+ [SugarColumn(ColumnName = "F_CostWarehouseRent")]
+ public decimal CostWarehouseRent { get; set; }
+
+ ///
+ /// 成本-总部房租
+ ///
+ [SugarColumn(ColumnName = "F_CostHQRent")]
+ public decimal CostHQRent { get; set; }
+
+ ///
+ /// 总部运营利润
+ ///
+ [SugarColumn(ColumnName = "F_OperationalProfit")]
+ public decimal OperationalProfit { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ [SugarColumn(ColumnName = "F_CreateTime")]
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ [SugarColumn(ColumnName = "F_UpdateTime")]
+ public DateTime? UpdateTime { get; set; }
+
+ ///
+ /// 创建人
+ ///
+ [SugarColumn(ColumnName = "F_CreateUser")]
+ public string CreateUser { get; set; }
+
+ ///
+ /// 更新人
+ ///
+ [SugarColumn(ColumnName = "F_UpdateUser")]
+ public string UpdateUser { get; set; }
+
+ ///
+ /// 是否有效(1:有效 0:无效)
+ ///
+ [SugarColumn(ColumnName = "F_IsEffective")]
+ public int IsEffective { get; set; } = 1;
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_store/LqShareStatisticsStoreEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_store/LqShareStatisticsStoreEntity.cs
new file mode 100644
index 0000000..29eb161
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_store/LqShareStatisticsStoreEntity.cs
@@ -0,0 +1,340 @@
+using System;
+using NCC.Common.Const;
+using SqlSugar;
+
+namespace NCC.Extend.Entitys.lq_share_statistics_store
+{
+ ///
+ /// 门店股份统计表
+ ///
+ [SugarTable("lq_share_statistics_store")]
+ [Tenant(ClaimConst.TENANT_ID)]
+ public class LqShareStatisticsStoreEntity
+ {
+ ///
+ /// 主键ID
+ ///
+ [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
+ public string Id { get; set; }
+
+ ///
+ /// 门店ID
+ ///
+ [SugarColumn(ColumnName = "F_StoreId")]
+ public string StoreId { get; set; }
+
+ ///
+ /// 门店名称
+ ///
+ [SugarColumn(ColumnName = "F_StoreName")]
+ public string StoreName { get; set; }
+
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ [SugarColumn(ColumnName = "F_StatisticsMonth")]
+ public string StatisticsMonth { get; set; }
+
+ // 收入部分
+ ///
+ /// 主营收入(消耗业绩-对应退款)
+ ///
+ [SugarColumn(ColumnName = "F_MainIncome")]
+ public decimal MainIncome { get; set; }
+
+ ///
+ /// 其他收入(退款差额>0)
+ ///
+ [SugarColumn(ColumnName = "F_OtherIncome")]
+ public decimal OtherIncome { get; set; }
+
+ ///
+ /// 预收款(开单实付)
+ ///
+ [SugarColumn(ColumnName = "F_AdvanceReceipt")]
+ public decimal AdvanceReceipt { get; set; }
+
+ ///
+ /// 实际退款(实退业绩)
+ ///
+ [SugarColumn(ColumnName = "F_Refund")]
+ public decimal Refund { get; set; }
+
+ ///
+ /// 应收(合作医院)
+ ///
+ [SugarColumn(ColumnName = "F_Receivables")]
+ public decimal Receivables { get; set; }
+
+ ///
+ /// 银行存款(开单实付-应收)
+ ///
+ [SugarColumn(ColumnName = "F_BankDeposit")]
+ public decimal BankDeposit { get; set; }
+
+ // 成本部分
+ ///
+ /// 主营成本-产品(仓库领取)
+ ///
+ [SugarColumn(ColumnName = "F_CostProduct")]
+ public decimal CostProduct { get; set; }
+
+ ///
+ /// 主营成本-福田(福田仓库领取)
+ ///
+ [SugarColumn(ColumnName = "F_CostFutian")]
+ public decimal CostFutian { get; set; }
+
+ ///
+ /// 主营成本-毛巾(清洗送出)
+ ///
+ [SugarColumn(ColumnName = "F_CostTowel")]
+ public decimal CostTowel { get; set; }
+
+ ///
+ /// 主营成本-科技部(科美业绩30%)
+ ///
+ [SugarColumn(ColumnName = "F_CostTechDept")]
+ public decimal CostTechDept { get; set; }
+
+ ///
+ /// 主营成本-管理费(总业绩9%)
+ ///
+ [SugarColumn(ColumnName = "F_CostManagementFee")]
+ public decimal CostManagementFee { get; set; }
+
+ ///
+ /// 主营成本-合作(保留)
+ ///
+ [SugarColumn(ColumnName = "F_CostCooperation")]
+ public decimal CostCooperation { get; set; }
+
+ ///
+ /// 主营成本-大项目(保留)
+ ///
+ [SugarColumn(ColumnName = "F_CostMajorProject")]
+ public decimal CostMajorProject { get; set; }
+
+ ///
+ /// 其他成本(退款差额<0)
+ ///
+ [SugarColumn(ColumnName = "F_CostOther")]
+ public decimal CostOther { get; set; }
+
+ // 人工工资部分
+ ///
+ /// 人工工资-健康师底薪
+ ///
+ [SugarColumn(ColumnName = "F_SalaryBaseHealthCoach")]
+ public decimal SalaryBaseHealthCoach { get; set; }
+
+ ///
+ /// 人工工资-店助底薪
+ ///
+ [SugarColumn(ColumnName = "F_SalaryBaseAssistant")]
+ public decimal SalaryBaseAssistant { get; set; }
+
+ ///
+ /// 人工工资-店助主任底薪
+ ///
+ [SugarColumn(ColumnName = "F_SalaryBaseDirector")]
+ public decimal SalaryBaseDirector { get; set; }
+
+ ///
+ /// 人工工资-店长底薪
+ ///
+ [SugarColumn(ColumnName = "F_SalaryBaseStoreManager")]
+ public decimal SalaryBaseStoreManager { get; set; }
+
+ ///
+ /// 人工工资-总经理/经理底薪
+ ///
+ [SugarColumn(ColumnName = "F_SalaryBaseGeneralManager")]
+ public decimal SalaryBaseGeneralManager { get; set; }
+
+ ///
+ /// 人工工资-健康师提成
+ ///
+ [SugarColumn(ColumnName = "F_SalaryCommissionHealthCoach")]
+ public decimal SalaryCommissionHealthCoach { get; set; }
+
+ ///
+ /// 人工工资-店助提成
+ ///
+ [SugarColumn(ColumnName = "F_SalaryCommissionAssistant")]
+ public decimal SalaryCommissionAssistant { get; set; }
+
+ ///
+ /// 人工工资-店助主任提成
+ ///
+ [SugarColumn(ColumnName = "F_SalaryCommissionDirector")]
+ public decimal SalaryCommissionDirector { get; set; }
+
+ ///
+ /// 人工工资-店长提成
+ ///
+ [SugarColumn(ColumnName = "F_SalaryCommissionStoreManager")]
+ public decimal SalaryCommissionStoreManager { get; set; }
+
+ ///
+ /// 人工工资-总经理/经理提成
+ ///
+ [SugarColumn(ColumnName = "F_SalaryCommissionGeneralManager")]
+ public decimal SalaryCommissionGeneralManager { get; set; }
+
+ ///
+ /// 人工工资-手工
+ ///
+ [SugarColumn(ColumnName = "F_SalaryManual")]
+ public decimal SalaryManual { get; set; }
+
+ ///
+ /// 人工工资-出勤(保留)
+ ///
+ [SugarColumn(ColumnName = "F_SalaryAttendance")]
+ public decimal SalaryAttendance { get; set; }
+
+ ///
+ /// 人工工资-岗位-手机保管费
+ ///
+ [SugarColumn(ColumnName = "F_SalaryPhoneCustody")]
+ public decimal SalaryPhoneCustody { get; set; }
+
+ ///
+ /// 人工工资-岗位-人头
+ ///
+ [SugarColumn(ColumnName = "F_SalaryHeadcountReward")]
+ public decimal SalaryHeadcountReward { get; set; }
+
+ ///
+ /// 人工工资-门店T区
+ ///
+ [SugarColumn(ColumnName = "F_SalaryTZone")]
+ public decimal SalaryTZone { get; set; }
+
+ // 费用与其他
+ ///
+ /// 社保(保留)
+ ///
+ [SugarColumn(ColumnName = "F_SocialSecurity")]
+ public decimal SocialSecurity { get; set; }
+
+ ///
+ /// 门店房租
+ ///
+ [SugarColumn(ColumnName = "F_StoreRent")]
+ public decimal StoreRent { get; set; }
+
+ ///
+ /// 宿舍房租(保留)
+ ///
+ [SugarColumn(ColumnName = "F_DormRent")]
+ public decimal DormRent { get; set; }
+
+ ///
+ /// 当期费用(报销)
+ ///
+ [SugarColumn(ColumnName = "F_CurrentPeriodExpense")]
+ public decimal CurrentPeriodExpense { get; set; }
+
+ ///
+ /// 当前费用-秦董(保留)
+ ///
+ [SugarColumn(ColumnName = "F_CurrentPeriodExpenseQin")]
+ public decimal CurrentPeriodExpenseQin { get; set; }
+
+ ///
+ /// 财务费用(保留)
+ ///
+ [SugarColumn(ColumnName = "F_FinancialFee")]
+ public decimal FinancialFee { get; set; }
+
+ // 奖励
+ ///
+ /// 奖励-医美(保留)
+ ///
+ [SugarColumn(ColumnName = "F_RewardMedicalBeauty")]
+ public decimal RewardMedicalBeauty { get; set; }
+
+ ///
+ /// 奖励-其他(保留)
+ ///
+ [SugarColumn(ColumnName = "F_RewardOther")]
+ public decimal RewardOther { get; set; }
+
+ ///
+ /// 奖励-大单奖(保留)
+ ///
+ [SugarColumn(ColumnName = "F_RewardLargeOrder")]
+ public decimal RewardLargeOrder { get; set; }
+
+ ///
+ /// 奖励-首单奖(保留)
+ ///
+ [SugarColumn(ColumnName = "F_RewardFirstOrder")]
+ public decimal RewardFirstOrder { get; set; }
+
+ ///
+ /// 奖励(保留)
+ ///
+ [SugarColumn(ColumnName = "F_RewardGeneral")]
+ public decimal RewardGeneral { get; set; }
+
+ // 其他保留字段
+ ///
+ /// 其他1(保留)
+ ///
+ [SugarColumn(ColumnName = "F_Other1")]
+ public decimal Other1 { get; set; }
+
+ ///
+ /// 其他2(保留)
+ ///
+ [SugarColumn(ColumnName = "F_Other2")]
+ public decimal Other2 { get; set; }
+
+ // 利润结果
+ ///
+ /// 利润(预收-实退-主营成本-人工工资[分项汇总]-房租-费用-奖励-其他)
+ ///
+ [SugarColumn(ColumnName = "F_Profit")]
+ public decimal Profit { get; set; }
+
+ ///
+ /// 财务利润(主营-其他收入-主营成本-人工工资[分项汇总]-房租-费用-奖励-其他)
+ ///
+ [SugarColumn(ColumnName = "F_FinancialProfit")]
+ public decimal FinancialProfit { get; set; }
+
+ // 基础字段
+ ///
+ /// 创建时间
+ ///
+ [SugarColumn(ColumnName = "F_CreateTime")]
+ public DateTime? CreateTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ [SugarColumn(ColumnName = "F_UpdateTime")]
+ public DateTime? UpdateTime { get; set; }
+
+ ///
+ /// 创建人
+ ///
+ [SugarColumn(ColumnName = "F_CreateUser")]
+ public string CreateUser { get; set; }
+
+ ///
+ /// 更新人
+ ///
+ [SugarColumn(ColumnName = "F_UpdateUser")]
+ public string UpdateUser { get; set; }
+
+ ///
+ /// 是否有效(1:有效 0:无效)
+ ///
+ [SugarColumn(ColumnName = "F_IsEffective")]
+ public int IsEffective { get; set; }
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_tech_dept/LqShareStatisticsTechDeptEntity.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_tech_dept/LqShareStatisticsTechDeptEntity.cs
new file mode 100644
index 0000000..96821f3
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_tech_dept/LqShareStatisticsTechDeptEntity.cs
@@ -0,0 +1,146 @@
+using System;
+using NCC.Common.Const;
+using SqlSugar;
+
+namespace NCC.Extend.Entitys.lq_share_statistics_tech_dept
+{
+ ///
+ /// 科技部股份统计表
+ ///
+ [SugarTable("lq_share_statistics_tech_dept")]
+ [Tenant(ClaimConst.TENANT_ID)]
+ public class LqShareStatisticsTechDeptEntity
+ {
+ ///
+ /// 主键ID
+ ///
+ [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
+ public string Id { get; set; }
+
+ ///
+ /// 部门名称(科技一部/二部)
+ ///
+ [SugarColumn(ColumnName = "F_DepartmentName")]
+ public string DepartmentName { get; set; }
+
+ ///
+ /// 统计月份(YYYYMM)
+ ///
+ [SugarColumn(ColumnName = "F_StatisticsMonth")]
+ public string StatisticsMonth { get; set; }
+
+ ///
+ /// 收入(门店科美开单30%)
+ ///
+ [SugarColumn(ColumnName = "F_Income")]
+ public decimal Income { get; set; }
+
+ ///
+ /// 成本-报销
+ ///
+ [SugarColumn(ColumnName = "F_CostReimbursement")]
+ public decimal CostReimbursement { get; set; }
+
+ ///
+ /// 成本-人工-科技部老师底薪
+ ///
+ [SugarColumn(ColumnName = "F_CostTeacherBase")]
+ public decimal CostTeacherBase { get; set; }
+
+ ///
+ /// 成本-人工-科技部手工费
+ ///
+ [SugarColumn(ColumnName = "F_CostTeacherManual")]
+ public decimal CostTeacherManual { get; set; }
+
+ ///
+ /// 成本-人工-科技部开单提成
+ ///
+ [SugarColumn(ColumnName = "F_CostTeacherBillingComm")]
+ public decimal CostTeacherBillingComm { get; set; }
+
+ ///
+ /// 成本-人工-科技部消耗提成
+ ///
+ [SugarColumn(ColumnName = "F_CostTeacherConsumeComm")]
+ public decimal CostTeacherConsumeComm { get; set; }
+
+ ///
+ /// 成本-人工-科技部专家提成(保留)
+ ///
+ [SugarColumn(ColumnName = "F_CostTeacherExpertComm")]
+ public decimal CostTeacherExpertComm { get; set; }
+
+ ///
+ /// 成本-人工-科技部加班(保留)
+ ///
+ [SugarColumn(ColumnName = "F_CostTeacherOvertime")]
+ public decimal CostTeacherOvertime { get; set; }
+
+ ///
+ /// 成本-人工-科技部总经理底薪
+ ///
+ [SugarColumn(ColumnName = "F_CostGMBase")]
+ public decimal CostGMBase { get; set; }
+
+ ///
+ /// 成本-人工-科技部总经理提成
+ ///
+ [SugarColumn(ColumnName = "F_CostGMComm")]
+ public decimal CostGMComm { get; set; }
+
+ ///
+ /// 奖励-科技部(保留)
+ ///
+ [SugarColumn(ColumnName = "F_RewardTechDept")]
+ public decimal RewardTechDept { get; set; }
+
+ ///
+ /// 成本-其他1(保留)
+ ///
+ [SugarColumn(ColumnName = "F_CostOther1")]
+ public decimal CostOther1 { get; set; }
+
+ ///
+ /// 成本-其他2(保留)
+ ///
+ [SugarColumn(ColumnName = "F_CostOther2")]
+ public decimal CostOther2 { get; set; }
+
+ ///
+ /// 科技部利润
+ ///
+ [SugarColumn(ColumnName = "F_Profit")]
+ public decimal Profit { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ [SugarColumn(ColumnName = "F_CreateTime")]
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ [SugarColumn(ColumnName = "F_UpdateTime")]
+ public DateTime? UpdateTime { get; set; }
+
+ ///
+ /// 创建人
+ ///
+ [SugarColumn(ColumnName = "F_CreateUser")]
+ public string CreateUser { get; set; }
+
+ ///
+ /// 更新人
+ ///
+ [SugarColumn(ColumnName = "F_UpdateUser")]
+ public string UpdateUser { get; set; }
+
+ ///
+ /// 是否有效(1:有效 0:无效)
+ ///
+ [SugarColumn(ColumnName = "F_IsEffective")]
+ public int IsEffective { get; set; } = 1;
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
index 66eec98..241d593 100644
--- a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
@@ -2294,6 +2294,7 @@ namespace NCC.Extend.LqKdKdjlb
Sfyj = input.Sfyj,
DeductAmount = input.DeductAmount,
Qk = input.Qk,
+ Bz = input.Remark,
UpdateTime = DateTime.Now
}).Where(w => w.Id == input.BillingId).ExecuteCommandAsync();
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsHqService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsHqService.cs
new file mode 100644
index 0000000..1addbd2
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsHqService.cs
@@ -0,0 +1,191 @@
+using Microsoft.AspNetCore.Mvc;
+using NCC.Common.Filter;
+using NCC.Dependency;
+using NCC.DynamicApiController;
+using NCC.Extend.Entitys.Dto.LqShareStatisticsHq;
+using NCC.Extend.Entitys.lq_share_statistics_hq;
+using NCC.Extend.Entitys.lq_kd_kdjlb;
+using NCC.Extend.Entitys.lq_hytk_hytk;
+using NCC.Extend.Entitys.lq_kd_pxmx;
+using NCC.Extend.Entitys.lq_contract_rent_detail;
+using SqlSugar;
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Yitter.IdGenerator;
+
+namespace NCC.Extend
+{
+ ///
+ /// 总部股份统计服务
+ ///
+ [ApiDescriptionSettings(Tag = "总部股份统计服务", Name = "LqShareStatisticsHq", Order = 402)]
+ [Route("api/Extend/[controller]")]
+ public class LqShareStatisticsHqService : IDynamicApiController, ITransient
+ {
+ private readonly ISqlSugarClient _db;
+
+ public LqShareStatisticsHqService(ISqlSugarClient db)
+ {
+ _db = db;
+ }
+
+ ///
+ /// 生成总部股份统计数据
+ ///
+ /// 生成参数
+ /// 生成结果
+ [HttpPost("generate")]
+ public async Task GenerateStatistics([FromBody] ShareStatisticsHqGenerateInput input)
+ {
+ if (string.IsNullOrEmpty(input.StatisticsMonth) || input.StatisticsMonth.Length != 6)
+ {
+ return new { code = 500, msg = "统计月份格式错误,应为 YYYYMM" };
+ }
+
+ var year = int.Parse(input.StatisticsMonth.Substring(0, 4));
+ var month = int.Parse(input.StatisticsMonth.Substring(4, 2));
+ var startDate = new DateTime(year, month, 1);
+ var endDate = startDate.AddMonths(1).AddDays(-1);
+
+ // 检查是否已存在
+ var existing = await _db.Queryable()
+ .FirstAsync(x => x.StatisticsMonth == input.StatisticsMonth);
+
+ var entity = existing ?? new LqShareStatisticsHqEntity
+ {
+ Id = YitIdHelper.NextId().ToString(),
+ StatisticsMonth = input.StatisticsMonth,
+ IsEffective = 1,
+ CreateTime = DateTime.Now,
+ CreateUser = "System"
+ };
+
+ // 计算各项数据
+ await CalculateIncome(entity, startDate, endDate);
+ await CalculateCost(entity, startDate, endDate, input.StatisticsMonth);
+ CalculateProfit(entity);
+
+ entity.UpdateTime = DateTime.Now;
+ entity.UpdateUser = "System";
+
+ if (existing == null)
+ {
+ await _db.Insertable(entity).ExecuteCommandAsync();
+ return new { code = 200, msg = "生成成功", data = new { generated = true } };
+ }
+ else
+ {
+ await _db.Updateable(entity).ExecuteCommandAsync();
+ return new { code = 200, msg = "更新成功", data = new { updated = true } };
+ }
+ }
+
+ ///
+ /// 查询总部股份统计列表
+ ///
+ /// 查询参数
+ /// 统计列表
+ [HttpGet("list")]
+ public async Task GetList([FromQuery] ShareStatisticsHqQueryInput input)
+ {
+ var query = _db.Queryable()
+ .Where(x => x.IsEffective == 1);
+
+ if (!string.IsNullOrEmpty(input.StatisticsMonth))
+ {
+ query = query.Where(x => x.StatisticsMonth == input.StatisticsMonth);
+ }
+
+ var list = await query.OrderBy(x => x.StatisticsMonth, OrderByType.Desc)
+ .Select(x => new ShareStatisticsHqOutput
+ {
+ Id = x.Id,
+ StatisticsMonth = x.StatisticsMonth,
+ IncomeGeneral = x.IncomeGeneral,
+ IncomeTechDept = x.IncomeTechDept,
+ CostReimbursement = x.CostReimbursement,
+ CostLabor = x.CostLabor,
+ CostEducationRent = x.CostEducationRent,
+ CostWarehouseRent = x.CostWarehouseRent,
+ CostHQRent = x.CostHQRent,
+ OperationalProfit = x.OperationalProfit,
+ CreateTime = x.CreateTime,
+ UpdateTime = x.UpdateTime
+ })
+ .ToListAsync();
+
+ return new { code = 200, msg = "查询成功", data = list };
+ }
+
+ #region 私有计算方法
+
+ ///
+ /// 计算收入部分
+ ///
+ private async Task CalculateIncome(LqShareStatisticsHqEntity entity, DateTime startDate, DateTime endDate)
+ {
+ // 1. 收入-全部 = (所有门店的总开单实付业绩 - 所有门店的总实退金额) * 9%
+ var totalBilling = await _db.Queryable()
+ .Where(x => x.Kdrq >= startDate && x.Kdrq <= endDate && x.IsEffective == 1)
+ .SumAsync(x => x.Sfyj);
+
+ var totalRefund = await _db.Queryable()
+ .Where(x => x.Tksj >= startDate && x.Tksj <= endDate && x.IsEffective == 1)
+ .SumAsync(x => x.Tkje ?? 0);
+
+ entity.IncomeGeneral = (totalBilling - totalRefund) * 0.09m;
+
+ // 2. 收入-科技部 = (总科美业绩 - 总科美退款) * 0.3 * 0.09
+ var kemeiPerformance = await _db.Queryable()
+ .Where(x => x.Yjsj >= startDate && x.Yjsj <= endDate && x.IsEffective == 1)
+ .Where(x => x.ItemCategory == "科美")
+ .SumAsync(x => x.TotalPrice);
+
+ // TODO: 需要确认科美退款的统计方式
+ entity.IncomeTechDept = kemeiPerformance * 0.3m * 0.09m;
+ }
+
+ ///
+ /// 计算成本部分
+ ///
+ private async Task CalculateCost(LqShareStatisticsHqEntity entity, DateTime startDate, DateTime endDate, string statisticsMonth)
+ {
+ // 1. 成本-报销 (TODO: 需要确认总部报销的判定方式)
+ entity.CostReimbursement = 0;
+
+ // 2. 成本-人工 (保留)
+ entity.CostLabor = 0;
+
+ // 3. 成本-教育部房租
+ // TODO: 需要确认如何识别教育部合同
+ entity.CostEducationRent = 0;
+
+ // 4. 成本-仓库房租
+ // TODO: 需要确认如何识别仓库合同
+ entity.CostWarehouseRent = 0;
+
+ // 5. 成本-总部房租
+ // TODO: 需要确认如何识别总部合同
+ entity.CostHQRent = 0;
+ }
+
+ ///
+ /// 计算利润
+ ///
+ private void CalculateProfit(LqShareStatisticsHqEntity entity)
+ {
+ // 总部运营利润 = 收入(门店9%) + 收入(科技部9%) - 成本(报销) - 成本(人工) - 成本(房租)
+ var totalIncome = entity.IncomeGeneral + entity.IncomeTechDept;
+ var totalCost = entity.CostReimbursement
+ + entity.CostLabor
+ + entity.CostEducationRent
+ + entity.CostWarehouseRent
+ + entity.CostHQRent;
+
+ entity.OperationalProfit = totalIncome - totalCost;
+ }
+
+ #endregion
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsStoreService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsStoreService.cs
new file mode 100644
index 0000000..36e7b68
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsStoreService.cs
@@ -0,0 +1,500 @@
+using Microsoft.AspNetCore.Mvc;
+using NCC.Common.Filter;
+using NCC.Dependency;
+using NCC.DynamicApiController;
+using NCC.Extend.Entitys.Dto.LqShareStatisticsStore;
+using NCC.Extend.Entitys.lq_share_statistics_store;
+using NCC.Extend.Entitys.lq_xh_jksyj;
+using NCC.Extend.Entitys.lq_kd_kdjlb;
+using NCC.Extend.Entitys.lq_hytk_hytk;
+using NCC.Extend.Entitys.lq_hytk_jksyj;
+using NCC.Extend.Entitys.lq_inventory_usage;
+using NCC.Extend.Entitys.lq_laundry_flow;
+using NCC.Extend.Entitys.lq_salary_statistics;
+using NCC.Extend.Entitys.lq_assistant_salary_statistics;
+using NCC.Extend.Entitys.lq_director_salary_statistics;
+using NCC.Extend.Entitys.lq_store_manager_salary_statistics;
+using NCC.Extend.Entitys.lq_business_unit_manager_salary_statistics;
+using NCC.Extend.Entitys.lq_contract_rent_detail;
+using NCC.Extend.Entitys.lq_mdxx;
+using NCC.Extend.Entitys.lq_kd_pxmx;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Yitter.IdGenerator;
+
+namespace NCC.Extend
+{
+ ///
+ /// 门店股份统计服务
+ ///
+ [ApiDescriptionSettings(Tag = "门店股份统计服务", Name = "LqShareStatisticsStore", Order = 400)]
+ [Route("api/Extend/[controller]")]
+ public class LqShareStatisticsStoreService : IDynamicApiController, ITransient
+ {
+ private readonly ISqlSugarClient _db;
+
+ public LqShareStatisticsStoreService(ISqlSugarClient db)
+ {
+ _db = db;
+ }
+
+ ///
+ /// 生成门店股份统计数据
+ ///
+ /// 生成参数
+ /// 生成结果
+ [HttpPost("generate")]
+ public async Task GenerateStatistics([FromBody] ShareStatisticsStoreGenerateInput input)
+ {
+ if (string.IsNullOrEmpty(input.StatisticsMonth) || input.StatisticsMonth.Length != 6)
+ {
+ return new { code = 500, msg = "统计月份格式错误,应为 YYYYMM" };
+ }
+
+ var year = int.Parse(input.StatisticsMonth.Substring(0, 4));
+ var month = int.Parse(input.StatisticsMonth.Substring(4, 2));
+ var startDate = new DateTime(year, month, 1);
+ var endDate = startDate.AddMonths(1).AddDays(-1);
+
+ // 获取门店列表
+ var storeQuery = _db.Queryable();
+ if (!string.IsNullOrEmpty(input.StoreId))
+ {
+ storeQuery = storeQuery.Where(x => x.Id == input.StoreId);
+ }
+ var stores = await storeQuery.ToListAsync();
+
+ if (stores.Count == 0)
+ {
+ return new { code = 500, msg = "未找到有效门店" };
+ }
+
+ var generatedCount = 0;
+ var updatedCount = 0;
+
+ foreach (var store in stores)
+ {
+ try
+ {
+ // 检查是否已存在
+ var existing = await _db.Queryable()
+ .FirstAsync(x => x.StoreId == store.Id && x.StatisticsMonth == input.StatisticsMonth);
+
+ var entity = existing ?? new LqShareStatisticsStoreEntity
+ {
+ Id = YitIdHelper.NextId().ToString(),
+ StoreId = store.Id,
+ StoreName = store.Dm,
+ StatisticsMonth = input.StatisticsMonth,
+ IsEffective = 1,
+ CreateTime = DateTime.Now,
+ CreateUser = "System"
+ };
+
+ // 计算各项数据
+ await CalculateIncome(entity, startDate, endDate);
+ await CalculateCost(entity, startDate, endDate);
+ await CalculateSalary(entity, input.StatisticsMonth);
+ await CalculateExpense(entity, startDate, endDate, input.StatisticsMonth);
+ CalculateProfit(entity);
+
+ entity.UpdateTime = DateTime.Now;
+ entity.UpdateUser = "System";
+
+ if (existing == null)
+ {
+ await _db.Insertable(entity).ExecuteCommandAsync();
+ generatedCount++;
+ }
+ else
+ {
+ await _db.Updateable(entity).ExecuteCommandAsync();
+ updatedCount++;
+ }
+ }
+ catch (Exception ex)
+ {
+ return new { code = 500, msg = $"处理门店 {store.Dm} 时出错: {ex.Message}, StackTrace: {ex.StackTrace}" };
+ }
+ }
+
+ return new
+ {
+ code = 200,
+ msg = "生成成功",
+ data = new
+ {
+ generatedCount,
+ updatedCount,
+ totalCount = stores.Count
+ }
+ };
+ }
+
+ ///
+ /// 查询门店股份统计列表
+ ///
+ /// 查询参数
+ /// 统计列表
+ [HttpGet("list")]
+ public async Task GetList([FromQuery] ShareStatisticsStoreQueryInput input)
+ {
+ var query = _db.Queryable()
+ .Where(x => x.IsEffective == 1);
+
+ if (!string.IsNullOrEmpty(input.StatisticsMonth))
+ {
+ query = query.Where(x => x.StatisticsMonth == input.StatisticsMonth);
+ }
+
+ if (!string.IsNullOrEmpty(input.StoreId))
+ {
+ query = query.Where(x => x.StoreId == input.StoreId);
+ }
+
+ if (!string.IsNullOrEmpty(input.StoreName))
+ {
+ query = query.Where(x => x.StoreName.Contains(input.StoreName));
+ }
+
+ var list = await query.OrderBy(x => x.StatisticsMonth, OrderByType.Desc)
+ .OrderBy(x => x.StoreName)
+ .Select(x => new ShareStatisticsStoreOutput
+ {
+ Id = x.Id,
+ StoreId = x.StoreId,
+ StoreName = x.StoreName,
+ StatisticsMonth = x.StatisticsMonth,
+ MainIncome = x.MainIncome,
+ OtherIncome = x.OtherIncome,
+ AdvanceReceipt = x.AdvanceReceipt,
+ Refund = x.Refund,
+ Receivables = x.Receivables,
+ BankDeposit = x.BankDeposit,
+ CostProduct = x.CostProduct,
+ CostFutian = x.CostFutian,
+ CostTowel = x.CostTowel,
+ CostTechDept = x.CostTechDept,
+ CostManagementFee = x.CostManagementFee,
+ CostCooperation = x.CostCooperation,
+ CostMajorProject = x.CostMajorProject,
+ CostOther = x.CostOther,
+ SalaryBaseHealthCoach = x.SalaryBaseHealthCoach,
+ SalaryBaseAssistant = x.SalaryBaseAssistant,
+ SalaryBaseDirector = x.SalaryBaseDirector,
+ SalaryBaseStoreManager = x.SalaryBaseStoreManager,
+ SalaryBaseGeneralManager = x.SalaryBaseGeneralManager,
+ SalaryCommissionHealthCoach = x.SalaryCommissionHealthCoach,
+ SalaryCommissionAssistant = x.SalaryCommissionAssistant,
+ SalaryCommissionDirector = x.SalaryCommissionDirector,
+ SalaryCommissionStoreManager = x.SalaryCommissionStoreManager,
+ SalaryCommissionGeneralManager = x.SalaryCommissionGeneralManager,
+ SalaryManual = x.SalaryManual,
+ SalaryAttendance = x.SalaryAttendance,
+ SalaryPhoneCustody = x.SalaryPhoneCustody,
+ SalaryHeadcountReward = x.SalaryHeadcountReward,
+ SalaryTZone = x.SalaryTZone,
+ SocialSecurity = x.SocialSecurity,
+ StoreRent = x.StoreRent,
+ DormRent = x.DormRent,
+ CurrentPeriodExpense = x.CurrentPeriodExpense,
+ CurrentPeriodExpenseQin = x.CurrentPeriodExpenseQin,
+ FinancialFee = x.FinancialFee,
+ RewardMedicalBeauty = x.RewardMedicalBeauty,
+ RewardOther = x.RewardOther,
+ RewardLargeOrder = x.RewardLargeOrder,
+ RewardFirstOrder = x.RewardFirstOrder,
+ RewardGeneral = x.RewardGeneral,
+ Other1 = x.Other1,
+ Other2 = x.Other2,
+ Profit = x.Profit,
+ FinancialProfit = x.FinancialProfit,
+ CreateTime = x.CreateTime,
+ UpdateTime = x.UpdateTime
+ })
+ .ToListAsync();
+
+ return new { code = 200, msg = "查询成功", data = list };
+ }
+
+ #region 私有计算方法
+
+ ///
+ /// 计算收入部分
+ ///
+ private async Task CalculateIncome(LqShareStatisticsStoreEntity entity, DateTime startDate, DateTime endDate)
+ {
+ // 1. 主营收入 = 消耗业绩 - 消耗退款
+ var consumePerformance = await _db.Queryable()
+ .Where(x => x.StoreId == entity.StoreId && x.Yjsj >= startDate && x.Yjsj <= endDate && x.IsEffective == 1)
+ .SumAsync(x => x.Jksyj);
+
+ var consumeRefund = await _db.Queryable()
+ .Where(x => x.StoreId == entity.StoreId && x.Tksj >= startDate && x.Tksj <= endDate && x.IsEffective == 1)
+ .SumAsync(x => x.Jksyj);
+
+ entity.MainIncome = (consumePerformance ?? 0) - (consumeRefund ?? 0);
+
+ // 2. 预收款 = 开单实付
+ entity.AdvanceReceipt = await _db.Queryable()
+ .Where(x => x.Djmd == entity.StoreId && x.Kdrq >= startDate && x.Kdrq <= endDate && x.IsEffective == 1)
+ .SumAsync(x => x.Sfyj);
+
+ // 3. 实际退款 = 退卡实退金额
+ entity.Refund = await _db.Queryable()
+ .Where(x => x.Md == entity.StoreId && x.Tksj >= startDate && x.Tksj <= endDate && x.IsEffective == 1)
+ .SumAsync(x => x.Tkje ?? 0);
+
+ // 4. 应收 = 合作医院开单金额
+ entity.Receivables = await _db.Queryable()
+ .Where(x => x.Djmd == entity.StoreId && x.Kdrq >= startDate && x.Kdrq <= endDate
+ && x.IsEffective == 1 && !string.IsNullOrEmpty(x.Fkyy))
+ .SumAsync(x => x.Sfyj);
+
+ // 5. 银行存款 = 开单实付 - 应收
+ entity.BankDeposit = entity.AdvanceReceipt - entity.Receivables;
+
+ // 6. 其他收入 = 退款差额 > 0 的部分
+ var refundDiff = entity.Refund - (consumeRefund ?? 0);
+ entity.OtherIncome = refundDiff > 0 ? refundDiff : 0;
+ }
+
+ ///
+ /// 计算成本部分
+ ///
+ private async Task CalculateCost(LqShareStatisticsStoreEntity entity, DateTime startDate, DateTime endDate)
+ {
+ // 1. 产品成本 = 仓库领用金额
+ entity.CostProduct = await _db.Queryable()
+ .Where(x => x.StoreId == entity.StoreId && x.UsageTime >= startDate && x.UsageTime <= endDate && x.IsEffective == 1)
+ .SumAsync(x => x.TotalAmount);
+
+ // 2. 福田成本 = 福田仓库领用 (需要确认福田仓库ID)
+ // TODO: 需要确认福田仓库的识别方式
+ entity.CostFutian = 0;
+
+ // 3. 毛巾成本 = 洗毛巾费用
+ entity.CostTowel = await _db.Queryable()
+ .Where(x => x.StoreId == entity.StoreId
+ && x.SendTime >= startDate && x.SendTime <= endDate
+ && x.IsEffective == 1)
+ .SumAsync(x => x.TotalPrice);
+
+ // 4. 科技部成本 = 科美业绩 * 30%
+ var kemeiPerformance = await _db.Queryable()
+ .Where(x => x.Glkdbh.StartsWith(entity.StoreId) && x.Yjsj >= startDate && x.Yjsj <= endDate && x.IsEffective == 1)
+ .Where(x => x.ItemCategory == "科美")
+ .SumAsync(x => x.TotalPrice);
+
+ entity.CostTechDept = kemeiPerformance * 0.3m;
+
+ // 5. 管理费 = 总业绩 * 9%
+ var totalPerformance = await _db.Queryable()
+ .Where(x => x.Djmd == entity.StoreId && x.Kdrq >= startDate && x.Kdrq <= endDate && x.IsEffective == 1)
+ .SumAsync(x => x.Sfyj);
+
+ entity.CostManagementFee = totalPerformance * 0.09m;
+
+ // 6. 其他成本 = 退款差额 < 0 的部分
+ var consumeRefund = await _db.Queryable()
+ .Where(x => x.StoreId == entity.StoreId && x.Tksj >= startDate && x.Tksj <= endDate && x.IsEffective == 1)
+ .SumAsync(x => x.Jksyj ?? 0);
+
+ var refundDiff = entity.Refund - consumeRefund;
+ entity.CostOther = refundDiff < 0 ? Math.Abs(refundDiff) : 0;
+
+ // 保留字段暂时为0
+ entity.CostCooperation = 0;
+ entity.CostMajorProject = 0;
+ }
+
+ ///
+ /// 计算人工工资部分
+ ///
+ private async Task CalculateSalary(LqShareStatisticsStoreEntity entity, string statisticsMonth)
+ {
+ // 1. 健康师底薪和提成
+ var healthCoachSalary = await _db.Queryable()
+ .Where(x => x.StoreId == entity.StoreId && x.StatisticsMonth == statisticsMonth)
+ .Select(x => new
+ {
+ BaseSalary = SqlFunc.AggregateSum(x.HealthCoachBaseSalary),
+ Commission = SqlFunc.AggregateSum(x.TotalCommission),
+ Manual = SqlFunc.AggregateSum(x.HandworkFee),
+ TZone = SqlFunc.AggregateSum(x.StoreTZoneCommission)
+ })
+ .FirstAsync();
+
+ entity.SalaryBaseHealthCoach = healthCoachSalary?.BaseSalary ?? 0;
+ entity.SalaryCommissionHealthCoach = healthCoachSalary?.Commission ?? 0;
+ entity.SalaryManual = healthCoachSalary?.Manual ?? 0;
+ entity.SalaryTZone = healthCoachSalary?.TZone ?? 0;
+
+ // 2. 店助底薪和提成
+ var assistantSalary = await _db.Queryable()
+ .Where(x => x.StoreId == entity.StoreId && x.StatisticsMonth == statisticsMonth
+ && x.Position == "店助")
+ .Select(x => new
+ {
+ BaseSalary = SqlFunc.AggregateSum(x.BaseSalary),
+ Commission = SqlFunc.AggregateSum(x.CommissionAmount),
+ PhoneCustody = SqlFunc.AggregateSum(x.PhoneManagementFee),
+ HeadcountReward = SqlFunc.AggregateSum(x.Stage1Reward + x.Stage2Reward)
+ })
+ .FirstAsync();
+
+ entity.SalaryBaseAssistant = assistantSalary?.BaseSalary ?? 0;
+ entity.SalaryCommissionAssistant = assistantSalary?.Commission ?? 0;
+ entity.SalaryPhoneCustody = assistantSalary?.PhoneCustody ?? 0;
+ entity.SalaryHeadcountReward = assistantSalary?.HeadcountReward ?? 0;
+
+ // 3. 店助主任底薪和提成
+ var directorSalary = await _db.Queryable()
+ .Where(x => x.StoreId == entity.StoreId && x.StatisticsMonth == statisticsMonth)
+ .Select(x => new
+ {
+ BaseSalary = SqlFunc.AggregateSum(x.ActualBaseSalary),
+ Commission = SqlFunc.AggregateSum(x.TotalCommissionAmount)
+ })
+ .FirstAsync();
+
+ entity.SalaryBaseDirector = directorSalary?.BaseSalary ?? 0;
+ entity.SalaryCommissionDirector = directorSalary?.Commission ?? 0;
+
+ // 4. 店长底薪和提成
+ var storeManagerSalary = await _db.Queryable()
+ .Where(x => x.StoreId == entity.StoreId && x.StatisticsMonth == statisticsMonth)
+ .Select(x => new
+ {
+ BaseSalary = SqlFunc.AggregateSum(x.ActualBaseSalary),
+ Commission = SqlFunc.AggregateSum(x.CommissionAmount)
+ })
+ .FirstAsync();
+
+ entity.SalaryBaseStoreManager = storeManagerSalary?.BaseSalary ?? 0;
+ entity.SalaryCommissionStoreManager = storeManagerSalary?.Commission ?? 0;
+
+ // 5. 总经理/经理底薪和提成
+ // 底薪按门店数平均分摊,提成需要从 F_StorePerformanceDetail JSON 中提取该门店的提成
+ var gmSalary = await _db.Queryable()
+ .Where(x => x.StatisticsMonth == statisticsMonth)
+ .Where(x => x.StorePerformanceDetail.Contains(entity.StoreId))
+ .ToListAsync();
+
+ decimal gmBaseSalary = 0;
+ decimal gmCommission = 0;
+
+ foreach (var gm in gmSalary)
+ {
+ // 底薪平均分摊
+ if (!string.IsNullOrEmpty(gm.StorePerformanceDetail))
+ {
+ try
+ {
+ var storeDetails = Newtonsoft.Json.JsonConvert.DeserializeObject>>(gm.StorePerformanceDetail);
+ var storeCount = storeDetails?.Count ?? 1;
+ gmBaseSalary += gm.BaseSalary / storeCount;
+
+ // 提取该门店的提成
+ var storeDetail = storeDetails?.FirstOrDefault(s => s.ContainsKey("StoreId") && s["StoreId"].ToString() == entity.StoreId);
+ if (storeDetail != null && storeDetail.ContainsKey("Commission"))
+ {
+ gmCommission += Convert.ToDecimal(storeDetail["Commission"]);
+ }
+ }
+ catch
+ {
+ // JSON 解析失败,使用默认分摊
+ gmBaseSalary += gm.BaseSalary;
+ }
+ }
+ }
+
+ entity.SalaryBaseGeneralManager = gmBaseSalary;
+ entity.SalaryCommissionGeneralManager = gmCommission;
+
+ // 保留字段
+ entity.SalaryAttendance = 0;
+ }
+
+ ///
+ /// 计算费用部分
+ ///
+ private async Task CalculateExpense(LqShareStatisticsStoreEntity entity, DateTime startDate, DateTime endDate, string statisticsMonth)
+ {
+ // 1. 门店房租 - 需要通过合同关联门店
+ // 从合同表关联租金明细
+ // 解析统计月份
+ var year = int.Parse(statisticsMonth.Substring(0, 4));
+ var month = int.Parse(statisticsMonth.Substring(4, 2));
+
+ var rentDetail = await _db.Queryable((rd, c) => new JoinQueryInfos(
+ JoinType.Inner, rd.ContractId == c.Id))
+ .Where((rd, c) => c.StoreId == entity.StoreId
+ && rd.PaymentMonth.Year == year
+ && rd.PaymentMonth.Month == month
+ && rd.IsEffective == 1)
+ .Select((rd, c) => rd.DueAmount)
+ .ToListAsync();
+
+ entity.StoreRent = rentDetail.Sum();
+
+ // 2. 当期费用 = 报销
+ // TODO: 需要根据报销分类来筛选门店相关费用
+ entity.CurrentPeriodExpense = 0;
+
+ // 保留字段
+ entity.SocialSecurity = 0;
+ entity.DormRent = 0;
+ entity.CurrentPeriodExpenseQin = 0;
+ entity.FinancialFee = 0;
+ entity.RewardMedicalBeauty = 0;
+ entity.RewardOther = 0;
+ entity.RewardLargeOrder = 0;
+ entity.RewardFirstOrder = 0;
+ entity.RewardGeneral = 0;
+ entity.Other1 = 0;
+ entity.Other2 = 0;
+ }
+
+ ///
+ /// 计算利润
+ ///
+ private void CalculateProfit(LqShareStatisticsStoreEntity entity)
+ {
+ // 人工工资汇总
+ var totalSalary = entity.SalaryBaseHealthCoach + entity.SalaryBaseAssistant + entity.SalaryBaseDirector
+ + entity.SalaryBaseStoreManager + entity.SalaryBaseGeneralManager
+ + entity.SalaryCommissionHealthCoach + entity.SalaryCommissionAssistant + entity.SalaryCommissionDirector
+ + entity.SalaryCommissionStoreManager + entity.SalaryCommissionGeneralManager
+ + entity.SalaryManual + entity.SalaryAttendance + entity.SalaryPhoneCustody
+ + entity.SalaryHeadcountReward + entity.SalaryTZone;
+
+ // 主营成本汇总
+ var totalCost = entity.CostProduct + entity.CostFutian + entity.CostTowel + entity.CostTechDept
+ + entity.CostManagementFee + entity.CostCooperation + entity.CostMajorProject + entity.CostOther;
+
+ // 费用汇总
+ var totalExpense = entity.SocialSecurity + entity.StoreRent + entity.DormRent + entity.CurrentPeriodExpense
+ + entity.CurrentPeriodExpenseQin + entity.FinancialFee;
+
+ // 奖励汇总
+ var totalReward = entity.RewardMedicalBeauty + entity.RewardOther + entity.RewardLargeOrder
+ + entity.RewardFirstOrder + entity.RewardGeneral;
+
+ // 其他汇总
+ var totalOther = entity.Other1 + entity.Other2;
+
+ // 利润 = 预收 - 实退 - 主营成本 - 人工工资 - 房租 - 费用 - 奖励 - 其他
+ entity.Profit = entity.AdvanceReceipt - entity.Refund - totalCost - totalSalary - totalExpense - totalReward - totalOther;
+
+ // 财务利润 = 主营收入 + 其他收入 - 主营成本 - 人工工资 - 房租 - 费用 - 奖励 - 其他
+ entity.FinancialProfit = entity.MainIncome + entity.OtherIncome - totalCost - totalSalary - totalExpense - totalReward - totalOther;
+ }
+
+ #endregion
+ }
+}
diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsTechDeptService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsTechDeptService.cs
new file mode 100644
index 0000000..974123a
--- /dev/null
+++ b/netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsTechDeptService.cs
@@ -0,0 +1,262 @@
+using Microsoft.AspNetCore.Mvc;
+using NCC.Common.Filter;
+using NCC.Dependency;
+using NCC.DynamicApiController;
+using NCC.Extend.Entitys.Dto.LqShareStatisticsTechDept;
+using NCC.Extend.Entitys.lq_share_statistics_tech_dept;
+using NCC.Extend.Entitys.lq_mdxx;
+using NCC.Extend.Entitys.lq_kd_pxmx;
+using NCC.Extend.Entitys.lq_kd_kdjlb;
+using NCC.Extend.Entitys.lq_hytk_jksyj;
+using NCC.Extend.Entitys.lq_xh_jksyj;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Yitter.IdGenerator;
+
+namespace NCC.Extend
+{
+ ///
+ /// 科技部股份统计服务
+ ///
+ [ApiDescriptionSettings(Tag = "科技部股份统计服务", Name = "LqShareStatisticsTechDept", Order = 401)]
+ [Route("api/Extend/[controller]")]
+ public class LqShareStatisticsTechDeptService : IDynamicApiController, ITransient
+ {
+ private readonly ISqlSugarClient _db;
+
+ public LqShareStatisticsTechDeptService(ISqlSugarClient db)
+ {
+ _db = db;
+ }
+
+ ///
+ /// 生成科技部股份统计数据
+ ///
+ /// 生成参数
+ /// 生成结果
+ [HttpPost("generate")]
+ public async Task GenerateStatistics([FromBody] ShareStatisticsTechDeptGenerateInput input)
+ {
+ if (string.IsNullOrEmpty(input.StatisticsMonth) || input.StatisticsMonth.Length != 6)
+ {
+ return new { code = 500, msg = "统计月份格式错误,应为 YYYYMM" };
+ }
+
+ var year = int.Parse(input.StatisticsMonth.Substring(0, 4));
+ var month = int.Parse(input.StatisticsMonth.Substring(4, 2));
+ var startDate = new DateTime(year, month, 1);
+ var endDate = startDate.AddMonths(1).AddDays(-1);
+
+ // 确定要生成的部门列表
+ var departments = new List();
+ if (!string.IsNullOrEmpty(input.DepartmentName))
+ {
+ departments.Add(input.DepartmentName);
+ }
+ else
+ {
+ departments.Add("科技一部");
+ departments.Add("科技二部");
+ }
+
+ var generatedCount = 0;
+ var updatedCount = 0;
+
+ foreach (var deptName in departments)
+ {
+ // 检查是否已存在
+ var existing = await _db.Queryable()
+ .FirstAsync(x => x.DepartmentName == deptName && x.StatisticsMonth == input.StatisticsMonth);
+
+ var entity = existing ?? new LqShareStatisticsTechDeptEntity
+ {
+ Id = YitIdHelper.NextId().ToString(),
+ DepartmentName = deptName,
+ StatisticsMonth = input.StatisticsMonth,
+ IsEffective = 1,
+ CreateTime = DateTime.Now,
+ CreateUser = "System"
+ };
+
+ // 计算各项数据
+ await CalculateIncome(entity, deptName, startDate, endDate);
+ await CalculateCost(entity, deptName, startDate, endDate, input.StatisticsMonth);
+ CalculateProfit(entity);
+
+ entity.UpdateTime = DateTime.Now;
+ entity.UpdateUser = "System";
+
+ if (existing == null)
+ {
+ await _db.Insertable(entity).ExecuteCommandAsync();
+ generatedCount++;
+ }
+ else
+ {
+ await _db.Updateable(entity).ExecuteCommandAsync();
+ updatedCount++;
+ }
+ }
+
+ return new
+ {
+ code = 200,
+ msg = "生成成功",
+ data = new
+ {
+ generatedCount,
+ updatedCount,
+ totalCount = departments.Count
+ }
+ };
+ }
+
+ ///
+ /// 查询科技部股份统计列表
+ ///
+ /// 查询参数
+ /// 统计列表
+ [HttpGet("list")]
+ public async Task GetList([FromQuery] ShareStatisticsTechDeptQueryInput input)
+ {
+ var query = _db.Queryable()
+ .Where(x => x.IsEffective == 1);
+
+ if (!string.IsNullOrEmpty(input.StatisticsMonth))
+ {
+ query = query.Where(x => x.StatisticsMonth == input.StatisticsMonth);
+ }
+
+ if (!string.IsNullOrEmpty(input.DepartmentName))
+ {
+ query = query.Where(x => x.DepartmentName == input.DepartmentName);
+ }
+
+ var list = await query.OrderBy(x => x.StatisticsMonth, OrderByType.Desc)
+ .OrderBy(x => x.DepartmentName)
+ .Select(x => new ShareStatisticsTechDeptOutput
+ {
+ Id = x.Id,
+ DepartmentName = x.DepartmentName,
+ StatisticsMonth = x.StatisticsMonth,
+ Income = x.Income,
+ CostReimbursement = x.CostReimbursement,
+ CostTeacherBase = x.CostTeacherBase,
+ CostTeacherManual = x.CostTeacherManual,
+ CostTeacherBillingComm = x.CostTeacherBillingComm,
+ CostTeacherConsumeComm = x.CostTeacherConsumeComm,
+ CostTeacherExpertComm = x.CostTeacherExpertComm,
+ CostTeacherOvertime = x.CostTeacherOvertime,
+ CostGMBase = x.CostGMBase,
+ CostGMComm = x.CostGMComm,
+ RewardTechDept = x.RewardTechDept,
+ CostOther1 = x.CostOther1,
+ CostOther2 = x.CostOther2,
+ Profit = x.Profit,
+ CreateTime = x.CreateTime,
+ UpdateTime = x.UpdateTime
+ })
+ .ToListAsync();
+
+ return new { code = 200, msg = "查询成功", data = list };
+ }
+
+ #region 私有计算方法
+
+ ///
+ /// 计算收入部分
+ ///
+ private async Task CalculateIncome(LqShareStatisticsTechDeptEntity entity, string deptName, DateTime startDate, DateTime endDate)
+ {
+ // 1. 找到该科技部管辖的所有门店
+ var stores = await _db.Queryable()
+ .Where(x => x.Kjb == deptName)
+ .Select(x => x.Id)
+ .ToListAsync();
+
+ if (stores.Count == 0)
+ {
+ entity.Income = 0;
+ return;
+ }
+
+ // 2. 统计这些门店的科美项目开单实付业绩
+ // 需要关联 lq_kd_kdjlb 来获取门店信息
+ var kemeiIncome = await _db.Queryable((px, kd) => new JoinQueryInfos(
+ JoinType.Inner, px.Glkdbh == kd.Id))
+ .Where((px, kd) => stores.Contains(kd.Djmd) && px.Yjsj >= startDate && px.Yjsj <= endDate && px.IsEffective == 1)
+ .Where((px, kd) => px.ItemCategory == "科美")
+ .SumAsync((px, kd) => px.TotalPrice);
+
+ // 3. 减去对应的科美项目实退金额
+ var kemeiRefund = await _db.Queryable()
+ .Where(x => stores.Contains(x.StoreId) && x.Tksj >= startDate && x.Tksj <= endDate && x.IsEffective == 1)
+ .Where(x => x.ItemCategory == "科美")
+ .SumAsync(x => x.Jksyj ?? 0);
+
+ // 4. 结果 * 30%
+ entity.Income = (kemeiIncome - kemeiRefund) * 0.3m;
+ }
+
+ ///
+ /// 计算成本部分
+ ///
+ private async Task CalculateCost(LqShareStatisticsTechDeptEntity entity, string deptName, DateTime startDate, DateTime endDate, string statisticsMonth)
+ {
+ // 1. 成本-报销 (TODO: 需要确认报销分类的具体判定方式)
+ entity.CostReimbursement = 0;
+
+ // 2. 成本-人工-科技部老师底薪 (TODO: 需要确认科技部老师工资表名和字段)
+ entity.CostTeacherBase = 0;
+
+ // 3. 成本-人工-科技部手工费
+ // 从消耗表中统计科技部老师的手工费
+ // TODO: 需要确认如何识别科技部老师
+ entity.CostTeacherManual = 0;
+
+ // 4. 成本-人工-科技部开单提成 (TODO: 需要确认字段名)
+ entity.CostTeacherBillingComm = 0;
+
+ // 5. 成本-人工-科技部消耗提成 (TODO: 需要确认字段名)
+ entity.CostTeacherConsumeComm = 0;
+
+ // 6. 成本-人工-科技部总经理 (TODO: 需要确认科技部总经理工资表)
+ entity.CostGMBase = 0;
+ entity.CostGMComm = 0;
+
+ // 保留字段
+ entity.CostTeacherExpertComm = 0;
+ entity.CostTeacherOvertime = 0;
+ entity.RewardTechDept = 0;
+ entity.CostOther1 = 0;
+ entity.CostOther2 = 0;
+ }
+
+ ///
+ /// 计算利润
+ ///
+ private void CalculateProfit(LqShareStatisticsTechDeptEntity entity)
+ {
+ // 科技部利润 = 收入 - 成本报销 - 成本人工 - 其他
+ var totalCost = entity.CostReimbursement
+ + entity.CostTeacherBase
+ + entity.CostTeacherManual
+ + entity.CostTeacherBillingComm
+ + entity.CostTeacherConsumeComm
+ + entity.CostTeacherExpertComm
+ + entity.CostTeacherOvertime
+ + entity.CostGMBase
+ + entity.CostGMComm
+ + entity.RewardTechDept
+ + entity.CostOther1
+ + entity.CostOther2;
+
+ entity.Profit = entity.Income - totalCost;
+ }
+
+ #endregion
+ }
+}
diff --git a/sql/排查生美业绩统计差异-简化版.sql b/sql/排查生美业绩统计差异-简化版.sql
index dbfd09e..d98ed59 100644
--- a/sql/排查生美业绩统计差异-简化版.sql
+++ b/sql/排查生美业绩统计差异-简化版.sql
@@ -116,3 +116,6 @@ ORDER BY 生美业绩 DESC;
+
+
+
diff --git a/sql/排查生美业绩统计差异详细.sql b/sql/排查生美业绩统计差异详细.sql
index 4051a8d..4a4dde9 100644
--- a/sql/排查生美业绩统计差异详细.sql
+++ b/sql/排查生美业绩统计差异详细.sql
@@ -168,3 +168,6 @@ HAVING COUNT(*) > 1;
+
+
+
diff --git a/sql/检查生美业绩统计差异.sql b/sql/检查生美业绩统计差异.sql
index 029e1dd..e14f4e0 100644
--- a/sql/检查生美业绩统计差异.sql
+++ b/sql/检查生美业绩统计差异.sql
@@ -138,3 +138,6 @@ ORDER BY 生美业绩 DESC;
+
+
+
diff --git a/test_tianwang_api.py b/test_tianwang_api.py
index 270dada..7dcc326 100644
--- a/test_tianwang_api.py
+++ b/test_tianwang_api.py
@@ -71,3 +71,6 @@ total2 = sum([d.get('BillingPerformance', 0) for d in depts2])
print(f"\n教育一部+教育二部合计 BillingPerformance: {total2}")
+
+
+