Commit 166f38013cab0d66999a79b907b3e3b3eca0b066

Authored by “wangming”
1 parent b76918ad

分润统计相关功能及储扣ItemCategory等修复

Showing 22 changed files with 2144 additions and 51 deletions
PROJECT_RULES.md
... ... @@ -143,6 +143,44 @@ Id = Guid.NewGuid().ToString()
143 143 - 必须包含所有可能的HTTP状态码响应说明
144 144 - 复杂接口必须提供完整的请求示例
145 145  
  146 +### 接口测试规范
  147 +- **必须测试**: 所有新开发的接口或修改的接口都必须进行测试
  148 +- **测试要求**:
  149 + - 使用实际数据测试接口功能
  150 + - 验证接口返回数据的正确性
  151 + - 测试边界情况和异常情况
  152 + - 验证接口性能和响应时间
  153 + - 确保接口符合业务逻辑要求
  154 +- **测试方式**: 可以使用 curl、Postman、Swagger 等工具进行接口测试
  155 +- **测试通过**: 只有测试通过的接口才能提交代码
  156 +- **测试token获取**:
  157 + - **接口地址**: `/api/oauth/Login`
  158 + - **请求方式**: POST
  159 + - **Content-Type**: `application/x-www-form-urlencoded`
  160 + - **请求参数**:
  161 + - `account`: `admin`
  162 + - `password`: `e10adc3949ba59abbe56e057f20f883e`
  163 + - **curl示例**:
  164 + ```bash
  165 + curl -X POST "http://localhost:2011/api/oauth/Login" \
  166 + -H "Content-Type: application/x-www-form-urlencoded" \
  167 + -d "account=admin&password=e10adc3949ba59abbe56e057f20f883e"
  168 + ```
  169 + - **返回格式**:
  170 + ```json
  171 + {
  172 + "code": 200,
  173 + "msg": "操作成功",
  174 + "data": {
  175 + "theme": "functional",
  176 + "token": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  177 + "user": null
  178 + }
  179 + }
  180 + ```
  181 + - **token使用**: 返回的token已包含"Bearer "前缀,可直接在请求头中使用:`Authorization: {data.token}`
  182 +
  183 +
146 184 ## 📊 数据一致性规范
147 185  
148 186 ### 统计与列表数据
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys.Dto/LqTechTeacherSalary/TechTeacherStatisticsOutput.cs deleted
1   -using System;
2   -
3   -namespace NCC.Extend.Entitys.Dto.LqTechTeacherSalary
4   -{
5   - /// <summary>
6   - /// 科技部老师统计数据输出
7   - /// </summary>
8   - public class TechTeacherStatisticsOutput
9   - {
10   - /// <summary>
11   - /// 员工ID
12   - /// </summary>
13   - public string EmployeeId { get; set; }
14   -
15   - /// <summary>
16   - /// 员工姓名
17   - /// </summary>
18   - public string EmployeeName { get; set; }
19   -
20   - /// <summary>
21   - /// 开单业绩
22   - /// </summary>
23   - public decimal OrderAchievement { get; set; }
24   -
25   - /// <summary>
26   - /// 消耗业绩
27   - /// </summary>
28   - public decimal ConsumeAchievement { get; set; }
29   -
30   - /// <summary>
31   - /// 退卡业绩
32   - /// </summary>
33   - public decimal RefundAchievement { get; set; }
34   -
35   - /// <summary>
36   - /// 人头(按月份+客户去重统计)
37   - /// </summary>
38   - public int PersonCount { get; set; }
39   -
40   - /// <summary>
41   - /// 人次(按日期+客户去重统计)
42   - /// </summary>
43   - public decimal PersonTimes { get; set; }
44   -
45   - /// <summary>
46   - /// 手工费
47   - /// </summary>
48   - public decimal LaborCost { get; set; }
49   - }
50   -}
51   -
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqGenerateInput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.LqShareStatisticsHq
  2 +{
  3 + /// <summary>
  4 + /// 总部股份统计生成输入
  5 + /// </summary>
  6 + public class ShareStatisticsHqGenerateInput
  7 + {
  8 + /// <summary>
  9 + /// 统计月份(YYYYMM)
  10 + /// </summary>
  11 + public string StatisticsMonth { get; set; }
  12 + }
  13 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqOutput.cs 0 → 100644
  1 +using System;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqShareStatisticsHq
  4 +{
  5 + /// <summary>
  6 + /// 总部股份统计输出
  7 + /// </summary>
  8 + public class ShareStatisticsHqOutput
  9 + {
  10 + /// <summary>
  11 + /// 主键ID
  12 + /// </summary>
  13 + public string Id { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 统计月份
  17 + /// </summary>
  18 + public string StatisticsMonth { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 收入-全部
  22 + /// </summary>
  23 + public decimal IncomeGeneral { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 收入-科技部
  27 + /// </summary>
  28 + public decimal IncomeTechDept { get; set; }
  29 +
  30 + /// <summary>
  31 + /// 成本-报销
  32 + /// </summary>
  33 + public decimal CostReimbursement { get; set; }
  34 +
  35 + /// <summary>
  36 + /// 成本-人工
  37 + /// </summary>
  38 + public decimal CostLabor { get; set; }
  39 +
  40 + /// <summary>
  41 + /// 成本-教育部房租
  42 + /// </summary>
  43 + public decimal CostEducationRent { get; set; }
  44 +
  45 + /// <summary>
  46 + /// 成本-仓库房租
  47 + /// </summary>
  48 + public decimal CostWarehouseRent { get; set; }
  49 +
  50 + /// <summary>
  51 + /// 成本-总部房租
  52 + /// </summary>
  53 + public decimal CostHQRent { get; set; }
  54 +
  55 + /// <summary>
  56 + /// 运营利润
  57 + /// </summary>
  58 + public decimal OperationalProfit { get; set; }
  59 +
  60 + /// <summary>
  61 + /// 创建时间
  62 + /// </summary>
  63 + public DateTime CreateTime { get; set; }
  64 +
  65 + /// <summary>
  66 + /// 更新时间
  67 + /// </summary>
  68 + public DateTime? UpdateTime { get; set; }
  69 + }
  70 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsHq/ShareStatisticsHqQueryInput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.LqShareStatisticsHq
  2 +{
  3 + /// <summary>
  4 + /// 总部股份统计查询输入
  5 + /// </summary>
  6 + public class ShareStatisticsHqQueryInput
  7 + {
  8 + /// <summary>
  9 + /// 统计月份(YYYYMM)
  10 + /// </summary>
  11 + public string StatisticsMonth { get; set; }
  12 + }
  13 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreGenerateInput.cs 0 → 100644
  1 +using System;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqShareStatisticsStore
  4 +{
  5 + /// <summary>
  6 + /// 门店股份统计生成输入
  7 + /// </summary>
  8 + public class ShareStatisticsStoreGenerateInput
  9 + {
  10 + /// <summary>
  11 + /// 统计月份(YYYYMM)
  12 + /// </summary>
  13 + public string StatisticsMonth { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 门店ID(可选,为空则生成所有门店)
  17 + /// </summary>
  18 + public string StoreId { get; set; }
  19 + }
  20 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreOutput.cs 0 → 100644
  1 +using System;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqShareStatisticsStore
  4 +{
  5 + /// <summary>
  6 + /// 门店股份统计输出
  7 + /// </summary>
  8 + public class ShareStatisticsStoreOutput
  9 + {
  10 + /// <summary>
  11 + /// 主键ID
  12 + /// </summary>
  13 + public string Id { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 门店ID
  17 + /// </summary>
  18 + public string StoreId { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 门店名称
  22 + /// </summary>
  23 + public string StoreName { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 统计月份(YYYYMM)
  27 + /// </summary>
  28 + public string StatisticsMonth { get; set; }
  29 +
  30 + // 收入部分
  31 + /// <summary>
  32 + /// 主营收入(消耗业绩-对应退款)
  33 + /// </summary>
  34 + public decimal MainIncome { get; set; }
  35 +
  36 + /// <summary>
  37 + /// 其他收入(退款差额>0)
  38 + /// </summary>
  39 + public decimal OtherIncome { get; set; }
  40 +
  41 + /// <summary>
  42 + /// 预收款(开单实付)
  43 + /// </summary>
  44 + public decimal AdvanceReceipt { get; set; }
  45 +
  46 + /// <summary>
  47 + /// 实际退款(实退业绩)
  48 + /// </summary>
  49 + public decimal Refund { get; set; }
  50 +
  51 + /// <summary>
  52 + /// 应收(合作医院)
  53 + /// </summary>
  54 + public decimal Receivables { get; set; }
  55 +
  56 + /// <summary>
  57 + /// 银行存款(开单实付-应收)
  58 + /// </summary>
  59 + public decimal BankDeposit { get; set; }
  60 +
  61 + // 成本部分
  62 + /// <summary>
  63 + /// 主营成本-产品(仓库领取)
  64 + /// </summary>
  65 + public decimal CostProduct { get; set; }
  66 +
  67 + /// <summary>
  68 + /// 主营成本-福田(福田仓库领取)
  69 + /// </summary>
  70 + public decimal CostFutian { get; set; }
  71 +
  72 + /// <summary>
  73 + /// 主营成本-毛巾(清洗送出)
  74 + /// </summary>
  75 + public decimal CostTowel { get; set; }
  76 +
  77 + /// <summary>
  78 + /// 主营成本-科技部(科美业绩30%)
  79 + /// </summary>
  80 + public decimal CostTechDept { get; set; }
  81 +
  82 + /// <summary>
  83 + /// 主营成本-管理费(总业绩9%)
  84 + /// </summary>
  85 + public decimal CostManagementFee { get; set; }
  86 +
  87 + /// <summary>
  88 + /// 主营成本-合作(保留)
  89 + /// </summary>
  90 + public decimal CostCooperation { get; set; }
  91 +
  92 + /// <summary>
  93 + /// 主营成本-大项目(保留)
  94 + /// </summary>
  95 + public decimal CostMajorProject { get; set; }
  96 +
  97 + /// <summary>
  98 + /// 其他成本(退款差额<0)
  99 + /// </summary>
  100 + public decimal CostOther { get; set; }
  101 +
  102 + // 人工工资部分
  103 + /// <summary>
  104 + /// 人工工资-健康师底薪
  105 + /// </summary>
  106 + public decimal SalaryBaseHealthCoach { get; set; }
  107 +
  108 + /// <summary>
  109 + /// 人工工资-店助底薪
  110 + /// </summary>
  111 + public decimal SalaryBaseAssistant { get; set; }
  112 +
  113 + /// <summary>
  114 + /// 人工工资-店助主任底薪
  115 + /// </summary>
  116 + public decimal SalaryBaseDirector { get; set; }
  117 +
  118 + /// <summary>
  119 + /// 人工工资-店长底薪
  120 + /// </summary>
  121 + public decimal SalaryBaseStoreManager { get; set; }
  122 +
  123 + /// <summary>
  124 + /// 人工工资-总经理/经理底薪
  125 + /// </summary>
  126 + public decimal SalaryBaseGeneralManager { get; set; }
  127 +
  128 + /// <summary>
  129 + /// 人工工资-健康师提成
  130 + /// </summary>
  131 + public decimal SalaryCommissionHealthCoach { get; set; }
  132 +
  133 + /// <summary>
  134 + /// 人工工资-店助提成
  135 + /// </summary>
  136 + public decimal SalaryCommissionAssistant { get; set; }
  137 +
  138 + /// <summary>
  139 + /// 人工工资-店助主任提成
  140 + /// </summary>
  141 + public decimal SalaryCommissionDirector { get; set; }
  142 +
  143 + /// <summary>
  144 + /// 人工工资-店长提成
  145 + /// </summary>
  146 + public decimal SalaryCommissionStoreManager { get; set; }
  147 +
  148 + /// <summary>
  149 + /// 人工工资-总经理/经理提成
  150 + /// </summary>
  151 + public decimal SalaryCommissionGeneralManager { get; set; }
  152 +
  153 + /// <summary>
  154 + /// 人工工资-手工
  155 + /// </summary>
  156 + public decimal SalaryManual { get; set; }
  157 +
  158 + /// <summary>
  159 + /// 人工工资-出勤(保留)
  160 + /// </summary>
  161 + public decimal SalaryAttendance { get; set; }
  162 +
  163 + /// <summary>
  164 + /// 人工工资-岗位-手机保管费
  165 + /// </summary>
  166 + public decimal SalaryPhoneCustody { get; set; }
  167 +
  168 + /// <summary>
  169 + /// 人工工资-岗位-人头
  170 + /// </summary>
  171 + public decimal SalaryHeadcountReward { get; set; }
  172 +
  173 + /// <summary>
  174 + /// 人工工资-门店T区
  175 + /// </summary>
  176 + public decimal SalaryTZone { get; set; }
  177 +
  178 + // 费用与其他
  179 + /// <summary>
  180 + /// 社保(保留)
  181 + /// </summary>
  182 + public decimal SocialSecurity { get; set; }
  183 +
  184 + /// <summary>
  185 + /// 门店房租
  186 + /// </summary>
  187 + public decimal StoreRent { get; set; }
  188 +
  189 + /// <summary>
  190 + /// 宿舍房租(保留)
  191 + /// </summary>
  192 + public decimal DormRent { get; set; }
  193 +
  194 + /// <summary>
  195 + /// 当期费用(报销)
  196 + /// </summary>
  197 + public decimal CurrentPeriodExpense { get; set; }
  198 +
  199 + /// <summary>
  200 + /// 当前费用-秦董(保留)
  201 + /// </summary>
  202 + public decimal CurrentPeriodExpenseQin { get; set; }
  203 +
  204 + /// <summary>
  205 + /// 财务费用(保留)
  206 + /// </summary>
  207 + public decimal FinancialFee { get; set; }
  208 +
  209 + // 奖励
  210 + /// <summary>
  211 + /// 奖励-医美(保留)
  212 + /// </summary>
  213 + public decimal RewardMedicalBeauty { get; set; }
  214 +
  215 + /// <summary>
  216 + /// 奖励-其他(保留)
  217 + /// </summary>
  218 + public decimal RewardOther { get; set; }
  219 +
  220 + /// <summary>
  221 + /// 奖励-大单奖(保留)
  222 + /// </summary>
  223 + public decimal RewardLargeOrder { get; set; }
  224 +
  225 + /// <summary>
  226 + /// 奖励-首单奖(保留)
  227 + /// </summary>
  228 + public decimal RewardFirstOrder { get; set; }
  229 +
  230 + /// <summary>
  231 + /// 奖励(保留)
  232 + /// </summary>
  233 + public decimal RewardGeneral { get; set; }
  234 +
  235 + // 其他保留字段
  236 + /// <summary>
  237 + /// 其他1(保留)
  238 + /// </summary>
  239 + public decimal Other1 { get; set; }
  240 +
  241 + /// <summary>
  242 + /// 其他2(保留)
  243 + /// </summary>
  244 + public decimal Other2 { get; set; }
  245 +
  246 + // 利润结果
  247 + /// <summary>
  248 + /// 利润(预收-实退-主营成本-人工工资[分项汇总]-房租-费用-奖励-其他)
  249 + /// </summary>
  250 + public decimal Profit { get; set; }
  251 +
  252 + /// <summary>
  253 + /// 财务利润(主营-其他收入-主营成本-人工工资[分项汇总]-房租-费用-奖励-其他)
  254 + /// </summary>
  255 + public decimal FinancialProfit { get; set; }
  256 +
  257 + // 基础字段
  258 + /// <summary>
  259 + /// 创建时间
  260 + /// </summary>
  261 + public DateTime? CreateTime { get; set; }
  262 +
  263 + /// <summary>
  264 + /// 更新时间
  265 + /// </summary>
  266 + public DateTime? UpdateTime { get; set; }
  267 + }
  268 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsStore/ShareStatisticsStoreQueryInput.cs 0 → 100644
  1 +using System;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqShareStatisticsStore
  4 +{
  5 + /// <summary>
  6 + /// 门店股份统计查询输入
  7 + /// </summary>
  8 + public class ShareStatisticsStoreQueryInput
  9 + {
  10 + /// <summary>
  11 + /// 统计月份(YYYYMM)
  12 + /// </summary>
  13 + public string StatisticsMonth { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 门店ID(可选)
  17 + /// </summary>
  18 + public string StoreId { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 门店名称(可选,模糊查询)
  22 + /// </summary>
  23 + public string StoreName { get; set; }
  24 + }
  25 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptGenerateInput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.LqShareStatisticsTechDept
  2 +{
  3 + /// <summary>
  4 + /// 科技部股份统计生成输入
  5 + /// </summary>
  6 + public class ShareStatisticsTechDeptGenerateInput
  7 + {
  8 + /// <summary>
  9 + /// 统计月份(YYYYMM)
  10 + /// </summary>
  11 + public string StatisticsMonth { get; set; }
  12 +
  13 + /// <summary>
  14 + /// 部门名称(科技一部/科技二部,为空则生成两个部门)
  15 + /// </summary>
  16 + public string DepartmentName { get; set; }
  17 + }
  18 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptOutput.cs 0 → 100644
  1 +using System;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.LqShareStatisticsTechDept
  4 +{
  5 + /// <summary>
  6 + /// 科技部股份统计输出
  7 + /// </summary>
  8 + public class ShareStatisticsTechDeptOutput
  9 + {
  10 + /// <summary>
  11 + /// 主键ID
  12 + /// </summary>
  13 + public string Id { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 部门名称
  17 + /// </summary>
  18 + public string DepartmentName { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 统计月份
  22 + /// </summary>
  23 + public string StatisticsMonth { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 收入
  27 + /// </summary>
  28 + public decimal Income { get; set; }
  29 +
  30 + /// <summary>
  31 + /// 成本-报销
  32 + /// </summary>
  33 + public decimal CostReimbursement { get; set; }
  34 +
  35 + /// <summary>
  36 + /// 成本-人工-老师底薪
  37 + /// </summary>
  38 + public decimal CostTeacherBase { get; set; }
  39 +
  40 + /// <summary>
  41 + /// 成本-人工-手工费
  42 + /// </summary>
  43 + public decimal CostTeacherManual { get; set; }
  44 +
  45 + /// <summary>
  46 + /// 成本-人工-开单提成
  47 + /// </summary>
  48 + public decimal CostTeacherBillingComm { get; set; }
  49 +
  50 + /// <summary>
  51 + /// 成本-人工-消耗提成
  52 + /// </summary>
  53 + public decimal CostTeacherConsumeComm { get; set; }
  54 +
  55 + /// <summary>
  56 + /// 成本-人工-专家提成
  57 + /// </summary>
  58 + public decimal CostTeacherExpertComm { get; set; }
  59 +
  60 + /// <summary>
  61 + /// 成本-人工-加班
  62 + /// </summary>
  63 + public decimal CostTeacherOvertime { get; set; }
  64 +
  65 + /// <summary>
  66 + /// 成本-人工-总经理底薪
  67 + /// </summary>
  68 + public decimal CostGMBase { get; set; }
  69 +
  70 + /// <summary>
  71 + /// 成本-人工-总经理提成
  72 + /// </summary>
  73 + public decimal CostGMComm { get; set; }
  74 +
  75 + /// <summary>
  76 + /// 奖励-科技部
  77 + /// </summary>
  78 + public decimal RewardTechDept { get; set; }
  79 +
  80 + /// <summary>
  81 + /// 成本-其他1
  82 + /// </summary>
  83 + public decimal CostOther1 { get; set; }
  84 +
  85 + /// <summary>
  86 + /// 成本-其他2
  87 + /// </summary>
  88 + public decimal CostOther2 { get; set; }
  89 +
  90 + /// <summary>
  91 + /// 利润
  92 + /// </summary>
  93 + public decimal Profit { get; set; }
  94 +
  95 + /// <summary>
  96 + /// 创建时间
  97 + /// </summary>
  98 + public DateTime CreateTime { get; set; }
  99 +
  100 + /// <summary>
  101 + /// 更新时间
  102 + /// </summary>
  103 + public DateTime? UpdateTime { get; set; }
  104 + }
  105 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqShareStatisticsTechDept/ShareStatisticsTechDeptQueryInput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.LqShareStatisticsTechDept
  2 +{
  3 + /// <summary>
  4 + /// 科技部股份统计查询输入
  5 + /// </summary>
  6 + public class ShareStatisticsTechDeptQueryInput
  7 + {
  8 + /// <summary>
  9 + /// 统计月份(YYYYMM)
  10 + /// </summary>
  11 + public string StatisticsMonth { get; set; }
  12 +
  13 + /// <summary>
  14 + /// 部门名称
  15 + /// </summary>
  16 + public string DepartmentName { get; set; }
  17 + }
  18 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_hq/LqShareStatisticsHqEntity.cs 0 → 100644
  1 +using System;
  2 +using NCC.Common.Const;
  3 +using SqlSugar;
  4 +
  5 +namespace NCC.Extend.Entitys.lq_share_statistics_hq
  6 +{
  7 + /// <summary>
  8 + /// 总部股份统计表
  9 + /// </summary>
  10 + [SugarTable("lq_share_statistics_hq")]
  11 + [Tenant(ClaimConst.TENANT_ID)]
  12 + public class LqShareStatisticsHqEntity
  13 + {
  14 + /// <summary>
  15 + /// 主键ID
  16 + /// </summary>
  17 + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
  18 + public string Id { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 统计月份(YYYYMM)
  22 + /// </summary>
  23 + [SugarColumn(ColumnName = "F_StatisticsMonth")]
  24 + public string StatisticsMonth { get; set; }
  25 +
  26 + /// <summary>
  27 + /// 收入-全部(开单业绩9%)
  28 + /// </summary>
  29 + [SugarColumn(ColumnName = "F_IncomeGeneral")]
  30 + public decimal IncomeGeneral { get; set; }
  31 +
  32 + /// <summary>
  33 + /// 收入-科技部(科美30%的9%)
  34 + /// </summary>
  35 + [SugarColumn(ColumnName = "F_IncomeTechDept")]
  36 + public decimal IncomeTechDept { get; set; }
  37 +
  38 + /// <summary>
  39 + /// 成本-报销(总部费用)
  40 + /// </summary>
  41 + [SugarColumn(ColumnName = "F_CostReimbursement")]
  42 + public decimal CostReimbursement { get; set; }
  43 +
  44 + /// <summary>
  45 + /// 成本-人工(保留)
  46 + /// </summary>
  47 + [SugarColumn(ColumnName = "F_CostLabor")]
  48 + public decimal CostLabor { get; set; }
  49 +
  50 + /// <summary>
  51 + /// 成本-教育部房租
  52 + /// </summary>
  53 + [SugarColumn(ColumnName = "F_CostEducationRent")]
  54 + public decimal CostEducationRent { get; set; }
  55 +
  56 + /// <summary>
  57 + /// 成本-仓库房租
  58 + /// </summary>
  59 + [SugarColumn(ColumnName = "F_CostWarehouseRent")]
  60 + public decimal CostWarehouseRent { get; set; }
  61 +
  62 + /// <summary>
  63 + /// 成本-总部房租
  64 + /// </summary>
  65 + [SugarColumn(ColumnName = "F_CostHQRent")]
  66 + public decimal CostHQRent { get; set; }
  67 +
  68 + /// <summary>
  69 + /// 总部运营利润
  70 + /// </summary>
  71 + [SugarColumn(ColumnName = "F_OperationalProfit")]
  72 + public decimal OperationalProfit { get; set; }
  73 +
  74 + /// <summary>
  75 + /// 创建时间
  76 + /// </summary>
  77 + [SugarColumn(ColumnName = "F_CreateTime")]
  78 + public DateTime CreateTime { get; set; }
  79 +
  80 + /// <summary>
  81 + /// 更新时间
  82 + /// </summary>
  83 + [SugarColumn(ColumnName = "F_UpdateTime")]
  84 + public DateTime? UpdateTime { get; set; }
  85 +
  86 + /// <summary>
  87 + /// 创建人
  88 + /// </summary>
  89 + [SugarColumn(ColumnName = "F_CreateUser")]
  90 + public string CreateUser { get; set; }
  91 +
  92 + /// <summary>
  93 + /// 更新人
  94 + /// </summary>
  95 + [SugarColumn(ColumnName = "F_UpdateUser")]
  96 + public string UpdateUser { get; set; }
  97 +
  98 + /// <summary>
  99 + /// 是否有效(1:有效 0:无效)
  100 + /// </summary>
  101 + [SugarColumn(ColumnName = "F_IsEffective")]
  102 + public int IsEffective { get; set; } = 1;
  103 + }
  104 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_store/LqShareStatisticsStoreEntity.cs 0 → 100644
  1 +using System;
  2 +using NCC.Common.Const;
  3 +using SqlSugar;
  4 +
  5 +namespace NCC.Extend.Entitys.lq_share_statistics_store
  6 +{
  7 + /// <summary>
  8 + /// 门店股份统计表
  9 + /// </summary>
  10 + [SugarTable("lq_share_statistics_store")]
  11 + [Tenant(ClaimConst.TENANT_ID)]
  12 + public class LqShareStatisticsStoreEntity
  13 + {
  14 + /// <summary>
  15 + /// 主键ID
  16 + /// </summary>
  17 + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
  18 + public string Id { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 门店ID
  22 + /// </summary>
  23 + [SugarColumn(ColumnName = "F_StoreId")]
  24 + public string StoreId { get; set; }
  25 +
  26 + /// <summary>
  27 + /// 门店名称
  28 + /// </summary>
  29 + [SugarColumn(ColumnName = "F_StoreName")]
  30 + public string StoreName { get; set; }
  31 +
  32 + /// <summary>
  33 + /// 统计月份(YYYYMM)
  34 + /// </summary>
  35 + [SugarColumn(ColumnName = "F_StatisticsMonth")]
  36 + public string StatisticsMonth { get; set; }
  37 +
  38 + // 收入部分
  39 + /// <summary>
  40 + /// 主营收入(消耗业绩-对应退款)
  41 + /// </summary>
  42 + [SugarColumn(ColumnName = "F_MainIncome")]
  43 + public decimal MainIncome { get; set; }
  44 +
  45 + /// <summary>
  46 + /// 其他收入(退款差额>0)
  47 + /// </summary>
  48 + [SugarColumn(ColumnName = "F_OtherIncome")]
  49 + public decimal OtherIncome { get; set; }
  50 +
  51 + /// <summary>
  52 + /// 预收款(开单实付)
  53 + /// </summary>
  54 + [SugarColumn(ColumnName = "F_AdvanceReceipt")]
  55 + public decimal AdvanceReceipt { get; set; }
  56 +
  57 + /// <summary>
  58 + /// 实际退款(实退业绩)
  59 + /// </summary>
  60 + [SugarColumn(ColumnName = "F_Refund")]
  61 + public decimal Refund { get; set; }
  62 +
  63 + /// <summary>
  64 + /// 应收(合作医院)
  65 + /// </summary>
  66 + [SugarColumn(ColumnName = "F_Receivables")]
  67 + public decimal Receivables { get; set; }
  68 +
  69 + /// <summary>
  70 + /// 银行存款(开单实付-应收)
  71 + /// </summary>
  72 + [SugarColumn(ColumnName = "F_BankDeposit")]
  73 + public decimal BankDeposit { get; set; }
  74 +
  75 + // 成本部分
  76 + /// <summary>
  77 + /// 主营成本-产品(仓库领取)
  78 + /// </summary>
  79 + [SugarColumn(ColumnName = "F_CostProduct")]
  80 + public decimal CostProduct { get; set; }
  81 +
  82 + /// <summary>
  83 + /// 主营成本-福田(福田仓库领取)
  84 + /// </summary>
  85 + [SugarColumn(ColumnName = "F_CostFutian")]
  86 + public decimal CostFutian { get; set; }
  87 +
  88 + /// <summary>
  89 + /// 主营成本-毛巾(清洗送出)
  90 + /// </summary>
  91 + [SugarColumn(ColumnName = "F_CostTowel")]
  92 + public decimal CostTowel { get; set; }
  93 +
  94 + /// <summary>
  95 + /// 主营成本-科技部(科美业绩30%)
  96 + /// </summary>
  97 + [SugarColumn(ColumnName = "F_CostTechDept")]
  98 + public decimal CostTechDept { get; set; }
  99 +
  100 + /// <summary>
  101 + /// 主营成本-管理费(总业绩9%)
  102 + /// </summary>
  103 + [SugarColumn(ColumnName = "F_CostManagementFee")]
  104 + public decimal CostManagementFee { get; set; }
  105 +
  106 + /// <summary>
  107 + /// 主营成本-合作(保留)
  108 + /// </summary>
  109 + [SugarColumn(ColumnName = "F_CostCooperation")]
  110 + public decimal CostCooperation { get; set; }
  111 +
  112 + /// <summary>
  113 + /// 主营成本-大项目(保留)
  114 + /// </summary>
  115 + [SugarColumn(ColumnName = "F_CostMajorProject")]
  116 + public decimal CostMajorProject { get; set; }
  117 +
  118 + /// <summary>
  119 + /// 其他成本(退款差额<0)
  120 + /// </summary>
  121 + [SugarColumn(ColumnName = "F_CostOther")]
  122 + public decimal CostOther { get; set; }
  123 +
  124 + // 人工工资部分
  125 + /// <summary>
  126 + /// 人工工资-健康师底薪
  127 + /// </summary>
  128 + [SugarColumn(ColumnName = "F_SalaryBaseHealthCoach")]
  129 + public decimal SalaryBaseHealthCoach { get; set; }
  130 +
  131 + /// <summary>
  132 + /// 人工工资-店助底薪
  133 + /// </summary>
  134 + [SugarColumn(ColumnName = "F_SalaryBaseAssistant")]
  135 + public decimal SalaryBaseAssistant { get; set; }
  136 +
  137 + /// <summary>
  138 + /// 人工工资-店助主任底薪
  139 + /// </summary>
  140 + [SugarColumn(ColumnName = "F_SalaryBaseDirector")]
  141 + public decimal SalaryBaseDirector { get; set; }
  142 +
  143 + /// <summary>
  144 + /// 人工工资-店长底薪
  145 + /// </summary>
  146 + [SugarColumn(ColumnName = "F_SalaryBaseStoreManager")]
  147 + public decimal SalaryBaseStoreManager { get; set; }
  148 +
  149 + /// <summary>
  150 + /// 人工工资-总经理/经理底薪
  151 + /// </summary>
  152 + [SugarColumn(ColumnName = "F_SalaryBaseGeneralManager")]
  153 + public decimal SalaryBaseGeneralManager { get; set; }
  154 +
  155 + /// <summary>
  156 + /// 人工工资-健康师提成
  157 + /// </summary>
  158 + [SugarColumn(ColumnName = "F_SalaryCommissionHealthCoach")]
  159 + public decimal SalaryCommissionHealthCoach { get; set; }
  160 +
  161 + /// <summary>
  162 + /// 人工工资-店助提成
  163 + /// </summary>
  164 + [SugarColumn(ColumnName = "F_SalaryCommissionAssistant")]
  165 + public decimal SalaryCommissionAssistant { get; set; }
  166 +
  167 + /// <summary>
  168 + /// 人工工资-店助主任提成
  169 + /// </summary>
  170 + [SugarColumn(ColumnName = "F_SalaryCommissionDirector")]
  171 + public decimal SalaryCommissionDirector { get; set; }
  172 +
  173 + /// <summary>
  174 + /// 人工工资-店长提成
  175 + /// </summary>
  176 + [SugarColumn(ColumnName = "F_SalaryCommissionStoreManager")]
  177 + public decimal SalaryCommissionStoreManager { get; set; }
  178 +
  179 + /// <summary>
  180 + /// 人工工资-总经理/经理提成
  181 + /// </summary>
  182 + [SugarColumn(ColumnName = "F_SalaryCommissionGeneralManager")]
  183 + public decimal SalaryCommissionGeneralManager { get; set; }
  184 +
  185 + /// <summary>
  186 + /// 人工工资-手工
  187 + /// </summary>
  188 + [SugarColumn(ColumnName = "F_SalaryManual")]
  189 + public decimal SalaryManual { get; set; }
  190 +
  191 + /// <summary>
  192 + /// 人工工资-出勤(保留)
  193 + /// </summary>
  194 + [SugarColumn(ColumnName = "F_SalaryAttendance")]
  195 + public decimal SalaryAttendance { get; set; }
  196 +
  197 + /// <summary>
  198 + /// 人工工资-岗位-手机保管费
  199 + /// </summary>
  200 + [SugarColumn(ColumnName = "F_SalaryPhoneCustody")]
  201 + public decimal SalaryPhoneCustody { get; set; }
  202 +
  203 + /// <summary>
  204 + /// 人工工资-岗位-人头
  205 + /// </summary>
  206 + [SugarColumn(ColumnName = "F_SalaryHeadcountReward")]
  207 + public decimal SalaryHeadcountReward { get; set; }
  208 +
  209 + /// <summary>
  210 + /// 人工工资-门店T区
  211 + /// </summary>
  212 + [SugarColumn(ColumnName = "F_SalaryTZone")]
  213 + public decimal SalaryTZone { get; set; }
  214 +
  215 + // 费用与其他
  216 + /// <summary>
  217 + /// 社保(保留)
  218 + /// </summary>
  219 + [SugarColumn(ColumnName = "F_SocialSecurity")]
  220 + public decimal SocialSecurity { get; set; }
  221 +
  222 + /// <summary>
  223 + /// 门店房租
  224 + /// </summary>
  225 + [SugarColumn(ColumnName = "F_StoreRent")]
  226 + public decimal StoreRent { get; set; }
  227 +
  228 + /// <summary>
  229 + /// 宿舍房租(保留)
  230 + /// </summary>
  231 + [SugarColumn(ColumnName = "F_DormRent")]
  232 + public decimal DormRent { get; set; }
  233 +
  234 + /// <summary>
  235 + /// 当期费用(报销)
  236 + /// </summary>
  237 + [SugarColumn(ColumnName = "F_CurrentPeriodExpense")]
  238 + public decimal CurrentPeriodExpense { get; set; }
  239 +
  240 + /// <summary>
  241 + /// 当前费用-秦董(保留)
  242 + /// </summary>
  243 + [SugarColumn(ColumnName = "F_CurrentPeriodExpenseQin")]
  244 + public decimal CurrentPeriodExpenseQin { get; set; }
  245 +
  246 + /// <summary>
  247 + /// 财务费用(保留)
  248 + /// </summary>
  249 + [SugarColumn(ColumnName = "F_FinancialFee")]
  250 + public decimal FinancialFee { get; set; }
  251 +
  252 + // 奖励
  253 + /// <summary>
  254 + /// 奖励-医美(保留)
  255 + /// </summary>
  256 + [SugarColumn(ColumnName = "F_RewardMedicalBeauty")]
  257 + public decimal RewardMedicalBeauty { get; set; }
  258 +
  259 + /// <summary>
  260 + /// 奖励-其他(保留)
  261 + /// </summary>
  262 + [SugarColumn(ColumnName = "F_RewardOther")]
  263 + public decimal RewardOther { get; set; }
  264 +
  265 + /// <summary>
  266 + /// 奖励-大单奖(保留)
  267 + /// </summary>
  268 + [SugarColumn(ColumnName = "F_RewardLargeOrder")]
  269 + public decimal RewardLargeOrder { get; set; }
  270 +
  271 + /// <summary>
  272 + /// 奖励-首单奖(保留)
  273 + /// </summary>
  274 + [SugarColumn(ColumnName = "F_RewardFirstOrder")]
  275 + public decimal RewardFirstOrder { get; set; }
  276 +
  277 + /// <summary>
  278 + /// 奖励(保留)
  279 + /// </summary>
  280 + [SugarColumn(ColumnName = "F_RewardGeneral")]
  281 + public decimal RewardGeneral { get; set; }
  282 +
  283 + // 其他保留字段
  284 + /// <summary>
  285 + /// 其他1(保留)
  286 + /// </summary>
  287 + [SugarColumn(ColumnName = "F_Other1")]
  288 + public decimal Other1 { get; set; }
  289 +
  290 + /// <summary>
  291 + /// 其他2(保留)
  292 + /// </summary>
  293 + [SugarColumn(ColumnName = "F_Other2")]
  294 + public decimal Other2 { get; set; }
  295 +
  296 + // 利润结果
  297 + /// <summary>
  298 + /// 利润(预收-实退-主营成本-人工工资[分项汇总]-房租-费用-奖励-其他)
  299 + /// </summary>
  300 + [SugarColumn(ColumnName = "F_Profit")]
  301 + public decimal Profit { get; set; }
  302 +
  303 + /// <summary>
  304 + /// 财务利润(主营-其他收入-主营成本-人工工资[分项汇总]-房租-费用-奖励-其他)
  305 + /// </summary>
  306 + [SugarColumn(ColumnName = "F_FinancialProfit")]
  307 + public decimal FinancialProfit { get; set; }
  308 +
  309 + // 基础字段
  310 + /// <summary>
  311 + /// 创建时间
  312 + /// </summary>
  313 + [SugarColumn(ColumnName = "F_CreateTime")]
  314 + public DateTime? CreateTime { get; set; }
  315 +
  316 + /// <summary>
  317 + /// 更新时间
  318 + /// </summary>
  319 + [SugarColumn(ColumnName = "F_UpdateTime")]
  320 + public DateTime? UpdateTime { get; set; }
  321 +
  322 + /// <summary>
  323 + /// 创建人
  324 + /// </summary>
  325 + [SugarColumn(ColumnName = "F_CreateUser")]
  326 + public string CreateUser { get; set; }
  327 +
  328 + /// <summary>
  329 + /// 更新人
  330 + /// </summary>
  331 + [SugarColumn(ColumnName = "F_UpdateUser")]
  332 + public string UpdateUser { get; set; }
  333 +
  334 + /// <summary>
  335 + /// 是否有效(1:有效 0:无效)
  336 + /// </summary>
  337 + [SugarColumn(ColumnName = "F_IsEffective")]
  338 + public int IsEffective { get; set; }
  339 + }
  340 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_share_statistics_tech_dept/LqShareStatisticsTechDeptEntity.cs 0 → 100644
  1 +using System;
  2 +using NCC.Common.Const;
  3 +using SqlSugar;
  4 +
  5 +namespace NCC.Extend.Entitys.lq_share_statistics_tech_dept
  6 +{
  7 + /// <summary>
  8 + /// 科技部股份统计表
  9 + /// </summary>
  10 + [SugarTable("lq_share_statistics_tech_dept")]
  11 + [Tenant(ClaimConst.TENANT_ID)]
  12 + public class LqShareStatisticsTechDeptEntity
  13 + {
  14 + /// <summary>
  15 + /// 主键ID
  16 + /// </summary>
  17 + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
  18 + public string Id { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 部门名称(科技一部/二部)
  22 + /// </summary>
  23 + [SugarColumn(ColumnName = "F_DepartmentName")]
  24 + public string DepartmentName { get; set; }
  25 +
  26 + /// <summary>
  27 + /// 统计月份(YYYYMM)
  28 + /// </summary>
  29 + [SugarColumn(ColumnName = "F_StatisticsMonth")]
  30 + public string StatisticsMonth { get; set; }
  31 +
  32 + /// <summary>
  33 + /// 收入(门店科美开单30%)
  34 + /// </summary>
  35 + [SugarColumn(ColumnName = "F_Income")]
  36 + public decimal Income { get; set; }
  37 +
  38 + /// <summary>
  39 + /// 成本-报销
  40 + /// </summary>
  41 + [SugarColumn(ColumnName = "F_CostReimbursement")]
  42 + public decimal CostReimbursement { get; set; }
  43 +
  44 + /// <summary>
  45 + /// 成本-人工-科技部老师底薪
  46 + /// </summary>
  47 + [SugarColumn(ColumnName = "F_CostTeacherBase")]
  48 + public decimal CostTeacherBase { get; set; }
  49 +
  50 + /// <summary>
  51 + /// 成本-人工-科技部手工费
  52 + /// </summary>
  53 + [SugarColumn(ColumnName = "F_CostTeacherManual")]
  54 + public decimal CostTeacherManual { get; set; }
  55 +
  56 + /// <summary>
  57 + /// 成本-人工-科技部开单提成
  58 + /// </summary>
  59 + [SugarColumn(ColumnName = "F_CostTeacherBillingComm")]
  60 + public decimal CostTeacherBillingComm { get; set; }
  61 +
  62 + /// <summary>
  63 + /// 成本-人工-科技部消耗提成
  64 + /// </summary>
  65 + [SugarColumn(ColumnName = "F_CostTeacherConsumeComm")]
  66 + public decimal CostTeacherConsumeComm { get; set; }
  67 +
  68 + /// <summary>
  69 + /// 成本-人工-科技部专家提成(保留)
  70 + /// </summary>
  71 + [SugarColumn(ColumnName = "F_CostTeacherExpertComm")]
  72 + public decimal CostTeacherExpertComm { get; set; }
  73 +
  74 + /// <summary>
  75 + /// 成本-人工-科技部加班(保留)
  76 + /// </summary>
  77 + [SugarColumn(ColumnName = "F_CostTeacherOvertime")]
  78 + public decimal CostTeacherOvertime { get; set; }
  79 +
  80 + /// <summary>
  81 + /// 成本-人工-科技部总经理底薪
  82 + /// </summary>
  83 + [SugarColumn(ColumnName = "F_CostGMBase")]
  84 + public decimal CostGMBase { get; set; }
  85 +
  86 + /// <summary>
  87 + /// 成本-人工-科技部总经理提成
  88 + /// </summary>
  89 + [SugarColumn(ColumnName = "F_CostGMComm")]
  90 + public decimal CostGMComm { get; set; }
  91 +
  92 + /// <summary>
  93 + /// 奖励-科技部(保留)
  94 + /// </summary>
  95 + [SugarColumn(ColumnName = "F_RewardTechDept")]
  96 + public decimal RewardTechDept { get; set; }
  97 +
  98 + /// <summary>
  99 + /// 成本-其他1(保留)
  100 + /// </summary>
  101 + [SugarColumn(ColumnName = "F_CostOther1")]
  102 + public decimal CostOther1 { get; set; }
  103 +
  104 + /// <summary>
  105 + /// 成本-其他2(保留)
  106 + /// </summary>
  107 + [SugarColumn(ColumnName = "F_CostOther2")]
  108 + public decimal CostOther2 { get; set; }
  109 +
  110 + /// <summary>
  111 + /// 科技部利润
  112 + /// </summary>
  113 + [SugarColumn(ColumnName = "F_Profit")]
  114 + public decimal Profit { get; set; }
  115 +
  116 + /// <summary>
  117 + /// 创建时间
  118 + /// </summary>
  119 + [SugarColumn(ColumnName = "F_CreateTime")]
  120 + public DateTime CreateTime { get; set; }
  121 +
  122 + /// <summary>
  123 + /// 更新时间
  124 + /// </summary>
  125 + [SugarColumn(ColumnName = "F_UpdateTime")]
  126 + public DateTime? UpdateTime { get; set; }
  127 +
  128 + /// <summary>
  129 + /// 创建人
  130 + /// </summary>
  131 + [SugarColumn(ColumnName = "F_CreateUser")]
  132 + public string CreateUser { get; set; }
  133 +
  134 + /// <summary>
  135 + /// 更新人
  136 + /// </summary>
  137 + [SugarColumn(ColumnName = "F_UpdateUser")]
  138 + public string UpdateUser { get; set; }
  139 +
  140 + /// <summary>
  141 + /// 是否有效(1:有效 0:无效)
  142 + /// </summary>
  143 + [SugarColumn(ColumnName = "F_IsEffective")]
  144 + public int IsEffective { get; set; } = 1;
  145 + }
  146 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
... ... @@ -2294,6 +2294,7 @@ namespace NCC.Extend.LqKdKdjlb
2294 2294 Sfyj = input.Sfyj,
2295 2295 DeductAmount = input.DeductAmount,
2296 2296 Qk = input.Qk,
  2297 + Bz = input.Remark,
2297 2298 UpdateTime = DateTime.Now
2298 2299 }).Where(w => w.Id == input.BillingId).ExecuteCommandAsync();
2299 2300  
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsHqService.cs 0 → 100644
  1 +using Microsoft.AspNetCore.Mvc;
  2 +using NCC.Common.Filter;
  3 +using NCC.Dependency;
  4 +using NCC.DynamicApiController;
  5 +using NCC.Extend.Entitys.Dto.LqShareStatisticsHq;
  6 +using NCC.Extend.Entitys.lq_share_statistics_hq;
  7 +using NCC.Extend.Entitys.lq_kd_kdjlb;
  8 +using NCC.Extend.Entitys.lq_hytk_hytk;
  9 +using NCC.Extend.Entitys.lq_kd_pxmx;
  10 +using NCC.Extend.Entitys.lq_contract_rent_detail;
  11 +using SqlSugar;
  12 +using System;
  13 +using System.Linq;
  14 +using System.Threading.Tasks;
  15 +using Yitter.IdGenerator;
  16 +
  17 +namespace NCC.Extend
  18 +{
  19 + /// <summary>
  20 + /// 总部股份统计服务
  21 + /// </summary>
  22 + [ApiDescriptionSettings(Tag = "总部股份统计服务", Name = "LqShareStatisticsHq", Order = 402)]
  23 + [Route("api/Extend/[controller]")]
  24 + public class LqShareStatisticsHqService : IDynamicApiController, ITransient
  25 + {
  26 + private readonly ISqlSugarClient _db;
  27 +
  28 + public LqShareStatisticsHqService(ISqlSugarClient db)
  29 + {
  30 + _db = db;
  31 + }
  32 +
  33 + /// <summary>
  34 + /// 生成总部股份统计数据
  35 + /// </summary>
  36 + /// <param name="input">生成参数</param>
  37 + /// <returns>生成结果</returns>
  38 + [HttpPost("generate")]
  39 + public async Task<dynamic> GenerateStatistics([FromBody] ShareStatisticsHqGenerateInput input)
  40 + {
  41 + if (string.IsNullOrEmpty(input.StatisticsMonth) || input.StatisticsMonth.Length != 6)
  42 + {
  43 + return new { code = 500, msg = "统计月份格式错误,应为 YYYYMM" };
  44 + }
  45 +
  46 + var year = int.Parse(input.StatisticsMonth.Substring(0, 4));
  47 + var month = int.Parse(input.StatisticsMonth.Substring(4, 2));
  48 + var startDate = new DateTime(year, month, 1);
  49 + var endDate = startDate.AddMonths(1).AddDays(-1);
  50 +
  51 + // 检查是否已存在
  52 + var existing = await _db.Queryable<LqShareStatisticsHqEntity>()
  53 + .FirstAsync(x => x.StatisticsMonth == input.StatisticsMonth);
  54 +
  55 + var entity = existing ?? new LqShareStatisticsHqEntity
  56 + {
  57 + Id = YitIdHelper.NextId().ToString(),
  58 + StatisticsMonth = input.StatisticsMonth,
  59 + IsEffective = 1,
  60 + CreateTime = DateTime.Now,
  61 + CreateUser = "System"
  62 + };
  63 +
  64 + // 计算各项数据
  65 + await CalculateIncome(entity, startDate, endDate);
  66 + await CalculateCost(entity, startDate, endDate, input.StatisticsMonth);
  67 + CalculateProfit(entity);
  68 +
  69 + entity.UpdateTime = DateTime.Now;
  70 + entity.UpdateUser = "System";
  71 +
  72 + if (existing == null)
  73 + {
  74 + await _db.Insertable(entity).ExecuteCommandAsync();
  75 + return new { code = 200, msg = "生成成功", data = new { generated = true } };
  76 + }
  77 + else
  78 + {
  79 + await _db.Updateable(entity).ExecuteCommandAsync();
  80 + return new { code = 200, msg = "更新成功", data = new { updated = true } };
  81 + }
  82 + }
  83 +
  84 + /// <summary>
  85 + /// 查询总部股份统计列表
  86 + /// </summary>
  87 + /// <param name="input">查询参数</param>
  88 + /// <returns>统计列表</returns>
  89 + [HttpGet("list")]
  90 + public async Task<dynamic> GetList([FromQuery] ShareStatisticsHqQueryInput input)
  91 + {
  92 + var query = _db.Queryable<LqShareStatisticsHqEntity>()
  93 + .Where(x => x.IsEffective == 1);
  94 +
  95 + if (!string.IsNullOrEmpty(input.StatisticsMonth))
  96 + {
  97 + query = query.Where(x => x.StatisticsMonth == input.StatisticsMonth);
  98 + }
  99 +
  100 + var list = await query.OrderBy(x => x.StatisticsMonth, OrderByType.Desc)
  101 + .Select(x => new ShareStatisticsHqOutput
  102 + {
  103 + Id = x.Id,
  104 + StatisticsMonth = x.StatisticsMonth,
  105 + IncomeGeneral = x.IncomeGeneral,
  106 + IncomeTechDept = x.IncomeTechDept,
  107 + CostReimbursement = x.CostReimbursement,
  108 + CostLabor = x.CostLabor,
  109 + CostEducationRent = x.CostEducationRent,
  110 + CostWarehouseRent = x.CostWarehouseRent,
  111 + CostHQRent = x.CostHQRent,
  112 + OperationalProfit = x.OperationalProfit,
  113 + CreateTime = x.CreateTime,
  114 + UpdateTime = x.UpdateTime
  115 + })
  116 + .ToListAsync();
  117 +
  118 + return new { code = 200, msg = "查询成功", data = list };
  119 + }
  120 +
  121 + #region 私有计算方法
  122 +
  123 + /// <summary>
  124 + /// 计算收入部分
  125 + /// </summary>
  126 + private async Task CalculateIncome(LqShareStatisticsHqEntity entity, DateTime startDate, DateTime endDate)
  127 + {
  128 + // 1. 收入-全部 = (所有门店的总开单实付业绩 - 所有门店的总实退金额) * 9%
  129 + var totalBilling = await _db.Queryable<LqKdKdjlbEntity>()
  130 + .Where(x => x.Kdrq >= startDate && x.Kdrq <= endDate && x.IsEffective == 1)
  131 + .SumAsync(x => x.Sfyj);
  132 +
  133 + var totalRefund = await _db.Queryable<LqHytkHytkEntity>()
  134 + .Where(x => x.Tksj >= startDate && x.Tksj <= endDate && x.IsEffective == 1)
  135 + .SumAsync(x => x.Tkje ?? 0);
  136 +
  137 + entity.IncomeGeneral = (totalBilling - totalRefund) * 0.09m;
  138 +
  139 + // 2. 收入-科技部 = (总科美业绩 - 总科美退款) * 0.3 * 0.09
  140 + var kemeiPerformance = await _db.Queryable<LqKdPxmxEntity>()
  141 + .Where(x => x.Yjsj >= startDate && x.Yjsj <= endDate && x.IsEffective == 1)
  142 + .Where(x => x.ItemCategory == "科美")
  143 + .SumAsync(x => x.TotalPrice);
  144 +
  145 + // TODO: 需要确认科美退款的统计方式
  146 + entity.IncomeTechDept = kemeiPerformance * 0.3m * 0.09m;
  147 + }
  148 +
  149 + /// <summary>
  150 + /// 计算成本部分
  151 + /// </summary>
  152 + private async Task CalculateCost(LqShareStatisticsHqEntity entity, DateTime startDate, DateTime endDate, string statisticsMonth)
  153 + {
  154 + // 1. 成本-报销 (TODO: 需要确认总部报销的判定方式)
  155 + entity.CostReimbursement = 0;
  156 +
  157 + // 2. 成本-人工 (保留)
  158 + entity.CostLabor = 0;
  159 +
  160 + // 3. 成本-教育部房租
  161 + // TODO: 需要确认如何识别教育部合同
  162 + entity.CostEducationRent = 0;
  163 +
  164 + // 4. 成本-仓库房租
  165 + // TODO: 需要确认如何识别仓库合同
  166 + entity.CostWarehouseRent = 0;
  167 +
  168 + // 5. 成本-总部房租
  169 + // TODO: 需要确认如何识别总部合同
  170 + entity.CostHQRent = 0;
  171 + }
  172 +
  173 + /// <summary>
  174 + /// 计算利润
  175 + /// </summary>
  176 + private void CalculateProfit(LqShareStatisticsHqEntity entity)
  177 + {
  178 + // 总部运营利润 = 收入(门店9%) + 收入(科技部9%) - 成本(报销) - 成本(人工) - 成本(房租)
  179 + var totalIncome = entity.IncomeGeneral + entity.IncomeTechDept;
  180 + var totalCost = entity.CostReimbursement
  181 + + entity.CostLabor
  182 + + entity.CostEducationRent
  183 + + entity.CostWarehouseRent
  184 + + entity.CostHQRent;
  185 +
  186 + entity.OperationalProfit = totalIncome - totalCost;
  187 + }
  188 +
  189 + #endregion
  190 + }
  191 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsStoreService.cs 0 → 100644
  1 +using Microsoft.AspNetCore.Mvc;
  2 +using NCC.Common.Filter;
  3 +using NCC.Dependency;
  4 +using NCC.DynamicApiController;
  5 +using NCC.Extend.Entitys.Dto.LqShareStatisticsStore;
  6 +using NCC.Extend.Entitys.lq_share_statistics_store;
  7 +using NCC.Extend.Entitys.lq_xh_jksyj;
  8 +using NCC.Extend.Entitys.lq_kd_kdjlb;
  9 +using NCC.Extend.Entitys.lq_hytk_hytk;
  10 +using NCC.Extend.Entitys.lq_hytk_jksyj;
  11 +using NCC.Extend.Entitys.lq_inventory_usage;
  12 +using NCC.Extend.Entitys.lq_laundry_flow;
  13 +using NCC.Extend.Entitys.lq_salary_statistics;
  14 +using NCC.Extend.Entitys.lq_assistant_salary_statistics;
  15 +using NCC.Extend.Entitys.lq_director_salary_statistics;
  16 +using NCC.Extend.Entitys.lq_store_manager_salary_statistics;
  17 +using NCC.Extend.Entitys.lq_business_unit_manager_salary_statistics;
  18 +using NCC.Extend.Entitys.lq_contract_rent_detail;
  19 +using NCC.Extend.Entitys.lq_mdxx;
  20 +using NCC.Extend.Entitys.lq_kd_pxmx;
  21 +using SqlSugar;
  22 +using System;
  23 +using System.Collections.Generic;
  24 +using System.Linq;
  25 +using System.Threading.Tasks;
  26 +using Yitter.IdGenerator;
  27 +
  28 +namespace NCC.Extend
  29 +{
  30 + /// <summary>
  31 + /// 门店股份统计服务
  32 + /// </summary>
  33 + [ApiDescriptionSettings(Tag = "门店股份统计服务", Name = "LqShareStatisticsStore", Order = 400)]
  34 + [Route("api/Extend/[controller]")]
  35 + public class LqShareStatisticsStoreService : IDynamicApiController, ITransient
  36 + {
  37 + private readonly ISqlSugarClient _db;
  38 +
  39 + public LqShareStatisticsStoreService(ISqlSugarClient db)
  40 + {
  41 + _db = db;
  42 + }
  43 +
  44 + /// <summary>
  45 + /// 生成门店股份统计数据
  46 + /// </summary>
  47 + /// <param name="input">生成参数</param>
  48 + /// <returns>生成结果</returns>
  49 + [HttpPost("generate")]
  50 + public async Task<dynamic> GenerateStatistics([FromBody] ShareStatisticsStoreGenerateInput input)
  51 + {
  52 + if (string.IsNullOrEmpty(input.StatisticsMonth) || input.StatisticsMonth.Length != 6)
  53 + {
  54 + return new { code = 500, msg = "统计月份格式错误,应为 YYYYMM" };
  55 + }
  56 +
  57 + var year = int.Parse(input.StatisticsMonth.Substring(0, 4));
  58 + var month = int.Parse(input.StatisticsMonth.Substring(4, 2));
  59 + var startDate = new DateTime(year, month, 1);
  60 + var endDate = startDate.AddMonths(1).AddDays(-1);
  61 +
  62 + // 获取门店列表
  63 + var storeQuery = _db.Queryable<LqMdxxEntity>();
  64 + if (!string.IsNullOrEmpty(input.StoreId))
  65 + {
  66 + storeQuery = storeQuery.Where(x => x.Id == input.StoreId);
  67 + }
  68 + var stores = await storeQuery.ToListAsync();
  69 +
  70 + if (stores.Count == 0)
  71 + {
  72 + return new { code = 500, msg = "未找到有效门店" };
  73 + }
  74 +
  75 + var generatedCount = 0;
  76 + var updatedCount = 0;
  77 +
  78 + foreach (var store in stores)
  79 + {
  80 + try
  81 + {
  82 + // 检查是否已存在
  83 + var existing = await _db.Queryable<LqShareStatisticsStoreEntity>()
  84 + .FirstAsync(x => x.StoreId == store.Id && x.StatisticsMonth == input.StatisticsMonth);
  85 +
  86 + var entity = existing ?? new LqShareStatisticsStoreEntity
  87 + {
  88 + Id = YitIdHelper.NextId().ToString(),
  89 + StoreId = store.Id,
  90 + StoreName = store.Dm,
  91 + StatisticsMonth = input.StatisticsMonth,
  92 + IsEffective = 1,
  93 + CreateTime = DateTime.Now,
  94 + CreateUser = "System"
  95 + };
  96 +
  97 + // 计算各项数据
  98 + await CalculateIncome(entity, startDate, endDate);
  99 + await CalculateCost(entity, startDate, endDate);
  100 + await CalculateSalary(entity, input.StatisticsMonth);
  101 + await CalculateExpense(entity, startDate, endDate, input.StatisticsMonth);
  102 + CalculateProfit(entity);
  103 +
  104 + entity.UpdateTime = DateTime.Now;
  105 + entity.UpdateUser = "System";
  106 +
  107 + if (existing == null)
  108 + {
  109 + await _db.Insertable(entity).ExecuteCommandAsync();
  110 + generatedCount++;
  111 + }
  112 + else
  113 + {
  114 + await _db.Updateable(entity).ExecuteCommandAsync();
  115 + updatedCount++;
  116 + }
  117 + }
  118 + catch (Exception ex)
  119 + {
  120 + return new { code = 500, msg = $"处理门店 {store.Dm} 时出错: {ex.Message}, StackTrace: {ex.StackTrace}" };
  121 + }
  122 + }
  123 +
  124 + return new
  125 + {
  126 + code = 200,
  127 + msg = "生成成功",
  128 + data = new
  129 + {
  130 + generatedCount,
  131 + updatedCount,
  132 + totalCount = stores.Count
  133 + }
  134 + };
  135 + }
  136 +
  137 + /// <summary>
  138 + /// 查询门店股份统计列表
  139 + /// </summary>
  140 + /// <param name="input">查询参数</param>
  141 + /// <returns>统计列表</returns>
  142 + [HttpGet("list")]
  143 + public async Task<dynamic> GetList([FromQuery] ShareStatisticsStoreQueryInput input)
  144 + {
  145 + var query = _db.Queryable<LqShareStatisticsStoreEntity>()
  146 + .Where(x => x.IsEffective == 1);
  147 +
  148 + if (!string.IsNullOrEmpty(input.StatisticsMonth))
  149 + {
  150 + query = query.Where(x => x.StatisticsMonth == input.StatisticsMonth);
  151 + }
  152 +
  153 + if (!string.IsNullOrEmpty(input.StoreId))
  154 + {
  155 + query = query.Where(x => x.StoreId == input.StoreId);
  156 + }
  157 +
  158 + if (!string.IsNullOrEmpty(input.StoreName))
  159 + {
  160 + query = query.Where(x => x.StoreName.Contains(input.StoreName));
  161 + }
  162 +
  163 + var list = await query.OrderBy(x => x.StatisticsMonth, OrderByType.Desc)
  164 + .OrderBy(x => x.StoreName)
  165 + .Select(x => new ShareStatisticsStoreOutput
  166 + {
  167 + Id = x.Id,
  168 + StoreId = x.StoreId,
  169 + StoreName = x.StoreName,
  170 + StatisticsMonth = x.StatisticsMonth,
  171 + MainIncome = x.MainIncome,
  172 + OtherIncome = x.OtherIncome,
  173 + AdvanceReceipt = x.AdvanceReceipt,
  174 + Refund = x.Refund,
  175 + Receivables = x.Receivables,
  176 + BankDeposit = x.BankDeposit,
  177 + CostProduct = x.CostProduct,
  178 + CostFutian = x.CostFutian,
  179 + CostTowel = x.CostTowel,
  180 + CostTechDept = x.CostTechDept,
  181 + CostManagementFee = x.CostManagementFee,
  182 + CostCooperation = x.CostCooperation,
  183 + CostMajorProject = x.CostMajorProject,
  184 + CostOther = x.CostOther,
  185 + SalaryBaseHealthCoach = x.SalaryBaseHealthCoach,
  186 + SalaryBaseAssistant = x.SalaryBaseAssistant,
  187 + SalaryBaseDirector = x.SalaryBaseDirector,
  188 + SalaryBaseStoreManager = x.SalaryBaseStoreManager,
  189 + SalaryBaseGeneralManager = x.SalaryBaseGeneralManager,
  190 + SalaryCommissionHealthCoach = x.SalaryCommissionHealthCoach,
  191 + SalaryCommissionAssistant = x.SalaryCommissionAssistant,
  192 + SalaryCommissionDirector = x.SalaryCommissionDirector,
  193 + SalaryCommissionStoreManager = x.SalaryCommissionStoreManager,
  194 + SalaryCommissionGeneralManager = x.SalaryCommissionGeneralManager,
  195 + SalaryManual = x.SalaryManual,
  196 + SalaryAttendance = x.SalaryAttendance,
  197 + SalaryPhoneCustody = x.SalaryPhoneCustody,
  198 + SalaryHeadcountReward = x.SalaryHeadcountReward,
  199 + SalaryTZone = x.SalaryTZone,
  200 + SocialSecurity = x.SocialSecurity,
  201 + StoreRent = x.StoreRent,
  202 + DormRent = x.DormRent,
  203 + CurrentPeriodExpense = x.CurrentPeriodExpense,
  204 + CurrentPeriodExpenseQin = x.CurrentPeriodExpenseQin,
  205 + FinancialFee = x.FinancialFee,
  206 + RewardMedicalBeauty = x.RewardMedicalBeauty,
  207 + RewardOther = x.RewardOther,
  208 + RewardLargeOrder = x.RewardLargeOrder,
  209 + RewardFirstOrder = x.RewardFirstOrder,
  210 + RewardGeneral = x.RewardGeneral,
  211 + Other1 = x.Other1,
  212 + Other2 = x.Other2,
  213 + Profit = x.Profit,
  214 + FinancialProfit = x.FinancialProfit,
  215 + CreateTime = x.CreateTime,
  216 + UpdateTime = x.UpdateTime
  217 + })
  218 + .ToListAsync();
  219 +
  220 + return new { code = 200, msg = "查询成功", data = list };
  221 + }
  222 +
  223 + #region 私有计算方法
  224 +
  225 + /// <summary>
  226 + /// 计算收入部分
  227 + /// </summary>
  228 + private async Task CalculateIncome(LqShareStatisticsStoreEntity entity, DateTime startDate, DateTime endDate)
  229 + {
  230 + // 1. 主营收入 = 消耗业绩 - 消耗退款
  231 + var consumePerformance = await _db.Queryable<LqXhJksyjEntity>()
  232 + .Where(x => x.StoreId == entity.StoreId && x.Yjsj >= startDate && x.Yjsj <= endDate && x.IsEffective == 1)
  233 + .SumAsync(x => x.Jksyj);
  234 +
  235 + var consumeRefund = await _db.Queryable<LqHytkJksyjEntity>()
  236 + .Where(x => x.StoreId == entity.StoreId && x.Tksj >= startDate && x.Tksj <= endDate && x.IsEffective == 1)
  237 + .SumAsync(x => x.Jksyj);
  238 +
  239 + entity.MainIncome = (consumePerformance ?? 0) - (consumeRefund ?? 0);
  240 +
  241 + // 2. 预收款 = 开单实付
  242 + entity.AdvanceReceipt = await _db.Queryable<LqKdKdjlbEntity>()
  243 + .Where(x => x.Djmd == entity.StoreId && x.Kdrq >= startDate && x.Kdrq <= endDate && x.IsEffective == 1)
  244 + .SumAsync(x => x.Sfyj);
  245 +
  246 + // 3. 实际退款 = 退卡实退金额
  247 + entity.Refund = await _db.Queryable<LqHytkHytkEntity>()
  248 + .Where(x => x.Md == entity.StoreId && x.Tksj >= startDate && x.Tksj <= endDate && x.IsEffective == 1)
  249 + .SumAsync(x => x.Tkje ?? 0);
  250 +
  251 + // 4. 应收 = 合作医院开单金额
  252 + entity.Receivables = await _db.Queryable<LqKdKdjlbEntity>()
  253 + .Where(x => x.Djmd == entity.StoreId && x.Kdrq >= startDate && x.Kdrq <= endDate
  254 + && x.IsEffective == 1 && !string.IsNullOrEmpty(x.Fkyy))
  255 + .SumAsync(x => x.Sfyj);
  256 +
  257 + // 5. 银行存款 = 开单实付 - 应收
  258 + entity.BankDeposit = entity.AdvanceReceipt - entity.Receivables;
  259 +
  260 + // 6. 其他收入 = 退款差额 > 0 的部分
  261 + var refundDiff = entity.Refund - (consumeRefund ?? 0);
  262 + entity.OtherIncome = refundDiff > 0 ? refundDiff : 0;
  263 + }
  264 +
  265 + /// <summary>
  266 + /// 计算成本部分
  267 + /// </summary>
  268 + private async Task CalculateCost(LqShareStatisticsStoreEntity entity, DateTime startDate, DateTime endDate)
  269 + {
  270 + // 1. 产品成本 = 仓库领用金额
  271 + entity.CostProduct = await _db.Queryable<LqInventoryUsageEntity>()
  272 + .Where(x => x.StoreId == entity.StoreId && x.UsageTime >= startDate && x.UsageTime <= endDate && x.IsEffective == 1)
  273 + .SumAsync(x => x.TotalAmount);
  274 +
  275 + // 2. 福田成本 = 福田仓库领用 (需要确认福田仓库ID)
  276 + // TODO: 需要确认福田仓库的识别方式
  277 + entity.CostFutian = 0;
  278 +
  279 + // 3. 毛巾成本 = 洗毛巾费用
  280 + entity.CostTowel = await _db.Queryable<LqLaundryFlowEntity>()
  281 + .Where(x => x.StoreId == entity.StoreId
  282 + && x.SendTime >= startDate && x.SendTime <= endDate
  283 + && x.IsEffective == 1)
  284 + .SumAsync(x => x.TotalPrice);
  285 +
  286 + // 4. 科技部成本 = 科美业绩 * 30%
  287 + var kemeiPerformance = await _db.Queryable<LqKdPxmxEntity>()
  288 + .Where(x => x.Glkdbh.StartsWith(entity.StoreId) && x.Yjsj >= startDate && x.Yjsj <= endDate && x.IsEffective == 1)
  289 + .Where(x => x.ItemCategory == "科美")
  290 + .SumAsync(x => x.TotalPrice);
  291 +
  292 + entity.CostTechDept = kemeiPerformance * 0.3m;
  293 +
  294 + // 5. 管理费 = 总业绩 * 9%
  295 + var totalPerformance = await _db.Queryable<LqKdKdjlbEntity>()
  296 + .Where(x => x.Djmd == entity.StoreId && x.Kdrq >= startDate && x.Kdrq <= endDate && x.IsEffective == 1)
  297 + .SumAsync(x => x.Sfyj);
  298 +
  299 + entity.CostManagementFee = totalPerformance * 0.09m;
  300 +
  301 + // 6. 其他成本 = 退款差额 < 0 的部分
  302 + var consumeRefund = await _db.Queryable<LqHytkJksyjEntity>()
  303 + .Where(x => x.StoreId == entity.StoreId && x.Tksj >= startDate && x.Tksj <= endDate && x.IsEffective == 1)
  304 + .SumAsync(x => x.Jksyj ?? 0);
  305 +
  306 + var refundDiff = entity.Refund - consumeRefund;
  307 + entity.CostOther = refundDiff < 0 ? Math.Abs(refundDiff) : 0;
  308 +
  309 + // 保留字段暂时为0
  310 + entity.CostCooperation = 0;
  311 + entity.CostMajorProject = 0;
  312 + }
  313 +
  314 + /// <summary>
  315 + /// 计算人工工资部分
  316 + /// </summary>
  317 + private async Task CalculateSalary(LqShareStatisticsStoreEntity entity, string statisticsMonth)
  318 + {
  319 + // 1. 健康师底薪和提成
  320 + var healthCoachSalary = await _db.Queryable<LqSalaryStatisticsEntity>()
  321 + .Where(x => x.StoreId == entity.StoreId && x.StatisticsMonth == statisticsMonth)
  322 + .Select(x => new
  323 + {
  324 + BaseSalary = SqlFunc.AggregateSum(x.HealthCoachBaseSalary),
  325 + Commission = SqlFunc.AggregateSum(x.TotalCommission),
  326 + Manual = SqlFunc.AggregateSum(x.HandworkFee),
  327 + TZone = SqlFunc.AggregateSum(x.StoreTZoneCommission)
  328 + })
  329 + .FirstAsync();
  330 +
  331 + entity.SalaryBaseHealthCoach = healthCoachSalary?.BaseSalary ?? 0;
  332 + entity.SalaryCommissionHealthCoach = healthCoachSalary?.Commission ?? 0;
  333 + entity.SalaryManual = healthCoachSalary?.Manual ?? 0;
  334 + entity.SalaryTZone = healthCoachSalary?.TZone ?? 0;
  335 +
  336 + // 2. 店助底薪和提成
  337 + var assistantSalary = await _db.Queryable<LqAssistantSalaryStatisticsEntity>()
  338 + .Where(x => x.StoreId == entity.StoreId && x.StatisticsMonth == statisticsMonth
  339 + && x.Position == "店助")
  340 + .Select(x => new
  341 + {
  342 + BaseSalary = SqlFunc.AggregateSum(x.BaseSalary),
  343 + Commission = SqlFunc.AggregateSum(x.CommissionAmount),
  344 + PhoneCustody = SqlFunc.AggregateSum(x.PhoneManagementFee),
  345 + HeadcountReward = SqlFunc.AggregateSum(x.Stage1Reward + x.Stage2Reward)
  346 + })
  347 + .FirstAsync();
  348 +
  349 + entity.SalaryBaseAssistant = assistantSalary?.BaseSalary ?? 0;
  350 + entity.SalaryCommissionAssistant = assistantSalary?.Commission ?? 0;
  351 + entity.SalaryPhoneCustody = assistantSalary?.PhoneCustody ?? 0;
  352 + entity.SalaryHeadcountReward = assistantSalary?.HeadcountReward ?? 0;
  353 +
  354 + // 3. 店助主任底薪和提成
  355 + var directorSalary = await _db.Queryable<LqDirectorSalaryStatisticsEntity>()
  356 + .Where(x => x.StoreId == entity.StoreId && x.StatisticsMonth == statisticsMonth)
  357 + .Select(x => new
  358 + {
  359 + BaseSalary = SqlFunc.AggregateSum(x.ActualBaseSalary),
  360 + Commission = SqlFunc.AggregateSum(x.TotalCommissionAmount)
  361 + })
  362 + .FirstAsync();
  363 +
  364 + entity.SalaryBaseDirector = directorSalary?.BaseSalary ?? 0;
  365 + entity.SalaryCommissionDirector = directorSalary?.Commission ?? 0;
  366 +
  367 + // 4. 店长底薪和提成
  368 + var storeManagerSalary = await _db.Queryable<LqStoreManagerSalaryStatisticsEntity>()
  369 + .Where(x => x.StoreId == entity.StoreId && x.StatisticsMonth == statisticsMonth)
  370 + .Select(x => new
  371 + {
  372 + BaseSalary = SqlFunc.AggregateSum(x.ActualBaseSalary),
  373 + Commission = SqlFunc.AggregateSum(x.CommissionAmount)
  374 + })
  375 + .FirstAsync();
  376 +
  377 + entity.SalaryBaseStoreManager = storeManagerSalary?.BaseSalary ?? 0;
  378 + entity.SalaryCommissionStoreManager = storeManagerSalary?.Commission ?? 0;
  379 +
  380 + // 5. 总经理/经理底薪和提成
  381 + // 底薪按门店数平均分摊,提成需要从 F_StorePerformanceDetail JSON 中提取该门店的提成
  382 + var gmSalary = await _db.Queryable<LqBusinessUnitManagerSalaryStatisticsEntity>()
  383 + .Where(x => x.StatisticsMonth == statisticsMonth)
  384 + .Where(x => x.StorePerformanceDetail.Contains(entity.StoreId))
  385 + .ToListAsync();
  386 +
  387 + decimal gmBaseSalary = 0;
  388 + decimal gmCommission = 0;
  389 +
  390 + foreach (var gm in gmSalary)
  391 + {
  392 + // 底薪平均分摊
  393 + if (!string.IsNullOrEmpty(gm.StorePerformanceDetail))
  394 + {
  395 + try
  396 + {
  397 + var storeDetails = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(gm.StorePerformanceDetail);
  398 + var storeCount = storeDetails?.Count ?? 1;
  399 + gmBaseSalary += gm.BaseSalary / storeCount;
  400 +
  401 + // 提取该门店的提成
  402 + var storeDetail = storeDetails?.FirstOrDefault(s => s.ContainsKey("StoreId") && s["StoreId"].ToString() == entity.StoreId);
  403 + if (storeDetail != null && storeDetail.ContainsKey("Commission"))
  404 + {
  405 + gmCommission += Convert.ToDecimal(storeDetail["Commission"]);
  406 + }
  407 + }
  408 + catch
  409 + {
  410 + // JSON 解析失败,使用默认分摊
  411 + gmBaseSalary += gm.BaseSalary;
  412 + }
  413 + }
  414 + }
  415 +
  416 + entity.SalaryBaseGeneralManager = gmBaseSalary;
  417 + entity.SalaryCommissionGeneralManager = gmCommission;
  418 +
  419 + // 保留字段
  420 + entity.SalaryAttendance = 0;
  421 + }
  422 +
  423 + /// <summary>
  424 + /// 计算费用部分
  425 + /// </summary>
  426 + private async Task CalculateExpense(LqShareStatisticsStoreEntity entity, DateTime startDate, DateTime endDate, string statisticsMonth)
  427 + {
  428 + // 1. 门店房租 - 需要通过合同关联门店
  429 + // 从合同表关联租金明细
  430 + // 解析统计月份
  431 + var year = int.Parse(statisticsMonth.Substring(0, 4));
  432 + var month = int.Parse(statisticsMonth.Substring(4, 2));
  433 +
  434 + var rentDetail = await _db.Queryable<LqContractRentDetailEntity, NCC.Extend.Entitys.lq_contract.LqContractEntity>((rd, c) => new JoinQueryInfos(
  435 + JoinType.Inner, rd.ContractId == c.Id))
  436 + .Where((rd, c) => c.StoreId == entity.StoreId
  437 + && rd.PaymentMonth.Year == year
  438 + && rd.PaymentMonth.Month == month
  439 + && rd.IsEffective == 1)
  440 + .Select((rd, c) => rd.DueAmount)
  441 + .ToListAsync();
  442 +
  443 + entity.StoreRent = rentDetail.Sum();
  444 +
  445 + // 2. 当期费用 = 报销
  446 + // TODO: 需要根据报销分类来筛选门店相关费用
  447 + entity.CurrentPeriodExpense = 0;
  448 +
  449 + // 保留字段
  450 + entity.SocialSecurity = 0;
  451 + entity.DormRent = 0;
  452 + entity.CurrentPeriodExpenseQin = 0;
  453 + entity.FinancialFee = 0;
  454 + entity.RewardMedicalBeauty = 0;
  455 + entity.RewardOther = 0;
  456 + entity.RewardLargeOrder = 0;
  457 + entity.RewardFirstOrder = 0;
  458 + entity.RewardGeneral = 0;
  459 + entity.Other1 = 0;
  460 + entity.Other2 = 0;
  461 + }
  462 +
  463 + /// <summary>
  464 + /// 计算利润
  465 + /// </summary>
  466 + private void CalculateProfit(LqShareStatisticsStoreEntity entity)
  467 + {
  468 + // 人工工资汇总
  469 + var totalSalary = entity.SalaryBaseHealthCoach + entity.SalaryBaseAssistant + entity.SalaryBaseDirector
  470 + + entity.SalaryBaseStoreManager + entity.SalaryBaseGeneralManager
  471 + + entity.SalaryCommissionHealthCoach + entity.SalaryCommissionAssistant + entity.SalaryCommissionDirector
  472 + + entity.SalaryCommissionStoreManager + entity.SalaryCommissionGeneralManager
  473 + + entity.SalaryManual + entity.SalaryAttendance + entity.SalaryPhoneCustody
  474 + + entity.SalaryHeadcountReward + entity.SalaryTZone;
  475 +
  476 + // 主营成本汇总
  477 + var totalCost = entity.CostProduct + entity.CostFutian + entity.CostTowel + entity.CostTechDept
  478 + + entity.CostManagementFee + entity.CostCooperation + entity.CostMajorProject + entity.CostOther;
  479 +
  480 + // 费用汇总
  481 + var totalExpense = entity.SocialSecurity + entity.StoreRent + entity.DormRent + entity.CurrentPeriodExpense
  482 + + entity.CurrentPeriodExpenseQin + entity.FinancialFee;
  483 +
  484 + // 奖励汇总
  485 + var totalReward = entity.RewardMedicalBeauty + entity.RewardOther + entity.RewardLargeOrder
  486 + + entity.RewardFirstOrder + entity.RewardGeneral;
  487 +
  488 + // 其他汇总
  489 + var totalOther = entity.Other1 + entity.Other2;
  490 +
  491 + // 利润 = 预收 - 实退 - 主营成本 - 人工工资 - 房租 - 费用 - 奖励 - 其他
  492 + entity.Profit = entity.AdvanceReceipt - entity.Refund - totalCost - totalSalary - totalExpense - totalReward - totalOther;
  493 +
  494 + // 财务利润 = 主营收入 + 其他收入 - 主营成本 - 人工工资 - 房租 - 费用 - 奖励 - 其他
  495 + entity.FinancialProfit = entity.MainIncome + entity.OtherIncome - totalCost - totalSalary - totalExpense - totalReward - totalOther;
  496 + }
  497 +
  498 + #endregion
  499 + }
  500 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqShareStatisticsTechDeptService.cs 0 → 100644
  1 +using Microsoft.AspNetCore.Mvc;
  2 +using NCC.Common.Filter;
  3 +using NCC.Dependency;
  4 +using NCC.DynamicApiController;
  5 +using NCC.Extend.Entitys.Dto.LqShareStatisticsTechDept;
  6 +using NCC.Extend.Entitys.lq_share_statistics_tech_dept;
  7 +using NCC.Extend.Entitys.lq_mdxx;
  8 +using NCC.Extend.Entitys.lq_kd_pxmx;
  9 +using NCC.Extend.Entitys.lq_kd_kdjlb;
  10 +using NCC.Extend.Entitys.lq_hytk_jksyj;
  11 +using NCC.Extend.Entitys.lq_xh_jksyj;
  12 +using SqlSugar;
  13 +using System;
  14 +using System.Collections.Generic;
  15 +using System.Linq;
  16 +using System.Threading.Tasks;
  17 +using Yitter.IdGenerator;
  18 +
  19 +namespace NCC.Extend
  20 +{
  21 + /// <summary>
  22 + /// 科技部股份统计服务
  23 + /// </summary>
  24 + [ApiDescriptionSettings(Tag = "科技部股份统计服务", Name = "LqShareStatisticsTechDept", Order = 401)]
  25 + [Route("api/Extend/[controller]")]
  26 + public class LqShareStatisticsTechDeptService : IDynamicApiController, ITransient
  27 + {
  28 + private readonly ISqlSugarClient _db;
  29 +
  30 + public LqShareStatisticsTechDeptService(ISqlSugarClient db)
  31 + {
  32 + _db = db;
  33 + }
  34 +
  35 + /// <summary>
  36 + /// 生成科技部股份统计数据
  37 + /// </summary>
  38 + /// <param name="input">生成参数</param>
  39 + /// <returns>生成结果</returns>
  40 + [HttpPost("generate")]
  41 + public async Task<dynamic> GenerateStatistics([FromBody] ShareStatisticsTechDeptGenerateInput input)
  42 + {
  43 + if (string.IsNullOrEmpty(input.StatisticsMonth) || input.StatisticsMonth.Length != 6)
  44 + {
  45 + return new { code = 500, msg = "统计月份格式错误,应为 YYYYMM" };
  46 + }
  47 +
  48 + var year = int.Parse(input.StatisticsMonth.Substring(0, 4));
  49 + var month = int.Parse(input.StatisticsMonth.Substring(4, 2));
  50 + var startDate = new DateTime(year, month, 1);
  51 + var endDate = startDate.AddMonths(1).AddDays(-1);
  52 +
  53 + // 确定要生成的部门列表
  54 + var departments = new List<string>();
  55 + if (!string.IsNullOrEmpty(input.DepartmentName))
  56 + {
  57 + departments.Add(input.DepartmentName);
  58 + }
  59 + else
  60 + {
  61 + departments.Add("科技一部");
  62 + departments.Add("科技二部");
  63 + }
  64 +
  65 + var generatedCount = 0;
  66 + var updatedCount = 0;
  67 +
  68 + foreach (var deptName in departments)
  69 + {
  70 + // 检查是否已存在
  71 + var existing = await _db.Queryable<LqShareStatisticsTechDeptEntity>()
  72 + .FirstAsync(x => x.DepartmentName == deptName && x.StatisticsMonth == input.StatisticsMonth);
  73 +
  74 + var entity = existing ?? new LqShareStatisticsTechDeptEntity
  75 + {
  76 + Id = YitIdHelper.NextId().ToString(),
  77 + DepartmentName = deptName,
  78 + StatisticsMonth = input.StatisticsMonth,
  79 + IsEffective = 1,
  80 + CreateTime = DateTime.Now,
  81 + CreateUser = "System"
  82 + };
  83 +
  84 + // 计算各项数据
  85 + await CalculateIncome(entity, deptName, startDate, endDate);
  86 + await CalculateCost(entity, deptName, startDate, endDate, input.StatisticsMonth);
  87 + CalculateProfit(entity);
  88 +
  89 + entity.UpdateTime = DateTime.Now;
  90 + entity.UpdateUser = "System";
  91 +
  92 + if (existing == null)
  93 + {
  94 + await _db.Insertable(entity).ExecuteCommandAsync();
  95 + generatedCount++;
  96 + }
  97 + else
  98 + {
  99 + await _db.Updateable(entity).ExecuteCommandAsync();
  100 + updatedCount++;
  101 + }
  102 + }
  103 +
  104 + return new
  105 + {
  106 + code = 200,
  107 + msg = "生成成功",
  108 + data = new
  109 + {
  110 + generatedCount,
  111 + updatedCount,
  112 + totalCount = departments.Count
  113 + }
  114 + };
  115 + }
  116 +
  117 + /// <summary>
  118 + /// 查询科技部股份统计列表
  119 + /// </summary>
  120 + /// <param name="input">查询参数</param>
  121 + /// <returns>统计列表</returns>
  122 + [HttpGet("list")]
  123 + public async Task<dynamic> GetList([FromQuery] ShareStatisticsTechDeptQueryInput input)
  124 + {
  125 + var query = _db.Queryable<LqShareStatisticsTechDeptEntity>()
  126 + .Where(x => x.IsEffective == 1);
  127 +
  128 + if (!string.IsNullOrEmpty(input.StatisticsMonth))
  129 + {
  130 + query = query.Where(x => x.StatisticsMonth == input.StatisticsMonth);
  131 + }
  132 +
  133 + if (!string.IsNullOrEmpty(input.DepartmentName))
  134 + {
  135 + query = query.Where(x => x.DepartmentName == input.DepartmentName);
  136 + }
  137 +
  138 + var list = await query.OrderBy(x => x.StatisticsMonth, OrderByType.Desc)
  139 + .OrderBy(x => x.DepartmentName)
  140 + .Select(x => new ShareStatisticsTechDeptOutput
  141 + {
  142 + Id = x.Id,
  143 + DepartmentName = x.DepartmentName,
  144 + StatisticsMonth = x.StatisticsMonth,
  145 + Income = x.Income,
  146 + CostReimbursement = x.CostReimbursement,
  147 + CostTeacherBase = x.CostTeacherBase,
  148 + CostTeacherManual = x.CostTeacherManual,
  149 + CostTeacherBillingComm = x.CostTeacherBillingComm,
  150 + CostTeacherConsumeComm = x.CostTeacherConsumeComm,
  151 + CostTeacherExpertComm = x.CostTeacherExpertComm,
  152 + CostTeacherOvertime = x.CostTeacherOvertime,
  153 + CostGMBase = x.CostGMBase,
  154 + CostGMComm = x.CostGMComm,
  155 + RewardTechDept = x.RewardTechDept,
  156 + CostOther1 = x.CostOther1,
  157 + CostOther2 = x.CostOther2,
  158 + Profit = x.Profit,
  159 + CreateTime = x.CreateTime,
  160 + UpdateTime = x.UpdateTime
  161 + })
  162 + .ToListAsync();
  163 +
  164 + return new { code = 200, msg = "查询成功", data = list };
  165 + }
  166 +
  167 + #region 私有计算方法
  168 +
  169 + /// <summary>
  170 + /// 计算收入部分
  171 + /// </summary>
  172 + private async Task CalculateIncome(LqShareStatisticsTechDeptEntity entity, string deptName, DateTime startDate, DateTime endDate)
  173 + {
  174 + // 1. 找到该科技部管辖的所有门店
  175 + var stores = await _db.Queryable<LqMdxxEntity>()
  176 + .Where(x => x.Kjb == deptName)
  177 + .Select(x => x.Id)
  178 + .ToListAsync();
  179 +
  180 + if (stores.Count == 0)
  181 + {
  182 + entity.Income = 0;
  183 + return;
  184 + }
  185 +
  186 + // 2. 统计这些门店的科美项目开单实付业绩
  187 + // 需要关联 lq_kd_kdjlb 来获取门店信息
  188 + var kemeiIncome = await _db.Queryable<LqKdPxmxEntity, LqKdKdjlbEntity>((px, kd) => new JoinQueryInfos(
  189 + JoinType.Inner, px.Glkdbh == kd.Id))
  190 + .Where((px, kd) => stores.Contains(kd.Djmd) && px.Yjsj >= startDate && px.Yjsj <= endDate && px.IsEffective == 1)
  191 + .Where((px, kd) => px.ItemCategory == "科美")
  192 + .SumAsync((px, kd) => px.TotalPrice);
  193 +
  194 + // 3. 减去对应的科美项目实退金额
  195 + var kemeiRefund = await _db.Queryable<LqHytkJksyjEntity>()
  196 + .Where(x => stores.Contains(x.StoreId) && x.Tksj >= startDate && x.Tksj <= endDate && x.IsEffective == 1)
  197 + .Where(x => x.ItemCategory == "科美")
  198 + .SumAsync(x => x.Jksyj ?? 0);
  199 +
  200 + // 4. 结果 * 30%
  201 + entity.Income = (kemeiIncome - kemeiRefund) * 0.3m;
  202 + }
  203 +
  204 + /// <summary>
  205 + /// 计算成本部分
  206 + /// </summary>
  207 + private async Task CalculateCost(LqShareStatisticsTechDeptEntity entity, string deptName, DateTime startDate, DateTime endDate, string statisticsMonth)
  208 + {
  209 + // 1. 成本-报销 (TODO: 需要确认报销分类的具体判定方式)
  210 + entity.CostReimbursement = 0;
  211 +
  212 + // 2. 成本-人工-科技部老师底薪 (TODO: 需要确认科技部老师工资表名和字段)
  213 + entity.CostTeacherBase = 0;
  214 +
  215 + // 3. 成本-人工-科技部手工费
  216 + // 从消耗表中统计科技部老师的手工费
  217 + // TODO: 需要确认如何识别科技部老师
  218 + entity.CostTeacherManual = 0;
  219 +
  220 + // 4. 成本-人工-科技部开单提成 (TODO: 需要确认字段名)
  221 + entity.CostTeacherBillingComm = 0;
  222 +
  223 + // 5. 成本-人工-科技部消耗提成 (TODO: 需要确认字段名)
  224 + entity.CostTeacherConsumeComm = 0;
  225 +
  226 + // 6. 成本-人工-科技部总经理 (TODO: 需要确认科技部总经理工资表)
  227 + entity.CostGMBase = 0;
  228 + entity.CostGMComm = 0;
  229 +
  230 + // 保留字段
  231 + entity.CostTeacherExpertComm = 0;
  232 + entity.CostTeacherOvertime = 0;
  233 + entity.RewardTechDept = 0;
  234 + entity.CostOther1 = 0;
  235 + entity.CostOther2 = 0;
  236 + }
  237 +
  238 + /// <summary>
  239 + /// 计算利润
  240 + /// </summary>
  241 + private void CalculateProfit(LqShareStatisticsTechDeptEntity entity)
  242 + {
  243 + // 科技部利润 = 收入 - 成本报销 - 成本人工 - 其他
  244 + var totalCost = entity.CostReimbursement
  245 + + entity.CostTeacherBase
  246 + + entity.CostTeacherManual
  247 + + entity.CostTeacherBillingComm
  248 + + entity.CostTeacherConsumeComm
  249 + + entity.CostTeacherExpertComm
  250 + + entity.CostTeacherOvertime
  251 + + entity.CostGMBase
  252 + + entity.CostGMComm
  253 + + entity.RewardTechDept
  254 + + entity.CostOther1
  255 + + entity.CostOther2;
  256 +
  257 + entity.Profit = entity.Income - totalCost;
  258 + }
  259 +
  260 + #endregion
  261 + }
  262 +}
... ...
sql/排查生美业绩统计差异-简化版.sql
... ... @@ -116,3 +116,6 @@ ORDER BY 生美业绩 DESC;
116 116  
117 117  
118 118  
  119 +
  120 +
  121 +
... ...
sql/排查生美业绩统计差异详细.sql
... ... @@ -168,3 +168,6 @@ HAVING COUNT(*) &gt; 1;
168 168  
169 169  
170 170  
  171 +
  172 +
  173 +
... ...
sql/检查生美业绩统计差异.sql
... ... @@ -138,3 +138,6 @@ ORDER BY 生美业绩 DESC;
138 138  
139 139  
140 140  
  141 +
  142 +
  143 +
... ...
test_tianwang_api.py
... ... @@ -71,3 +71,6 @@ total2 = sum([d.get(&#39;BillingPerformance&#39;, 0) for d in depts2])
71 71 print(f"\n教育一部+教育二部合计 BillingPerformance: {total2}")
72 72  
73 73  
  74 +
  75 +
  76 +
... ...