Commit ddcc459b5fd6a37683fabaa8b5b96a672f5f9777
1 parent
6f996def
修改大项目部老师归属设置表:将月份字段拆分为年份和月份两个字段,便于后续统计
Showing
17 changed files
with
2847 additions
and
0 deletions
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentCrInput.cs
0 → 100644
| 1 | +using System.ComponentModel.DataAnnotations; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 门店大项目部老师归属设置创建输入 | |
| 7 | + /// </summary> | |
| 8 | + public class LqMdMajorProjectTeacherAssignmentCrInput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 门店ID | |
| 12 | + /// </summary> | |
| 13 | + [Required(ErrorMessage = "门店ID不能为空")] | |
| 14 | + public string storeId { get; set; } | |
| 15 | + | |
| 16 | + /// <summary> | |
| 17 | + /// 年份(YYYY格式) | |
| 18 | + /// </summary> | |
| 19 | + [Required(ErrorMessage = "年份不能为空")] | |
| 20 | + [StringLength(4, MinimumLength = 4, ErrorMessage = "年份格式必须为YYYY")] | |
| 21 | + public string year { get; set; } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 月份(MM格式) | |
| 25 | + /// </summary> | |
| 26 | + [Required(ErrorMessage = "月份不能为空")] | |
| 27 | + [StringLength(2, MinimumLength = 2, ErrorMessage = "月份格式必须为MM")] | |
| 28 | + public string month { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 大项目部老师用户ID | |
| 32 | + /// </summary> | |
| 33 | + [Required(ErrorMessage = "大项目部老师用户ID不能为空")] | |
| 34 | + public string teacherId { get; set; } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 备注说明 | |
| 38 | + /// </summary> | |
| 39 | + public string remark { get; set; } | |
| 40 | + } | |
| 41 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentInfoOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 门店大项目部老师归属设置信息输出 | |
| 7 | + /// </summary> | |
| 8 | + public class LqMdMajorProjectTeacherAssignmentInfoOutput | |
| 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 | + /// 年份(YYYY格式) | |
| 27 | + /// </summary> | |
| 28 | + public string year { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 月份(MM格式) | |
| 32 | + /// </summary> | |
| 33 | + public string month { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 大项目部老师用户ID | |
| 37 | + /// </summary> | |
| 38 | + public string teacherId { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 大项目部老师姓名 | |
| 42 | + /// </summary> | |
| 43 | + public string teacherName { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 备注说明 | |
| 47 | + /// </summary> | |
| 48 | + public string remark { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 创建时间 | |
| 52 | + /// </summary> | |
| 53 | + public DateTime? createTime { get; set; } | |
| 54 | + | |
| 55 | + /// <summary> | |
| 56 | + /// 创建人ID | |
| 57 | + /// </summary> | |
| 58 | + public string createUserId { get; set; } | |
| 59 | + | |
| 60 | + /// <summary> | |
| 61 | + /// 更新时间 | |
| 62 | + /// </summary> | |
| 63 | + public DateTime? updateTime { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 更新人ID | |
| 67 | + /// </summary> | |
| 68 | + public string updateUserId { get; set; } | |
| 69 | + } | |
| 70 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 门店大项目部老师归属设置列表输出 | |
| 7 | + /// </summary> | |
| 8 | + public class LqMdMajorProjectTeacherAssignmentListOutput | |
| 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 | + /// 年份(YYYY格式) | |
| 27 | + /// </summary> | |
| 28 | + public string year { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 月份(MM格式) | |
| 32 | + /// </summary> | |
| 33 | + public string month { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 大项目部老师用户ID | |
| 37 | + /// </summary> | |
| 38 | + public string teacherId { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 大项目部老师姓名 | |
| 42 | + /// </summary> | |
| 43 | + public string teacherName { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 备注说明 | |
| 47 | + /// </summary> | |
| 48 | + public string remark { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 创建时间 | |
| 52 | + /// </summary> | |
| 53 | + public DateTime? createTime { get; set; } | |
| 54 | + | |
| 55 | + /// <summary> | |
| 56 | + /// 创建人ID | |
| 57 | + /// </summary> | |
| 58 | + public string createUserId { get; set; } | |
| 59 | + | |
| 60 | + /// <summary> | |
| 61 | + /// 更新时间 | |
| 62 | + /// </summary> | |
| 63 | + public DateTime? updateTime { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 更新人ID | |
| 67 | + /// </summary> | |
| 68 | + public string updateUserId { get; set; } | |
| 69 | + } | |
| 70 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentListQueryInput.cs
0 → 100644
| 1 | +using NCC.Common.Filter; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 门店大项目部老师归属设置列表查询输入 | |
| 7 | + /// </summary> | |
| 8 | + public class LqMdMajorProjectTeacherAssignmentListQueryInput : PageInputBase | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 门店ID | |
| 12 | + /// </summary> | |
| 13 | + public string storeId { get; set; } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 年份(YYYY格式) | |
| 17 | + /// </summary> | |
| 18 | + public string year { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 月份(MM格式) | |
| 22 | + /// </summary> | |
| 23 | + public string month { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 大项目部老师用户ID | |
| 27 | + /// </summary> | |
| 28 | + public string teacherId { get; set; } | |
| 29 | + } | |
| 30 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqMdMajorProjectTeacherAssignment/LqMdMajorProjectTeacherAssignmentUpInput.cs
0 → 100644
| 1 | +using System.ComponentModel.DataAnnotations; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 门店大项目部老师归属设置更新输入 | |
| 7 | + /// </summary> | |
| 8 | + public class LqMdMajorProjectTeacherAssignmentUpInput | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 主键ID | |
| 12 | + /// </summary> | |
| 13 | + [Required(ErrorMessage = "主键ID不能为空")] | |
| 14 | + public string id { get; set; } | |
| 15 | + | |
| 16 | + /// <summary> | |
| 17 | + /// 门店ID | |
| 18 | + /// </summary> | |
| 19 | + [Required(ErrorMessage = "门店ID不能为空")] | |
| 20 | + public string storeId { get; set; } | |
| 21 | + | |
| 22 | + /// <summary> | |
| 23 | + /// 年份(YYYY格式) | |
| 24 | + /// </summary> | |
| 25 | + [Required(ErrorMessage = "年份不能为空")] | |
| 26 | + [StringLength(4, MinimumLength = 4, ErrorMessage = "年份格式必须为YYYY")] | |
| 27 | + public string year { get; set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 月份(MM格式) | |
| 31 | + /// </summary> | |
| 32 | + [Required(ErrorMessage = "月份不能为空")] | |
| 33 | + [StringLength(2, MinimumLength = 2, ErrorMessage = "月份格式必须为MM")] | |
| 34 | + public string month { get; set; } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 大项目部老师用户ID | |
| 38 | + /// </summary> | |
| 39 | + [Required(ErrorMessage = "大项目部老师用户ID不能为空")] | |
| 40 | + public string teacherId { get; set; } | |
| 41 | + | |
| 42 | + /// <summary> | |
| 43 | + /// 备注说明 | |
| 44 | + /// </summary> | |
| 45 | + public string remark { get; set; } | |
| 46 | + } | |
| 47 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTechTeacherSalary/TechTeacherSalaryInput.cs
0 → 100644
| 1 | +using NCC.Common.Filter; | |
| 2 | +using System; | |
| 3 | + | |
| 4 | +namespace NCC.Extend.Entitys.Dto.LqTechTeacherSalary | |
| 5 | +{ | |
| 6 | + /// <summary> | |
| 7 | + /// 科技老师工资查询参数 | |
| 8 | + /// </summary> | |
| 9 | + public class TechTeacherSalaryInput : PageInputBase | |
| 10 | + { | |
| 11 | + /// <summary> | |
| 12 | + /// 年份 | |
| 13 | + /// </summary> | |
| 14 | + public int Year { get; set; } | |
| 15 | + | |
| 16 | + /// <summary> | |
| 17 | + /// 月份 | |
| 18 | + /// </summary> | |
| 19 | + public int Month { get; set; } | |
| 20 | + | |
| 21 | + /// <summary> | |
| 22 | + /// 门店ID(可选,用于筛选特定门店) | |
| 23 | + /// </summary> | |
| 24 | + public string StoreId { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 员工姓名/账号(可选,用于模糊搜索) | |
| 28 | + /// </summary> | |
| 29 | + public string Keyword { get; set; } | |
| 30 | + } | |
| 31 | +} | |
| 32 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTechTeacherSalary/TechTeacherSalaryOutput.cs
0 → 100644
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqTechTeacherSalary | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 科技老师工资输出 | |
| 7 | + /// </summary> | |
| 8 | + public class TechTeacherSalaryOutput | |
| 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 | + /// 门店ID | |
| 22 | + /// </summary> | |
| 23 | + public string StoreId { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 门店名称 | |
| 27 | + /// </summary> | |
| 28 | + public string StoreName { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 核算岗位 | |
| 32 | + /// </summary> | |
| 33 | + public string Position { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 员工姓名 | |
| 37 | + /// </summary> | |
| 38 | + public string EmployeeName { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 员工ID | |
| 42 | + /// </summary> | |
| 43 | + public string EmployeeId { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 员工账号 | |
| 47 | + /// </summary> | |
| 48 | + public string EmployeeAccount { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 开单业绩 | |
| 52 | + /// </summary> | |
| 53 | + public decimal OrderAchievement { get; set; } | |
| 54 | + | |
| 55 | + /// <summary> | |
| 56 | + /// 消耗业绩 | |
| 57 | + /// </summary> | |
| 58 | + public decimal ConsumeAchievement { get; set; } | |
| 59 | + | |
| 60 | + /// <summary> | |
| 61 | + /// 退卡业绩 | |
| 62 | + /// </summary> | |
| 63 | + public decimal RefundAchievement { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 总业绩 | |
| 67 | + /// </summary> | |
| 68 | + public decimal TotalPerformance { get; set; } | |
| 69 | + | |
| 70 | + /// <summary> | |
| 71 | + /// 项目数 | |
| 72 | + /// </summary> | |
| 73 | + public decimal ProjectCount { get; set; } | |
| 74 | + | |
| 75 | + /// <summary> | |
| 76 | + /// 底薪档位 | |
| 77 | + /// </summary> | |
| 78 | + public int BaseSalaryLevel { get; set; } | |
| 79 | + | |
| 80 | + /// <summary> | |
| 81 | + /// 底薪 | |
| 82 | + /// </summary> | |
| 83 | + public decimal BaseSalary { get; set; } | |
| 84 | + | |
| 85 | + /// <summary> | |
| 86 | + /// 业绩提成比例 | |
| 87 | + /// </summary> | |
| 88 | + public decimal PerformanceCommissionRate { get; set; } | |
| 89 | + | |
| 90 | + /// <summary> | |
| 91 | + /// 业绩提成金额 | |
| 92 | + /// </summary> | |
| 93 | + public decimal PerformanceCommissionAmount { get; set; } | |
| 94 | + | |
| 95 | + /// <summary> | |
| 96 | + /// 消耗提成比例 | |
| 97 | + /// </summary> | |
| 98 | + public decimal ConsumeCommissionRate { get; set; } | |
| 99 | + | |
| 100 | + /// <summary> | |
| 101 | + /// 消耗提成金额 | |
| 102 | + /// </summary> | |
| 103 | + public decimal ConsumeCommissionAmount { get; set; } | |
| 104 | + | |
| 105 | + /// <summary> | |
| 106 | + /// 手工费 | |
| 107 | + /// </summary> | |
| 108 | + public decimal HandworkFee { get; set; } | |
| 109 | + | |
| 110 | + /// <summary> | |
| 111 | + /// 在店天数 | |
| 112 | + /// </summary> | |
| 113 | + public decimal WorkingDays { get; set; } | |
| 114 | + | |
| 115 | + /// <summary> | |
| 116 | + /// 请假天数 | |
| 117 | + /// </summary> | |
| 118 | + public decimal LeaveDays { get; set; } | |
| 119 | + | |
| 120 | + /// <summary> | |
| 121 | + /// 提成合计 | |
| 122 | + /// </summary> | |
| 123 | + public decimal TotalCommission { get; set; } | |
| 124 | + | |
| 125 | + /// <summary> | |
| 126 | + /// 车补 | |
| 127 | + /// </summary> | |
| 128 | + public decimal TransportationAllowance { get; set; } | |
| 129 | + | |
| 130 | + /// <summary> | |
| 131 | + /// 少休费 | |
| 132 | + /// </summary> | |
| 133 | + public decimal LessRest { get; set; } | |
| 134 | + | |
| 135 | + /// <summary> | |
| 136 | + /// 全勤奖 | |
| 137 | + /// </summary> | |
| 138 | + public decimal FullAttendance { get; set; } | |
| 139 | + | |
| 140 | + /// <summary> | |
| 141 | + /// 核算应发工资 | |
| 142 | + /// </summary> | |
| 143 | + public decimal CalculatedGrossSalary { get; set; } | |
| 144 | + | |
| 145 | + /// <summary> | |
| 146 | + /// 保底工资 | |
| 147 | + /// </summary> | |
| 148 | + public decimal GuaranteedSalary { get; set; } | |
| 149 | + | |
| 150 | + /// <summary> | |
| 151 | + /// 保底请假扣款 | |
| 152 | + /// </summary> | |
| 153 | + public decimal GuaranteedLeaveDeduction { get; set; } | |
| 154 | + | |
| 155 | + /// <summary> | |
| 156 | + /// 保底底薪 | |
| 157 | + /// </summary> | |
| 158 | + public decimal GuaranteedBaseSalary { get; set; } | |
| 159 | + | |
| 160 | + /// <summary> | |
| 161 | + /// 保底补差 | |
| 162 | + /// </summary> | |
| 163 | + public decimal GuaranteedSupplement { get; set; } | |
| 164 | + | |
| 165 | + /// <summary> | |
| 166 | + /// 最终应发工资 | |
| 167 | + /// </summary> | |
| 168 | + public decimal FinalGrossSalary { get; set; } | |
| 169 | + | |
| 170 | + /// <summary> | |
| 171 | + /// 当月培训补贴 | |
| 172 | + /// </summary> | |
| 173 | + public decimal MonthlyTrainingSubsidy { get; set; } | |
| 174 | + | |
| 175 | + /// <summary> | |
| 176 | + /// 当月交通补贴 | |
| 177 | + /// </summary> | |
| 178 | + public decimal MonthlyTransportSubsidy { get; set; } | |
| 179 | + | |
| 180 | + /// <summary> | |
| 181 | + /// 上月培训补贴 | |
| 182 | + /// </summary> | |
| 183 | + public decimal LastMonthTrainingSubsidy { get; set; } | |
| 184 | + | |
| 185 | + /// <summary> | |
| 186 | + /// 上月交通补贴 | |
| 187 | + /// </summary> | |
| 188 | + public decimal LastMonthTransportSubsidy { get; set; } | |
| 189 | + | |
| 190 | + /// <summary> | |
| 191 | + /// 补贴合计 | |
| 192 | + /// </summary> | |
| 193 | + public decimal TotalSubsidy { get; set; } | |
| 194 | + | |
| 195 | + /// <summary> | |
| 196 | + /// 缺卡扣款 | |
| 197 | + /// </summary> | |
| 198 | + public decimal MissingCard { get; set; } | |
| 199 | + | |
| 200 | + /// <summary> | |
| 201 | + /// 迟到扣款 | |
| 202 | + /// </summary> | |
| 203 | + public decimal LateArrival { get; set; } | |
| 204 | + | |
| 205 | + /// <summary> | |
| 206 | + /// 请假扣款 | |
| 207 | + /// </summary> | |
| 208 | + public decimal LeaveDeduction { get; set; } | |
| 209 | + | |
| 210 | + /// <summary> | |
| 211 | + /// 扣社保 | |
| 212 | + /// </summary> | |
| 213 | + public decimal SocialInsuranceDeduction { get; set; } | |
| 214 | + | |
| 215 | + /// <summary> | |
| 216 | + /// 扣除奖励 | |
| 217 | + /// </summary> | |
| 218 | + public decimal RewardDeduction { get; set; } | |
| 219 | + | |
| 220 | + /// <summary> | |
| 221 | + /// 扣住宿费 | |
| 222 | + /// </summary> | |
| 223 | + public decimal AccommodationDeduction { get; set; } | |
| 224 | + | |
| 225 | + /// <summary> | |
| 226 | + /// 扣学习期费用 | |
| 227 | + /// </summary> | |
| 228 | + public decimal StudyPeriodDeduction { get; set; } | |
| 229 | + | |
| 230 | + /// <summary> | |
| 231 | + /// 扣工作服费用 | |
| 232 | + /// </summary> | |
| 233 | + public decimal WorkClothesDeduction { get; set; } | |
| 234 | + | |
| 235 | + /// <summary> | |
| 236 | + /// 扣款合计 | |
| 237 | + /// </summary> | |
| 238 | + public decimal TotalDeduction { get; set; } | |
| 239 | + | |
| 240 | + /// <summary> | |
| 241 | + /// 发奖金 | |
| 242 | + /// </summary> | |
| 243 | + public decimal Bonus { get; set; } | |
| 244 | + | |
| 245 | + /// <summary> | |
| 246 | + /// 退手机押金 | |
| 247 | + /// </summary> | |
| 248 | + public decimal ReturnPhoneDeposit { get; set; } | |
| 249 | + | |
| 250 | + /// <summary> | |
| 251 | + /// 退住宿押金 | |
| 252 | + /// </summary> | |
| 253 | + public decimal ReturnAccommodationDeposit { get; set; } | |
| 254 | + | |
| 255 | + /// <summary> | |
| 256 | + /// 实发工资 | |
| 257 | + /// </summary> | |
| 258 | + public decimal ActualSalary { get; set; } | |
| 259 | + | |
| 260 | + /// <summary> | |
| 261 | + /// 当月是否发放 | |
| 262 | + /// </summary> | |
| 263 | + public string MonthlyPaymentStatus { get; set; } | |
| 264 | + | |
| 265 | + /// <summary> | |
| 266 | + /// 支付金额 | |
| 267 | + /// </summary> | |
| 268 | + public decimal PaidAmount { get; set; } | |
| 269 | + | |
| 270 | + /// <summary> | |
| 271 | + /// 待支付金额 | |
| 272 | + /// </summary> | |
| 273 | + public decimal PendingAmount { get; set; } | |
| 274 | + | |
| 275 | + /// <summary> | |
| 276 | + /// 补发上月 | |
| 277 | + /// </summary> | |
| 278 | + public decimal LastMonthSupplement { get; set; } | |
| 279 | + | |
| 280 | + /// <summary> | |
| 281 | + /// 当月支付总额 | |
| 282 | + /// </summary> | |
| 283 | + public decimal MonthlyTotalPayment { get; set; } | |
| 284 | + | |
| 285 | + /// <summary> | |
| 286 | + /// 是否锁定 | |
| 287 | + /// </summary> | |
| 288 | + public int IsLocked { get; set; } | |
| 289 | + | |
| 290 | + /// <summary> | |
| 291 | + /// 是否离职 | |
| 292 | + /// </summary> | |
| 293 | + public int IsTerminated { get; set; } | |
| 294 | + | |
| 295 | + /// <summary> | |
| 296 | + /// 更新时间 | |
| 297 | + /// </summary> | |
| 298 | + public DateTime UpdateTime { get; set; } | |
| 299 | + | |
| 300 | + /// <summary> | |
| 301 | + /// 门店类型 | |
| 302 | + /// </summary> | |
| 303 | + public int? StoreType { get; set; } | |
| 304 | + | |
| 305 | + /// <summary> | |
| 306 | + /// 门店类别 | |
| 307 | + /// </summary> | |
| 308 | + public int? StoreCategory { get; set; } | |
| 309 | + | |
| 310 | + /// <summary> | |
| 311 | + /// 是否新店 | |
| 312 | + /// </summary> | |
| 313 | + public string IsNewStore { get; set; } | |
| 314 | + | |
| 315 | + /// <summary> | |
| 316 | + /// 新店保护阶段 | |
| 317 | + /// </summary> | |
| 318 | + public int NewStoreProtectionStage { get; set; } | |
| 319 | + } | |
| 320 | +} | |
| 321 | + | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_md_major_project_teacher_assignment/LqMdMajorProjectTeacherAssignmentEntity.cs
0 → 100644
| 1 | +using NCC.Common.Const; | |
| 2 | +using SqlSugar; | |
| 3 | +using System; | |
| 4 | + | |
| 5 | +namespace NCC.Extend.Entitys.lq_md_major_project_teacher_assignment | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 门店大项目部老师归属设置 | |
| 9 | + /// </summary> | |
| 10 | + [SugarTable("lq_md_major_project_teacher_assignment")] | |
| 11 | + [Tenant(ClaimConst.TENANT_ID)] | |
| 12 | + public class LqMdMajorProjectTeacherAssignmentEntity | |
| 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 | + /// 年份(YYYY格式) | |
| 28 | + /// </summary> | |
| 29 | + [SugarColumn(ColumnName = "F_Year")] | |
| 30 | + public string Year { get; set; } | |
| 31 | + | |
| 32 | + /// <summary> | |
| 33 | + /// 月份(MM格式) | |
| 34 | + /// </summary> | |
| 35 | + [SugarColumn(ColumnName = "F_Month")] | |
| 36 | + public string Month { get; set; } | |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 大项目部老师用户ID | |
| 40 | + /// </summary> | |
| 41 | + [SugarColumn(ColumnName = "F_TeacherId")] | |
| 42 | + public string TeacherId { get; set; } | |
| 43 | + | |
| 44 | + /// <summary> | |
| 45 | + /// 备注说明 | |
| 46 | + /// </summary> | |
| 47 | + [SugarColumn(ColumnName = "F_Remark")] | |
| 48 | + public string Remark { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 创建时间 | |
| 52 | + /// </summary> | |
| 53 | + [SugarColumn(ColumnName = "F_CreateTime")] | |
| 54 | + public DateTime? CreateTime { get; set; } | |
| 55 | + | |
| 56 | + /// <summary> | |
| 57 | + /// 创建人ID | |
| 58 | + /// </summary> | |
| 59 | + [SugarColumn(ColumnName = "F_CreateUserId")] | |
| 60 | + public string CreateUserId { get; set; } | |
| 61 | + | |
| 62 | + /// <summary> | |
| 63 | + /// 更新时间 | |
| 64 | + /// </summary> | |
| 65 | + [SugarColumn(ColumnName = "F_UpdateTime")] | |
| 66 | + public DateTime? UpdateTime { get; set; } | |
| 67 | + | |
| 68 | + /// <summary> | |
| 69 | + /// 更新人ID | |
| 70 | + /// </summary> | |
| 71 | + [SugarColumn(ColumnName = "F_UpdateUserId")] | |
| 72 | + public string UpdateUserId { get; set; } | |
| 73 | + } | |
| 74 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_tech_teacher_salary_statistics/LqTechTeacherSalaryStatisticsEntity.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using NCC.Common.Const; | |
| 3 | +using SqlSugar; | |
| 4 | + | |
| 5 | +namespace NCC.Extend.Entitys.lq_tech_teacher_salary_statistics | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 科技部老师工资统计表 | |
| 9 | + /// </summary> | |
| 10 | + [SugarTable("lq_tech_teacher_salary_statistics")] | |
| 11 | + [Tenant(ClaimConst.TENANT_ID)] | |
| 12 | + public class LqTechTeacherSalaryStatisticsEntity | |
| 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", Length = 6)] | |
| 24 | + public string StatisticsMonth { get; set; } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 门店ID | |
| 28 | + /// </summary> | |
| 29 | + [SugarColumn(ColumnName = "F_StoreId")] | |
| 30 | + public string StoreId { get; set; } | |
| 31 | + | |
| 32 | + /// <summary> | |
| 33 | + /// 门店名称 | |
| 34 | + /// </summary> | |
| 35 | + [SugarColumn(ColumnName = "F_StoreName")] | |
| 36 | + public string StoreName { get; set; } | |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 核算岗位 | |
| 40 | + /// </summary> | |
| 41 | + [SugarColumn(ColumnName = "F_Position")] | |
| 42 | + public string Position { get; set; } | |
| 43 | + | |
| 44 | + /// <summary> | |
| 45 | + /// 员工姓名 | |
| 46 | + /// </summary> | |
| 47 | + [SugarColumn(ColumnName = "F_EmployeeName")] | |
| 48 | + public string EmployeeName { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 员工ID | |
| 52 | + /// </summary> | |
| 53 | + [SugarColumn(ColumnName = "F_EmployeeId")] | |
| 54 | + public string EmployeeId { get; set; } | |
| 55 | + | |
| 56 | + /// <summary> | |
| 57 | + /// 员工账号 | |
| 58 | + /// </summary> | |
| 59 | + [SugarColumn(ColumnName = "F_EmployeeAccount")] | |
| 60 | + public string EmployeeAccount { get; set; } | |
| 61 | + | |
| 62 | + /// <summary> | |
| 63 | + /// 开单业绩 | |
| 64 | + /// </summary> | |
| 65 | + [SugarColumn(ColumnName = "F_OrderAchievement", DecimalDigits = 2)] | |
| 66 | + public decimal OrderAchievement { get; set; } | |
| 67 | + | |
| 68 | + /// <summary> | |
| 69 | + /// 消耗业绩(对应规则中的"消耗") | |
| 70 | + /// </summary> | |
| 71 | + [SugarColumn(ColumnName = "F_ConsumeAchievement", DecimalDigits = 2)] | |
| 72 | + public decimal ConsumeAchievement { get; set; } | |
| 73 | + | |
| 74 | + /// <summary> | |
| 75 | + /// 退卡业绩 | |
| 76 | + /// </summary> | |
| 77 | + [SugarColumn(ColumnName = "F_RefundAchievement", DecimalDigits = 2)] | |
| 78 | + public decimal RefundAchievement { get; set; } | |
| 79 | + | |
| 80 | + /// <summary> | |
| 81 | + /// 总业绩(开单业绩 + 消耗业绩 + 退卡业绩) | |
| 82 | + /// </summary> | |
| 83 | + [SugarColumn(ColumnName = "F_TotalPerformance", DecimalDigits = 2)] | |
| 84 | + public decimal TotalPerformance { get; set; } | |
| 85 | + | |
| 86 | + /// <summary> | |
| 87 | + /// 项目数(用于底薪计算,主要来源于耗卡品相次数) | |
| 88 | + /// </summary> | |
| 89 | + [SugarColumn(ColumnName = "F_ProjectCount", DecimalDigits = 2)] | |
| 90 | + public decimal ProjectCount { get; set; } | |
| 91 | + | |
| 92 | + /// <summary> | |
| 93 | + /// 底薪档位(1=第一档2500, 2=第二档3000, 3=第三档3500) | |
| 94 | + /// </summary> | |
| 95 | + [SugarColumn(ColumnName = "F_BaseSalaryLevel")] | |
| 96 | + public int BaseSalaryLevel { get; set; } | |
| 97 | + | |
| 98 | + /// <summary> | |
| 99 | + /// 健康师底薪(根据项目数和业绩计算) | |
| 100 | + /// </summary> | |
| 101 | + [SugarColumn(ColumnName = "F_BaseSalary", DecimalDigits = 2)] | |
| 102 | + public decimal BaseSalary { get; set; } | |
| 103 | + | |
| 104 | + /// <summary> | |
| 105 | + /// 业绩提成比例(百分比,如2表示2%) | |
| 106 | + /// </summary> | |
| 107 | + [SugarColumn(ColumnName = "F_PerformanceCommissionRate", DecimalDigits = 2)] | |
| 108 | + public decimal PerformanceCommissionRate { get; set; } | |
| 109 | + | |
| 110 | + /// <summary> | |
| 111 | + /// 业绩提成金额 | |
| 112 | + /// </summary> | |
| 113 | + [SugarColumn(ColumnName = "F_PerformanceCommissionAmount", DecimalDigits = 2)] | |
| 114 | + public decimal PerformanceCommissionAmount { get; set; } | |
| 115 | + | |
| 116 | + /// <summary> | |
| 117 | + /// 消耗提成比例(百分比,如0.5表示0.5%,负数表示扣除,如-300表示扣除300元) | |
| 118 | + /// </summary> | |
| 119 | + [SugarColumn(ColumnName = "F_ConsumeCommissionRate", DecimalDigits = 2)] | |
| 120 | + public decimal ConsumeCommissionRate { get; set; } | |
| 121 | + | |
| 122 | + /// <summary> | |
| 123 | + /// 消耗提成金额(可能为负数,如扣除300元) | |
| 124 | + /// </summary> | |
| 125 | + [SugarColumn(ColumnName = "F_ConsumeCommissionAmount", DecimalDigits = 2)] | |
| 126 | + public decimal ConsumeCommissionAmount { get; set; } | |
| 127 | + | |
| 128 | + /// <summary> | |
| 129 | + /// 手工费 | |
| 130 | + /// </summary> | |
| 131 | + [SugarColumn(ColumnName = "F_HandworkFee", DecimalDigits = 2)] | |
| 132 | + public decimal HandworkFee { get; set; } | |
| 133 | + | |
| 134 | + /// <summary> | |
| 135 | + /// 在店天数 | |
| 136 | + /// </summary> | |
| 137 | + [SugarColumn(ColumnName = "F_WorkingDays", DecimalDigits = 2)] | |
| 138 | + public decimal WorkingDays { get; set; } | |
| 139 | + | |
| 140 | + /// <summary> | |
| 141 | + /// 请假天数 | |
| 142 | + /// </summary> | |
| 143 | + [SugarColumn(ColumnName = "F_LeaveDays", DecimalDigits = 2)] | |
| 144 | + public decimal LeaveDays { get; set; } | |
| 145 | + | |
| 146 | + /// <summary> | |
| 147 | + /// 提成合计(业绩提成 + 消耗提成) | |
| 148 | + /// </summary> | |
| 149 | + [SugarColumn(ColumnName = "F_TotalCommission", DecimalDigits = 2)] | |
| 150 | + public decimal TotalCommission { get; set; } | |
| 151 | + | |
| 152 | + /// <summary> | |
| 153 | + /// 车补 | |
| 154 | + /// </summary> | |
| 155 | + [SugarColumn(ColumnName = "F_TransportationAllowance", DecimalDigits = 2)] | |
| 156 | + public decimal TransportationAllowance { get; set; } | |
| 157 | + | |
| 158 | + /// <summary> | |
| 159 | + /// 少休费 | |
| 160 | + /// </summary> | |
| 161 | + [SugarColumn(ColumnName = "F_LessRest", DecimalDigits = 2)] | |
| 162 | + public decimal LessRest { get; set; } | |
| 163 | + | |
| 164 | + /// <summary> | |
| 165 | + /// 全勤奖 | |
| 166 | + /// </summary> | |
| 167 | + [SugarColumn(ColumnName = "F_FullAttendance", DecimalDigits = 2)] | |
| 168 | + public decimal FullAttendance { get; set; } | |
| 169 | + | |
| 170 | + /// <summary> | |
| 171 | + /// 核算应发工资 | |
| 172 | + /// </summary> | |
| 173 | + [SugarColumn(ColumnName = "F_CalculatedGrossSalary", DecimalDigits = 2)] | |
| 174 | + public decimal CalculatedGrossSalary { get; set; } | |
| 175 | + | |
| 176 | + /// <summary> | |
| 177 | + /// 保底工资 | |
| 178 | + /// </summary> | |
| 179 | + [SugarColumn(ColumnName = "F_GuaranteedSalary", DecimalDigits = 2)] | |
| 180 | + public decimal GuaranteedSalary { get; set; } | |
| 181 | + | |
| 182 | + /// <summary> | |
| 183 | + /// 保底请假扣款 | |
| 184 | + /// </summary> | |
| 185 | + [SugarColumn(ColumnName = "F_GuaranteedLeaveDeduction", DecimalDigits = 2)] | |
| 186 | + public decimal GuaranteedLeaveDeduction { get; set; } | |
| 187 | + | |
| 188 | + /// <summary> | |
| 189 | + /// 保底底薪 | |
| 190 | + /// </summary> | |
| 191 | + [SugarColumn(ColumnName = "F_GuaranteedBaseSalary", DecimalDigits = 2)] | |
| 192 | + public decimal GuaranteedBaseSalary { get; set; } | |
| 193 | + | |
| 194 | + /// <summary> | |
| 195 | + /// 保底补差 | |
| 196 | + /// </summary> | |
| 197 | + [SugarColumn(ColumnName = "F_GuaranteedSupplement", DecimalDigits = 2)] | |
| 198 | + public decimal GuaranteedSupplement { get; set; } | |
| 199 | + | |
| 200 | + /// <summary> | |
| 201 | + /// 最终应发工资 | |
| 202 | + /// </summary> | |
| 203 | + [SugarColumn(ColumnName = "F_FinalGrossSalary", DecimalDigits = 2)] | |
| 204 | + public decimal FinalGrossSalary { get; set; } | |
| 205 | + | |
| 206 | + /// <summary> | |
| 207 | + /// 当月培训补贴 | |
| 208 | + /// </summary> | |
| 209 | + [SugarColumn(ColumnName = "F_MonthlyTrainingSubsidy", DecimalDigits = 2)] | |
| 210 | + public decimal MonthlyTrainingSubsidy { get; set; } | |
| 211 | + | |
| 212 | + /// <summary> | |
| 213 | + /// 当月交通补贴 | |
| 214 | + /// </summary> | |
| 215 | + [SugarColumn(ColumnName = "F_MonthlyTransportSubsidy", DecimalDigits = 2)] | |
| 216 | + public decimal MonthlyTransportSubsidy { get; set; } | |
| 217 | + | |
| 218 | + /// <summary> | |
| 219 | + /// 上月培训补贴 | |
| 220 | + /// </summary> | |
| 221 | + [SugarColumn(ColumnName = "F_LastMonthTrainingSubsidy", DecimalDigits = 2)] | |
| 222 | + public decimal LastMonthTrainingSubsidy { get; set; } | |
| 223 | + | |
| 224 | + /// <summary> | |
| 225 | + /// 上月交通补贴 | |
| 226 | + /// </summary> | |
| 227 | + [SugarColumn(ColumnName = "F_LastMonthTransportSubsidy", DecimalDigits = 2)] | |
| 228 | + public decimal LastMonthTransportSubsidy { get; set; } | |
| 229 | + | |
| 230 | + /// <summary> | |
| 231 | + /// 补贴合计 | |
| 232 | + /// </summary> | |
| 233 | + [SugarColumn(ColumnName = "F_TotalSubsidy", DecimalDigits = 2)] | |
| 234 | + public decimal TotalSubsidy { get; set; } | |
| 235 | + | |
| 236 | + /// <summary> | |
| 237 | + /// 缺卡扣款 | |
| 238 | + /// </summary> | |
| 239 | + [SugarColumn(ColumnName = "F_MissingCard", DecimalDigits = 2)] | |
| 240 | + public decimal MissingCard { get; set; } | |
| 241 | + | |
| 242 | + /// <summary> | |
| 243 | + /// 迟到扣款 | |
| 244 | + /// </summary> | |
| 245 | + [SugarColumn(ColumnName = "F_LateArrival", DecimalDigits = 2)] | |
| 246 | + public decimal LateArrival { get; set; } | |
| 247 | + | |
| 248 | + /// <summary> | |
| 249 | + /// 请假扣款 | |
| 250 | + /// </summary> | |
| 251 | + [SugarColumn(ColumnName = "F_LeaveDeduction", DecimalDigits = 2)] | |
| 252 | + public decimal LeaveDeduction { get; set; } | |
| 253 | + | |
| 254 | + /// <summary> | |
| 255 | + /// 扣社保 | |
| 256 | + /// </summary> | |
| 257 | + [SugarColumn(ColumnName = "F_SocialInsuranceDeduction", DecimalDigits = 2)] | |
| 258 | + public decimal SocialInsuranceDeduction { get; set; } | |
| 259 | + | |
| 260 | + /// <summary> | |
| 261 | + /// 扣除奖励 | |
| 262 | + /// </summary> | |
| 263 | + [SugarColumn(ColumnName = "F_RewardDeduction", DecimalDigits = 2)] | |
| 264 | + public decimal RewardDeduction { get; set; } | |
| 265 | + | |
| 266 | + /// <summary> | |
| 267 | + /// 扣住宿费 | |
| 268 | + /// </summary> | |
| 269 | + [SugarColumn(ColumnName = "F_AccommodationDeduction", DecimalDigits = 2)] | |
| 270 | + public decimal AccommodationDeduction { get; set; } | |
| 271 | + | |
| 272 | + /// <summary> | |
| 273 | + /// 扣学习期费用 | |
| 274 | + /// </summary> | |
| 275 | + [SugarColumn(ColumnName = "F_StudyPeriodDeduction", DecimalDigits = 2)] | |
| 276 | + public decimal StudyPeriodDeduction { get; set; } | |
| 277 | + | |
| 278 | + /// <summary> | |
| 279 | + /// 扣工作服费用 | |
| 280 | + /// </summary> | |
| 281 | + [SugarColumn(ColumnName = "F_WorkClothesDeduction", DecimalDigits = 2)] | |
| 282 | + public decimal WorkClothesDeduction { get; set; } | |
| 283 | + | |
| 284 | + /// <summary> | |
| 285 | + /// 扣款合计 | |
| 286 | + /// </summary> | |
| 287 | + [SugarColumn(ColumnName = "F_TotalDeduction", DecimalDigits = 2)] | |
| 288 | + public decimal TotalDeduction { get; set; } | |
| 289 | + | |
| 290 | + /// <summary> | |
| 291 | + /// 发奖金 | |
| 292 | + /// </summary> | |
| 293 | + [SugarColumn(ColumnName = "F_Bonus", DecimalDigits = 2)] | |
| 294 | + public decimal Bonus { get; set; } | |
| 295 | + | |
| 296 | + /// <summary> | |
| 297 | + /// 退手机押金 | |
| 298 | + /// </summary> | |
| 299 | + [SugarColumn(ColumnName = "F_ReturnPhoneDeposit", DecimalDigits = 2)] | |
| 300 | + public decimal ReturnPhoneDeposit { get; set; } | |
| 301 | + | |
| 302 | + /// <summary> | |
| 303 | + /// 退住宿押金 | |
| 304 | + /// </summary> | |
| 305 | + [SugarColumn(ColumnName = "F_ReturnAccommodationDeposit", DecimalDigits = 2)] | |
| 306 | + public decimal ReturnAccommodationDeposit { get; set; } | |
| 307 | + | |
| 308 | + /// <summary> | |
| 309 | + /// 实发工资 | |
| 310 | + /// </summary> | |
| 311 | + [SugarColumn(ColumnName = "F_ActualSalary", DecimalDigits = 2)] | |
| 312 | + public decimal ActualSalary { get; set; } | |
| 313 | + | |
| 314 | + /// <summary> | |
| 315 | + /// 当月是否发放 | |
| 316 | + /// </summary> | |
| 317 | + [SugarColumn(ColumnName = "F_MonthlyPaymentStatus")] | |
| 318 | + public string MonthlyPaymentStatus { get; set; } | |
| 319 | + | |
| 320 | + /// <summary> | |
| 321 | + /// 支付金额 | |
| 322 | + /// </summary> | |
| 323 | + [SugarColumn(ColumnName = "F_PaidAmount", DecimalDigits = 2)] | |
| 324 | + public decimal PaidAmount { get; set; } | |
| 325 | + | |
| 326 | + /// <summary> | |
| 327 | + /// 待支付金额 | |
| 328 | + /// </summary> | |
| 329 | + [SugarColumn(ColumnName = "F_PendingAmount", DecimalDigits = 2)] | |
| 330 | + public decimal PendingAmount { get; set; } | |
| 331 | + | |
| 332 | + /// <summary> | |
| 333 | + /// 补发上月 | |
| 334 | + /// </summary> | |
| 335 | + [SugarColumn(ColumnName = "F_LastMonthSupplement", DecimalDigits = 2)] | |
| 336 | + public decimal LastMonthSupplement { get; set; } | |
| 337 | + | |
| 338 | + /// <summary> | |
| 339 | + /// 当月支付总额 | |
| 340 | + /// </summary> | |
| 341 | + [SugarColumn(ColumnName = "F_MonthlyTotalPayment", DecimalDigits = 2)] | |
| 342 | + public decimal MonthlyTotalPayment { get; set; } | |
| 343 | + | |
| 344 | + /// <summary> | |
| 345 | + /// 是否锁定(0未锁定,1已锁定) | |
| 346 | + /// </summary> | |
| 347 | + [SugarColumn(ColumnName = "F_IsLocked")] | |
| 348 | + public int IsLocked { get; set; } | |
| 349 | + | |
| 350 | + /// <summary> | |
| 351 | + /// 是否离职(0=在职,1=离职) | |
| 352 | + /// </summary> | |
| 353 | + [SugarColumn(ColumnName = "F_IsTerminated")] | |
| 354 | + public int IsTerminated { get; set; } | |
| 355 | + | |
| 356 | + /// <summary> | |
| 357 | + /// 创建时间 | |
| 358 | + /// </summary> | |
| 359 | + [SugarColumn(ColumnName = "F_CreateTime")] | |
| 360 | + public DateTime CreateTime { get; set; } | |
| 361 | + | |
| 362 | + /// <summary> | |
| 363 | + /// 更新时间 | |
| 364 | + /// </summary> | |
| 365 | + [SugarColumn(ColumnName = "F_UpdateTime")] | |
| 366 | + public DateTime UpdateTime { get; set; } | |
| 367 | + | |
| 368 | + /// <summary> | |
| 369 | + /// 创建人 | |
| 370 | + /// </summary> | |
| 371 | + [SugarColumn(ColumnName = "F_CreateUser")] | |
| 372 | + public string CreateUser { get; set; } | |
| 373 | + | |
| 374 | + /// <summary> | |
| 375 | + /// 更新人 | |
| 376 | + /// </summary> | |
| 377 | + [SugarColumn(ColumnName = "F_UpdateUser")] | |
| 378 | + public string UpdateUser { get; set; } | |
| 379 | + | |
| 380 | + /// <summary> | |
| 381 | + /// 是否新店 | |
| 382 | + /// </summary> | |
| 383 | + [SugarColumn(ColumnName = "F_IsNewStore")] | |
| 384 | + public string IsNewStore { get; set; } | |
| 385 | + | |
| 386 | + /// <summary> | |
| 387 | + /// 新店保护阶段 | |
| 388 | + /// </summary> | |
| 389 | + [SugarColumn(ColumnName = "F_NewStoreProtectionStage")] | |
| 390 | + public int NewStoreProtectionStage { get; set; } | |
| 391 | + | |
| 392 | + /// <summary> | |
| 393 | + /// 门店类型 | |
| 394 | + /// </summary> | |
| 395 | + [SugarColumn(ColumnName = "F_StoreType")] | |
| 396 | + public int? StoreType { get; set; } | |
| 397 | + | |
| 398 | + /// <summary> | |
| 399 | + /// 门店类别 | |
| 400 | + /// </summary> | |
| 401 | + [SugarColumn(ColumnName = "F_StoreCategory")] | |
| 402 | + public int? StoreCategory { get; set; } | |
| 403 | + } | |
| 404 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Interfaces/LqMdMajorProjectTeacherAssignment/ILqMdMajorProjectTeacherAssignmentService.cs
0 → 100644
| 1 | +using NCC.Common.Filter; | |
| 2 | +using NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment; | |
| 3 | +using System.Threading.Tasks; | |
| 4 | + | |
| 5 | +namespace NCC.Extend.Interfaces.LqMdMajorProjectTeacherAssignment | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 门店大项目部老师归属设置服务接口 | |
| 9 | + /// </summary> | |
| 10 | + public interface ILqMdMajorProjectTeacherAssignmentService | |
| 11 | + { | |
| 12 | + /// <summary> | |
| 13 | + /// 复制上月设置 | |
| 14 | + /// </summary> | |
| 15 | + /// <param name="targetMonth">目标月份(YYYYMM格式),如果为空则复制到当前月份</param> | |
| 16 | + /// <returns></returns> | |
| 17 | + Task<dynamic> CopyLastMonthData(string targetMonth = null); | |
| 18 | + } | |
| 19 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqMdMajorProjectTeacherAssignmentService.cs
0 → 100644
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text.RegularExpressions; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | +using Mapster; | |
| 7 | +using Microsoft.AspNetCore.Mvc; | |
| 8 | +using NCC.Common.Core.Manager; | |
| 9 | +using NCC.Common.Enum; | |
| 10 | +using NCC.Common.Extension; | |
| 11 | +using NCC.Common.Filter; | |
| 12 | +using NCC.Dependency; | |
| 13 | +using NCC.DynamicApiController; | |
| 14 | +using NCC.Extend.Entitys.Dto.LqMdMajorProjectTeacherAssignment; | |
| 15 | +using NCC.Extend.Entitys.lq_md_major_project_teacher_assignment; | |
| 16 | +using NCC.Extend.Entitys.lq_mdxx; | |
| 17 | +using NCC.Extend.Interfaces.LqMdMajorProjectTeacherAssignment; | |
| 18 | +using NCC.FriendlyException; | |
| 19 | +using NCC.System.Entitys.Permission; | |
| 20 | +using SqlSugar; | |
| 21 | +using Yitter.IdGenerator; | |
| 22 | + | |
| 23 | +namespace NCC.Extend | |
| 24 | +{ | |
| 25 | + /// <summary> | |
| 26 | + /// 门店大项目部老师归属设置服务 | |
| 27 | + /// </summary> | |
| 28 | + [ApiDescriptionSettings(Tag = "绿纤门店大项目部老师归属设置服务", Name = "LqMdMajorProjectTeacherAssignment", Order = 201)] | |
| 29 | + [Route("api/Extend/[controller]")] | |
| 30 | + public class LqMdMajorProjectTeacherAssignmentService : ILqMdMajorProjectTeacherAssignmentService, IDynamicApiController, ITransient | |
| 31 | + { | |
| 32 | + private readonly ISqlSugarRepository<LqMdMajorProjectTeacherAssignmentEntity> _repository; | |
| 33 | + private readonly SqlSugarScope _db; | |
| 34 | + private readonly IUserManager _userManager; | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 初始化一个<see cref="LqMdMajorProjectTeacherAssignmentService"/>类型的新实例 | |
| 38 | + /// </summary> | |
| 39 | + public LqMdMajorProjectTeacherAssignmentService(ISqlSugarRepository<LqMdMajorProjectTeacherAssignmentEntity> repository, IUserManager userManager) | |
| 40 | + { | |
| 41 | + _repository = repository; | |
| 42 | + _db = _repository.Context; | |
| 43 | + _userManager = userManager; | |
| 44 | + } | |
| 45 | + | |
| 46 | + #region 获取门店大项目部老师归属设置信息 | |
| 47 | + /// <summary> | |
| 48 | + /// 获取门店大项目部老师归属设置信息 | |
| 49 | + /// </summary> | |
| 50 | + /// <param name="id">主键ID</param> | |
| 51 | + /// <returns></returns> | |
| 52 | + [HttpGet("{id}")] | |
| 53 | + public async Task<dynamic> GetInfo(string id) | |
| 54 | + { | |
| 55 | + var entity = await _db.Queryable<LqMdMajorProjectTeacherAssignmentEntity>() | |
| 56 | + .Where(p => p.Id == id) | |
| 57 | + .Select(it => new LqMdMajorProjectTeacherAssignmentInfoOutput | |
| 58 | + { | |
| 59 | + id = it.Id, | |
| 60 | + storeId = it.StoreId, | |
| 61 | + storeName = SqlFunc.Subqueryable<LqMdxxEntity>().Where(x => x.Id == it.StoreId).Select(x => x.Dm), | |
| 62 | + year = it.Year, | |
| 63 | + month = it.Month, | |
| 64 | + teacherId = it.TeacherId, | |
| 65 | + teacherName = SqlFunc.Subqueryable<UserEntity>().Where(x => x.Id == it.TeacherId).Select(x => x.RealName), | |
| 66 | + remark = it.Remark, | |
| 67 | + createTime = it.CreateTime, | |
| 68 | + createUserId = it.CreateUserId, | |
| 69 | + updateTime = it.UpdateTime, | |
| 70 | + updateUserId = it.UpdateUserId, | |
| 71 | + }) | |
| 72 | + .FirstAsync(); | |
| 73 | + | |
| 74 | + _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005); | |
| 75 | + return entity; | |
| 76 | + } | |
| 77 | + #endregion | |
| 78 | + | |
| 79 | + #region 获取门店大项目部老师归属设置列表 | |
| 80 | + /// <summary> | |
| 81 | + /// 获取门店大项目部老师归属设置列表 | |
| 82 | + /// </summary> | |
| 83 | + /// <param name="input">请求参数</param> | |
| 84 | + /// <returns></returns> | |
| 85 | + [HttpGet("")] | |
| 86 | + public async Task<dynamic> GetList([FromQuery] LqMdMajorProjectTeacherAssignmentListQueryInput input) | |
| 87 | + { | |
| 88 | + var sidx = input.sidx == null ? "id" : input.sidx; | |
| 89 | + var data = await _db.Queryable<LqMdMajorProjectTeacherAssignmentEntity>() | |
| 90 | + .WhereIF(!string.IsNullOrEmpty(input.storeId), p => p.StoreId == input.storeId) | |
| 91 | + .WhereIF(!string.IsNullOrEmpty(input.year), p => p.Year == input.year) | |
| 92 | + .WhereIF(!string.IsNullOrEmpty(input.month), p => p.Month == input.month) | |
| 93 | + .WhereIF(!string.IsNullOrEmpty(input.teacherId), p => p.TeacherId == input.teacherId) | |
| 94 | + .Select(it => new LqMdMajorProjectTeacherAssignmentListOutput | |
| 95 | + { | |
| 96 | + id = it.Id, | |
| 97 | + storeId = it.StoreId, | |
| 98 | + storeName = SqlFunc.Subqueryable<LqMdxxEntity>().Where(x => x.Id == it.StoreId).Select(x => x.Dm), | |
| 99 | + year = it.Year, | |
| 100 | + month = it.Month, | |
| 101 | + teacherId = it.TeacherId, | |
| 102 | + teacherName = SqlFunc.Subqueryable<UserEntity>().Where(x => x.Id == it.TeacherId).Select(x => x.RealName), | |
| 103 | + remark = it.Remark, | |
| 104 | + createTime = it.CreateTime, | |
| 105 | + createUserId = it.CreateUserId, | |
| 106 | + updateTime = it.UpdateTime, | |
| 107 | + updateUserId = it.UpdateUserId, | |
| 108 | + }) | |
| 109 | + .MergeTable() | |
| 110 | + .OrderBy(sidx + " " + input.sort) | |
| 111 | + .ToPagedListAsync(input.currentPage, input.pageSize); | |
| 112 | + | |
| 113 | + return PageResult<LqMdMajorProjectTeacherAssignmentListOutput>.SqlSugarPageResult(data); | |
| 114 | + } | |
| 115 | + #endregion | |
| 116 | + | |
| 117 | + #region 新建门店大项目部老师归属设置 | |
| 118 | + /// <summary> | |
| 119 | + /// 新建门店大项目部老师归属设置 | |
| 120 | + /// </summary> | |
| 121 | + /// <param name="input">参数</param> | |
| 122 | + /// <returns></returns> | |
| 123 | + [HttpPost("")] | |
| 124 | + public async Task Create([FromBody] LqMdMajorProjectTeacherAssignmentCrInput input) | |
| 125 | + { | |
| 126 | + var userInfo = await _userManager.GetUserInfo(); | |
| 127 | + | |
| 128 | + // 验证年份格式 | |
| 129 | + if (input.year.Length != 4 || !Regex.IsMatch(input.year, @"^\d{4}$")) | |
| 130 | + { | |
| 131 | + throw NCCException.Oh(ErrorCode.COM1000, "年份格式必须为YYYY(如:2025)"); | |
| 132 | + } | |
| 133 | + | |
| 134 | + // 验证月份格式 | |
| 135 | + if (input.month.Length != 2 || !Regex.IsMatch(input.month, @"^\d{2}$")) | |
| 136 | + { | |
| 137 | + throw NCCException.Oh(ErrorCode.COM1000, "月份格式必须为MM(如:01表示1月)"); | |
| 138 | + } | |
| 139 | + | |
| 140 | + // 验证月份范围(01-12) | |
| 141 | + if (!int.TryParse(input.month, out int monthInt) || monthInt < 1 || monthInt > 12) | |
| 142 | + { | |
| 143 | + throw NCCException.Oh(ErrorCode.COM1000, "月份必须在01-12之间"); | |
| 144 | + } | |
| 145 | + | |
| 146 | + // 验证门店ID、年份、月份、老师ID的唯一性 | |
| 147 | + var exists = await _db.Queryable<LqMdMajorProjectTeacherAssignmentEntity>() | |
| 148 | + .Where(p => p.StoreId == input.storeId && p.Year == input.year && p.Month == input.month && p.TeacherId == input.teacherId) | |
| 149 | + .AnyAsync(); | |
| 150 | + if (exists) | |
| 151 | + { | |
| 152 | + throw NCCException.Oh(ErrorCode.COM1000, "该门店在该年份该月份该老师已存在归属设置记录"); | |
| 153 | + } | |
| 154 | + | |
| 155 | + var entity = input.Adapt<LqMdMajorProjectTeacherAssignmentEntity>(); | |
| 156 | + entity.Id = YitIdHelper.NextId().ToString(); | |
| 157 | + entity.CreateTime = DateTime.Now; | |
| 158 | + entity.CreateUserId = userInfo.userId; | |
| 159 | + | |
| 160 | + var isOk = await _db.Insertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync(); | |
| 161 | + if (!(isOk > 0)) | |
| 162 | + throw NCCException.Oh(ErrorCode.COM1000); | |
| 163 | + } | |
| 164 | + #endregion | |
| 165 | + | |
| 166 | + #region 更新门店大项目部老师归属设置 | |
| 167 | + /// <summary> | |
| 168 | + /// 更新门店大项目部老师归属设置 | |
| 169 | + /// </summary> | |
| 170 | + /// <param name="id">主键ID</param> | |
| 171 | + /// <param name="input">更新参数</param> | |
| 172 | + /// <returns></returns> | |
| 173 | + [HttpPut("{id}")] | |
| 174 | + public async Task Update([FromRoute] string id, [FromBody] LqMdMajorProjectTeacherAssignmentUpInput input) | |
| 175 | + { | |
| 176 | + var userInfo = await _userManager.GetUserInfo(); | |
| 177 | + | |
| 178 | + // 验证年份格式 | |
| 179 | + if (input.year.Length != 4 || !Regex.IsMatch(input.year, @"^\d{4}$")) | |
| 180 | + { | |
| 181 | + throw NCCException.Oh(ErrorCode.COM1000, "年份格式必须为YYYY(如:2025)"); | |
| 182 | + } | |
| 183 | + | |
| 184 | + // 验证月份格式 | |
| 185 | + if (input.month.Length != 2 || !Regex.IsMatch(input.month, @"^\d{2}$")) | |
| 186 | + { | |
| 187 | + throw NCCException.Oh(ErrorCode.COM1000, "月份格式必须为MM(如:01表示1月)"); | |
| 188 | + } | |
| 189 | + | |
| 190 | + // 验证月份范围(01-12) | |
| 191 | + if (!int.TryParse(input.month, out int monthInt) || monthInt < 1 || monthInt > 12) | |
| 192 | + { | |
| 193 | + throw NCCException.Oh(ErrorCode.COM1000, "月份必须在01-12之间"); | |
| 194 | + } | |
| 195 | + | |
| 196 | + var entity = await _db.Queryable<LqMdMajorProjectTeacherAssignmentEntity>().FirstAsync(p => p.Id == id); | |
| 197 | + _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005); | |
| 198 | + | |
| 199 | + // 如果门店、年份、月份、老师ID有变化,需要验证唯一性 | |
| 200 | + if (entity.StoreId != input.storeId || entity.Year != input.year || entity.Month != input.month || entity.TeacherId != input.teacherId) | |
| 201 | + { | |
| 202 | + var exists = await _db.Queryable<LqMdMajorProjectTeacherAssignmentEntity>() | |
| 203 | + .Where(p => p.Id != id && p.StoreId == input.storeId && p.Year == input.year && p.Month == input.month && p.TeacherId == input.teacherId) | |
| 204 | + .AnyAsync(); | |
| 205 | + if (exists) | |
| 206 | + { | |
| 207 | + throw NCCException.Oh(ErrorCode.COM1000, "该门店在该年份该月份该老师已存在归属设置记录"); | |
| 208 | + } | |
| 209 | + } | |
| 210 | + | |
| 211 | + entity.StoreId = input.storeId; | |
| 212 | + entity.Year = input.year; | |
| 213 | + entity.Month = input.month; | |
| 214 | + entity.TeacherId = input.teacherId; | |
| 215 | + entity.Remark = input.remark; | |
| 216 | + entity.UpdateTime = DateTime.Now; | |
| 217 | + entity.UpdateUserId = userInfo.userId; | |
| 218 | + | |
| 219 | + var isOk = await _db.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); | |
| 220 | + if (!(isOk > 0)) | |
| 221 | + throw NCCException.Oh(ErrorCode.COM1000); | |
| 222 | + } | |
| 223 | + #endregion | |
| 224 | + | |
| 225 | + #region 删除门店大项目部老师归属设置 | |
| 226 | + /// <summary> | |
| 227 | + /// 删除门店大项目部老师归属设置 | |
| 228 | + /// </summary> | |
| 229 | + /// <param name="id">主键ID</param> | |
| 230 | + /// <returns></returns> | |
| 231 | + [HttpDelete("{id}")] | |
| 232 | + public async Task Delete(string id) | |
| 233 | + { | |
| 234 | + var entity = await _db.Queryable<LqMdMajorProjectTeacherAssignmentEntity>().FirstAsync(p => p.Id == id); | |
| 235 | + _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005); | |
| 236 | + | |
| 237 | + var isOk = await _db.Deleteable<LqMdMajorProjectTeacherAssignmentEntity>().Where(p => p.Id == id).ExecuteCommandAsync(); | |
| 238 | + if (!(isOk > 0)) | |
| 239 | + throw NCCException.Oh(ErrorCode.COM1000); | |
| 240 | + } | |
| 241 | + #endregion | |
| 242 | + | |
| 243 | + #region 复制上月设置 | |
| 244 | + /// <summary> | |
| 245 | + /// 从上个月复制设置数据到目标月份 | |
| 246 | + /// </summary> | |
| 247 | + /// <remarks> | |
| 248 | + /// 从上个月复制门店大项目部老师归属设置数据到目标月份 | |
| 249 | + /// | |
| 250 | + /// 示例请求: | |
| 251 | + /// POST /api/Extend/LqMdMajorProjectTeacherAssignment/CopyLastMonthData?targetYear=2025&targetMonth=02 | |
| 252 | + /// | |
| 253 | + /// 业务逻辑: | |
| 254 | + /// 1. 确定目标年份和月份(如果未指定,使用当前年月) | |
| 255 | + /// 2. 计算上个月份 | |
| 256 | + /// 3. 查询上个月的所有设置数据 | |
| 257 | + /// 4. 查询目标月份已存在的记录 | |
| 258 | + /// 5. 过滤掉已存在的记录,只复制新记录 | |
| 259 | + /// 6. 批量插入新记录 | |
| 260 | + /// </remarks> | |
| 261 | + /// <param name="targetYear">目标年份(YYYY格式),如果为空则使用当前年份</param> | |
| 262 | + /// <param name="targetMonth">目标月份(MM格式),如果为空则使用当前月份</param> | |
| 263 | + /// <returns>复制结果</returns> | |
| 264 | + /// <response code="200">成功返回复制结果</response> | |
| 265 | + /// <response code="400">参数错误</response> | |
| 266 | + /// <response code="500">服务器内部错误</response> | |
| 267 | + [HttpPost("CopyLastMonthData")] | |
| 268 | + public async Task<dynamic> CopyLastMonthData([FromQuery] string targetYear = null, [FromQuery] string targetMonth = null) | |
| 269 | + { | |
| 270 | + // 确定目标年份和月份 | |
| 271 | + DateTime targetDate; | |
| 272 | + if (string.IsNullOrEmpty(targetYear) || string.IsNullOrEmpty(targetMonth)) | |
| 273 | + { | |
| 274 | + targetDate = DateTime.Now; | |
| 275 | + } | |
| 276 | + else | |
| 277 | + { | |
| 278 | + if (targetYear.Length != 4 || !Regex.IsMatch(targetYear, @"^\d{4}$")) | |
| 279 | + { | |
| 280 | + throw NCCException.Oh(ErrorCode.COM1000, "目标年份格式必须为YYYY(如:2025)"); | |
| 281 | + } | |
| 282 | + if (targetMonth.Length != 2 || !Regex.IsMatch(targetMonth, @"^\d{2}$")) | |
| 283 | + { | |
| 284 | + throw NCCException.Oh(ErrorCode.COM1000, "目标月份格式必须为MM(如:01表示1月)"); | |
| 285 | + } | |
| 286 | + if (!int.TryParse(targetMonth, out int monthInt) || monthInt < 1 || monthInt > 12) | |
| 287 | + { | |
| 288 | + throw NCCException.Oh(ErrorCode.COM1000, "目标月份必须在01-12之间"); | |
| 289 | + } | |
| 290 | + targetDate = DateTime.ParseExact($"{targetYear}{targetMonth}", "yyyyMM", null); | |
| 291 | + } | |
| 292 | + | |
| 293 | + // 计算上个月份 | |
| 294 | + var lastMonthDate = targetDate.AddMonths(-1); | |
| 295 | + var lastYear = lastMonthDate.ToString("yyyy"); | |
| 296 | + var lastMonth = lastMonthDate.ToString("MM"); | |
| 297 | + var targetYearStr = targetDate.ToString("yyyy"); | |
| 298 | + var targetMonthStr = targetDate.ToString("MM"); | |
| 299 | + | |
| 300 | + // 查询上个月的所有设置数据 | |
| 301 | + var lastMonthData = await _db.Queryable<LqMdMajorProjectTeacherAssignmentEntity>() | |
| 302 | + .Where(p => p.Year == lastYear && p.Month == lastMonth) | |
| 303 | + .ToListAsync(); | |
| 304 | + | |
| 305 | + if (lastMonthData == null || lastMonthData.Count == 0) | |
| 306 | + { | |
| 307 | + return new { message = $"上个月({lastYear}年{lastMonth}月)没有设置数据,无法复制" }; | |
| 308 | + } | |
| 309 | + | |
| 310 | + // 查询目标月份已存在的记录 | |
| 311 | + var existingTargetMonthData = await _db.Queryable<LqMdMajorProjectTeacherAssignmentEntity>() | |
| 312 | + .Where(p => p.Year == targetYearStr && p.Month == targetMonthStr) | |
| 313 | + .Select(p => new { p.StoreId, p.TeacherId }) | |
| 314 | + .ToListAsync(); | |
| 315 | + | |
| 316 | + var existingKeys = existingTargetMonthData | |
| 317 | + .Select(x => $"{x.StoreId}_{x.TeacherId}") | |
| 318 | + .ToHashSet(); | |
| 319 | + | |
| 320 | + // 过滤掉已存在的记录,只复制新记录 | |
| 321 | + var newData = lastMonthData | |
| 322 | + .Where(x => !existingKeys.Contains($"{x.StoreId}_{x.TeacherId}")) | |
| 323 | + .Select(x => new LqMdMajorProjectTeacherAssignmentEntity | |
| 324 | + { | |
| 325 | + Id = YitIdHelper.NextId().ToString(), | |
| 326 | + StoreId = x.StoreId, | |
| 327 | + Year = targetYearStr, | |
| 328 | + Month = targetMonthStr, | |
| 329 | + TeacherId = x.TeacherId, | |
| 330 | + Remark = x.Remark, | |
| 331 | + CreateTime = DateTime.Now, | |
| 332 | + CreateUserId = _userManager.UserId, | |
| 333 | + UpdateTime = null, | |
| 334 | + UpdateUserId = null | |
| 335 | + }) | |
| 336 | + .ToList(); | |
| 337 | + | |
| 338 | + if (newData.Count == 0) | |
| 339 | + { | |
| 340 | + return new { message = $"目标月份({targetYearStr}年{targetMonthStr}月)已存在所有设置,无需复制" }; | |
| 341 | + } | |
| 342 | + | |
| 343 | + // 批量插入新记录 | |
| 344 | + var insertCount = await _db.Insertable(newData).ExecuteCommandAsync(); | |
| 345 | + | |
| 346 | + return new { message = $"成功从{lastYear}年{lastMonth}月复制{insertCount}条记录到{targetYearStr}年{targetMonthStr}月" }; | |
| 347 | + } | |
| 348 | + #endregion | |
| 349 | + } | |
| 350 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqTechTeacherSalaryService.cs
0 → 100644
| 1 | +using Microsoft.AspNetCore.Authorization; | |
| 2 | +using Microsoft.AspNetCore.Mvc; | |
| 3 | +using NCC.Common.Filter; | |
| 4 | +using NCC.Common.Helper; | |
| 5 | +using NCC.Dependency; | |
| 6 | +using NCC.DynamicApiController; | |
| 7 | +using NCC.Extend.Entitys.Dto.LqTechTeacherSalary; | |
| 8 | +using NCC.Extend.Entitys.lq_hytk_kjbsyj; | |
| 9 | +using NCC.Extend.Entitys.lq_kd_kjbsyj; | |
| 10 | +using NCC.Extend.Entitys.lq_md_xdbhsj; | |
| 11 | +using NCC.Extend.Entitys.lq_mdxx; | |
| 12 | +using NCC.Extend.Entitys.lq_attendance_summary; | |
| 13 | +using NCC.Extend.Entitys.lq_tech_teacher_salary_statistics; | |
| 14 | +using NCC.Extend.Entitys.lq_xh_hyhk; | |
| 15 | +using NCC.Extend.Entitys.lq_xh_kjbsyj; | |
| 16 | +using NCC.System.Entitys.Permission; | |
| 17 | +using SqlSugar; | |
| 18 | +using System; | |
| 19 | +using System.Collections.Generic; | |
| 20 | +using System.Linq; | |
| 21 | +using System.Threading.Tasks; | |
| 22 | +using Yitter.IdGenerator; | |
| 23 | + | |
| 24 | +namespace NCC.Extend | |
| 25 | +{ | |
| 26 | + /// <summary> | |
| 27 | + /// 科技老师薪酬服务 | |
| 28 | + /// </summary> | |
| 29 | + [ApiDescriptionSettings(Tag = "科技老师薪酬服务", Name = "LqTechTeacherSalary", Order = 302)] | |
| 30 | + [Route("api/Extend/[controller]")] | |
| 31 | + public class LqTechTeacherSalaryService : IDynamicApiController, ITransient | |
| 32 | + { | |
| 33 | + private readonly ISqlSugarClient _db; | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 初始化一个<see cref="LqTechTeacherSalaryService"/>类型的新实例 | |
| 37 | + /// </summary> | |
| 38 | + public LqTechTeacherSalaryService(ISqlSugarClient db) | |
| 39 | + { | |
| 40 | + _db = db; | |
| 41 | + } | |
| 42 | + | |
| 43 | + /// <summary> | |
| 44 | + /// 获取科技老师工资列表 | |
| 45 | + /// </summary> | |
| 46 | + /// <param name="input">查询参数</param> | |
| 47 | + /// <returns>科技老师工资分页列表</returns> | |
| 48 | + [HttpGet("tech-teacher")] | |
| 49 | + public async Task<dynamic> GetTechTeacherSalaryList([FromQuery] TechTeacherSalaryInput input) | |
| 50 | + { | |
| 51 | + var monthStr = $"{input.Year}{input.Month:D2}"; | |
| 52 | + | |
| 53 | + // 1. 检查当月是否已生成工资数据 | |
| 54 | + var exists = await _db.Queryable<LqTechTeacherSalaryStatisticsEntity>() | |
| 55 | + .AnyAsync(x => x.StatisticsMonth == monthStr); | |
| 56 | + | |
| 57 | + // 2. 如果没有数据,则进行计算 | |
| 58 | + if (!exists) | |
| 59 | + { | |
| 60 | + await CalculateTechTeacherSalary(input.Year, input.Month); | |
| 61 | + } | |
| 62 | + | |
| 63 | + // 3. 查询数据 | |
| 64 | + var query = _db.Queryable<LqTechTeacherSalaryStatisticsEntity>() | |
| 65 | + .Where(x => x.StatisticsMonth == monthStr); | |
| 66 | + | |
| 67 | + if (!string.IsNullOrEmpty(input.StoreId)) | |
| 68 | + { | |
| 69 | + query = query.Where(x => x.StoreId == input.StoreId); | |
| 70 | + } | |
| 71 | + | |
| 72 | + if (!string.IsNullOrEmpty(input.Keyword)) | |
| 73 | + { | |
| 74 | + query = query.Where(x => x.EmployeeName.Contains(input.Keyword) || x.EmployeeAccount.Contains(input.Keyword)); | |
| 75 | + } | |
| 76 | + | |
| 77 | + var list = await query.Select(x => new TechTeacherSalaryOutput | |
| 78 | + { | |
| 79 | + Id = x.Id, | |
| 80 | + StatisticsMonth = x.StatisticsMonth, | |
| 81 | + StoreId = x.StoreId, | |
| 82 | + StoreName = x.StoreName, | |
| 83 | + Position = x.Position, | |
| 84 | + EmployeeName = x.EmployeeName, | |
| 85 | + EmployeeId = x.EmployeeId, | |
| 86 | + EmployeeAccount = x.EmployeeAccount, | |
| 87 | + OrderAchievement = x.OrderAchievement, | |
| 88 | + ConsumeAchievement = x.ConsumeAchievement, | |
| 89 | + RefundAchievement = x.RefundAchievement, | |
| 90 | + TotalPerformance = x.TotalPerformance, | |
| 91 | + ProjectCount = x.ProjectCount, | |
| 92 | + BaseSalaryLevel = x.BaseSalaryLevel, | |
| 93 | + BaseSalary = x.BaseSalary, | |
| 94 | + PerformanceCommissionRate = x.PerformanceCommissionRate, | |
| 95 | + PerformanceCommissionAmount = x.PerformanceCommissionAmount, | |
| 96 | + ConsumeCommissionRate = x.ConsumeCommissionRate, | |
| 97 | + ConsumeCommissionAmount = x.ConsumeCommissionAmount, | |
| 98 | + HandworkFee = x.HandworkFee, | |
| 99 | + WorkingDays = x.WorkingDays, | |
| 100 | + LeaveDays = x.LeaveDays, | |
| 101 | + TotalCommission = x.TotalCommission, | |
| 102 | + TransportationAllowance = x.TransportationAllowance, | |
| 103 | + LessRest = x.LessRest, | |
| 104 | + FullAttendance = x.FullAttendance, | |
| 105 | + CalculatedGrossSalary = x.CalculatedGrossSalary, | |
| 106 | + GuaranteedSalary = x.GuaranteedSalary, | |
| 107 | + GuaranteedLeaveDeduction = x.GuaranteedLeaveDeduction, | |
| 108 | + GuaranteedBaseSalary = x.GuaranteedBaseSalary, | |
| 109 | + GuaranteedSupplement = x.GuaranteedSupplement, | |
| 110 | + FinalGrossSalary = x.FinalGrossSalary, | |
| 111 | + MonthlyTrainingSubsidy = x.MonthlyTrainingSubsidy, | |
| 112 | + MonthlyTransportSubsidy = x.MonthlyTransportSubsidy, | |
| 113 | + LastMonthTrainingSubsidy = x.LastMonthTrainingSubsidy, | |
| 114 | + LastMonthTransportSubsidy = x.LastMonthTransportSubsidy, | |
| 115 | + TotalSubsidy = x.TotalSubsidy, | |
| 116 | + MissingCard = x.MissingCard, | |
| 117 | + LateArrival = x.LateArrival, | |
| 118 | + LeaveDeduction = x.LeaveDeduction, | |
| 119 | + SocialInsuranceDeduction = x.SocialInsuranceDeduction, | |
| 120 | + RewardDeduction = x.RewardDeduction, | |
| 121 | + AccommodationDeduction = x.AccommodationDeduction, | |
| 122 | + StudyPeriodDeduction = x.StudyPeriodDeduction, | |
| 123 | + WorkClothesDeduction = x.WorkClothesDeduction, | |
| 124 | + TotalDeduction = x.TotalDeduction, | |
| 125 | + Bonus = x.Bonus, | |
| 126 | + ReturnPhoneDeposit = x.ReturnPhoneDeposit, | |
| 127 | + ReturnAccommodationDeposit = x.ReturnAccommodationDeposit, | |
| 128 | + ActualSalary = x.ActualSalary, | |
| 129 | + MonthlyPaymentStatus = x.MonthlyPaymentStatus, | |
| 130 | + PaidAmount = x.PaidAmount, | |
| 131 | + PendingAmount = x.PendingAmount, | |
| 132 | + LastMonthSupplement = x.LastMonthSupplement, | |
| 133 | + MonthlyTotalPayment = x.MonthlyTotalPayment, | |
| 134 | + IsLocked = x.IsLocked, | |
| 135 | + IsTerminated = x.IsTerminated, | |
| 136 | + UpdateTime = x.UpdateTime, | |
| 137 | + StoreType = x.StoreType, | |
| 138 | + StoreCategory = x.StoreCategory, | |
| 139 | + IsNewStore = x.IsNewStore, | |
| 140 | + NewStoreProtectionStage = x.NewStoreProtectionStage | |
| 141 | + }) | |
| 142 | + .ToPagedListAsync(input.currentPage, input.pageSize); | |
| 143 | + | |
| 144 | + return PageResult<TechTeacherSalaryOutput>.SqlSugarPageResult(list); | |
| 145 | + } | |
| 146 | + | |
| 147 | + /// <summary> | |
| 148 | + /// 计算科技老师工资 | |
| 149 | + /// </summary> | |
| 150 | + /// <param name="year">年份</param> | |
| 151 | + /// <param name="month">月份</param> | |
| 152 | + /// <returns></returns> | |
| 153 | + [HttpPost("calculate/tech-teacher")] | |
| 154 | + public async Task CalculateTechTeacherSalary(int year, int month) | |
| 155 | + { | |
| 156 | + var startDate = new DateTime(year, month, 1); | |
| 157 | + var endDate = startDate.AddMonths(1).AddDays(-1); | |
| 158 | + var monthStr = $"{year}{month:D2}"; | |
| 159 | + | |
| 160 | + // 1. 获取基础数据 | |
| 161 | + | |
| 162 | + // 1.1 获取科技老师员工列表(从BASE_USER表,岗位为"科技老师") | |
| 163 | + var techTeacherUserList = await _db.Queryable<UserEntity>() | |
| 164 | + .Where(x => x.Gw == "科技老师" && x.DeleteMark == null && x.EnabledMark == 1) | |
| 165 | + .Select(x => new { x.Id, x.RealName, x.Account, x.Mdid, x.IsOnJob }) | |
| 166 | + .ToListAsync(); | |
| 167 | + | |
| 168 | + if (!techTeacherUserList.Any()) | |
| 169 | + { | |
| 170 | + // 如果没有科技老师员工,直接返回 | |
| 171 | + return; | |
| 172 | + } | |
| 173 | + | |
| 174 | + // 1.2 门店信息 (lq_mdxx) | |
| 175 | + var storeList = await _db.Queryable<LqMdxxEntity>().ToListAsync(); | |
| 176 | + var storeDict = storeList.Where(x => !string.IsNullOrEmpty(x.Id)).ToDictionary(x => x.Id, x => x); | |
| 177 | + | |
| 178 | + // 1.3 门店新店保护信息 (lq_md_xdbhsj) | |
| 179 | + var newStoreProtectionList = await _db.Queryable<LqMdXdbhsjEntity>() | |
| 180 | + .Where(x => x.Sfqy == 1) | |
| 181 | + .ToListAsync(); | |
| 182 | + | |
| 183 | + var newStoreProtectionDict = newStoreProtectionList | |
| 184 | + .Where(x => x.Bhkssj <= startDate && x.Bhjssj >= startDate) | |
| 185 | + .GroupBy(x => x.Mdid) | |
| 186 | + .ToDictionary(g => g.Key, g => g.First()); | |
| 187 | + | |
| 188 | + // 1.4 开单业绩数据 (lq_kd_kjbsyj) | |
| 189 | + var orderPerformanceList = await _db.Queryable<LqKdKjbsyjEntity>() | |
| 190 | + .Where(x => x.Yjsj >= startDate && x.Yjsj <= endDate.AddDays(1) && x.IsEffective == 1) | |
| 191 | + .ToListAsync(); | |
| 192 | + | |
| 193 | + // 1.5 消耗业绩和项目数数据 (lq_xh_kjbsyj,关联lq_xh_hyhk获取时间) | |
| 194 | + var consumePerformanceList = await _db.Queryable<LqXhKjbsyjEntity, LqXhHyhkEntity>( | |
| 195 | + (kjbsyj, hyhk) => kjbsyj.Glkdbh == hyhk.Id && hyhk.IsEffective == 1) | |
| 196 | + .Where((kjbsyj, hyhk) => kjbsyj.IsEffective == 1 | |
| 197 | + && hyhk.Hksj >= startDate && hyhk.Hksj <= endDate.AddDays(1)) | |
| 198 | + .Select((kjbsyj, hyhk) => new | |
| 199 | + { | |
| 200 | + kjbsyj.Kjblszh, | |
| 201 | + kjbsyj.Kjblsyj, | |
| 202 | + kjbsyj.HdpxNumber, | |
| 203 | + kjbsyj.LaborCost, | |
| 204 | + hyhk.Md | |
| 205 | + }) | |
| 206 | + .ToListAsync(); | |
| 207 | + | |
| 208 | + // 1.6 退卡业绩数据 (lq_hytk_kjbsyj) | |
| 209 | + var refundPerformanceList = await _db.Queryable<LqHytkKjbsyjEntity>() | |
| 210 | + .Where(x => x.Tksj >= startDate && x.Tksj <= endDate.AddDays(1) && x.IsEffective == 1) | |
| 211 | + .ToListAsync(); | |
| 212 | + | |
| 213 | + // 1.7 考勤数据 (lq_attendance_summary) | |
| 214 | + var attendanceList = await _db.Queryable<LqAttendanceSummaryEntity>() | |
| 215 | + .Where(x => x.Year == year && x.Month == month && x.IsEffective == 1) | |
| 216 | + .ToListAsync(); | |
| 217 | + var attendanceDict = attendanceList.ToDictionary(x => x.UserId, x => x); | |
| 218 | + | |
| 219 | + // 2. 按科技老师聚合数据 | |
| 220 | + var techTeacherStats = new Dictionary<string, LqTechTeacherSalaryStatisticsEntity>(); | |
| 221 | + | |
| 222 | + foreach (var techTeacherUser in techTeacherUserList) | |
| 223 | + { | |
| 224 | + var teacherId = techTeacherUser.Id; | |
| 225 | + var isTerminated = techTeacherUser.IsOnJob == 0; | |
| 226 | + | |
| 227 | + // 2.1 创建工资统计对象 | |
| 228 | + var salary = new LqTechTeacherSalaryStatisticsEntity | |
| 229 | + { | |
| 230 | + Id = YitIdHelper.NextId().ToString(), | |
| 231 | + StatisticsMonth = monthStr, | |
| 232 | + EmployeeId = teacherId, | |
| 233 | + EmployeeName = techTeacherUser.RealName, | |
| 234 | + EmployeeAccount = techTeacherUser.Account ?? "", | |
| 235 | + Position = "科技部老师", | |
| 236 | + IsTerminated = isTerminated ? 1 : 0, | |
| 237 | + CreateTime = DateTime.Now, | |
| 238 | + UpdateTime = DateTime.Now, | |
| 239 | + IsLocked = 0 | |
| 240 | + }; | |
| 241 | + | |
| 242 | + // 2.2 填充门店信息 | |
| 243 | + var storeId = techTeacherUser.Mdid; | |
| 244 | + if (!string.IsNullOrEmpty(storeId) && storeDict.ContainsKey(storeId)) | |
| 245 | + { | |
| 246 | + var store = storeDict[storeId]; | |
| 247 | + salary.StoreId = storeId; | |
| 248 | + salary.StoreName = store.Dm ?? ""; | |
| 249 | + salary.StoreType = store.StoreType; | |
| 250 | + salary.StoreCategory = store.StoreCategory; | |
| 251 | + } | |
| 252 | + else | |
| 253 | + { | |
| 254 | + // 如果用户没有门店,尝试从业绩数据中获取 | |
| 255 | + var firstOrderStore = orderPerformanceList.FirstOrDefault(x => x.Kjbls == teacherId || x.Kjblszh == teacherId); | |
| 256 | + var firstConsumeStore = consumePerformanceList.FirstOrDefault(x => x.Kjblszh == teacherId); | |
| 257 | + var firstRefundStore = refundPerformanceList.FirstOrDefault(x => x.Kjbls == teacherId || x.Kjblszh == teacherId); | |
| 258 | + | |
| 259 | + if (firstOrderStore != null && !string.IsNullOrEmpty(firstOrderStore.StoreId)) | |
| 260 | + { | |
| 261 | + storeId = firstOrderStore.StoreId; | |
| 262 | + } | |
| 263 | + else if (firstConsumeStore != null && !string.IsNullOrEmpty(firstConsumeStore.Md)) | |
| 264 | + { | |
| 265 | + storeId = firstConsumeStore.Md; | |
| 266 | + } | |
| 267 | + else if (firstRefundStore != null && !string.IsNullOrEmpty(firstRefundStore.StoreId)) | |
| 268 | + { | |
| 269 | + storeId = firstRefundStore.StoreId; | |
| 270 | + } | |
| 271 | + | |
| 272 | + if (!string.IsNullOrEmpty(storeId) && storeDict.ContainsKey(storeId)) | |
| 273 | + { | |
| 274 | + var store = storeDict[storeId]; | |
| 275 | + salary.StoreId = storeId; | |
| 276 | + salary.StoreName = store.Dm ?? ""; | |
| 277 | + salary.StoreType = store.StoreType; | |
| 278 | + salary.StoreCategory = store.StoreCategory; | |
| 279 | + } | |
| 280 | + } | |
| 281 | + | |
| 282 | + // 2.3 新店保护信息 | |
| 283 | + if (!string.IsNullOrEmpty(salary.StoreId) && newStoreProtectionDict.ContainsKey(salary.StoreId)) | |
| 284 | + { | |
| 285 | + var protection = newStoreProtectionDict[salary.StoreId]; | |
| 286 | + salary.IsNewStore = "是"; | |
| 287 | + salary.NewStoreProtectionStage = protection.Stage; | |
| 288 | + } | |
| 289 | + else | |
| 290 | + { | |
| 291 | + salary.IsNewStore = "否"; | |
| 292 | + salary.NewStoreProtectionStage = 0; | |
| 293 | + } | |
| 294 | + | |
| 295 | + // 2.4 统计业绩数据 | |
| 296 | + // 开单业绩(注意:kjblsyj字段是string类型,需要转换) | |
| 297 | + var orderPerformance = orderPerformanceList | |
| 298 | + .Where(x => (x.Kjbls == teacherId || x.Kjblszh == teacherId) && !string.IsNullOrEmpty(x.Kjblsyj)) | |
| 299 | + .Sum(x => decimal.TryParse(x.Kjblsyj, out var val) ? val : 0m); | |
| 300 | + salary.OrderAchievement = orderPerformance; | |
| 301 | + | |
| 302 | + // 消耗业绩和项目数 | |
| 303 | + var consumeData = consumePerformanceList | |
| 304 | + .Where(x => x.Kjblszh == teacherId) | |
| 305 | + .ToList(); | |
| 306 | + salary.ConsumeAchievement = consumeData.Sum(x => x.Kjblsyj ?? 0m); | |
| 307 | + salary.ProjectCount = consumeData.Sum(x => x.HdpxNumber ?? 0m); | |
| 308 | + salary.HandworkFee = consumeData.Sum(x => x.LaborCost ?? 0m); | |
| 309 | + | |
| 310 | + // 退卡业绩 | |
| 311 | + var refundPerformance = refundPerformanceList | |
| 312 | + .Where(x => (x.Kjbls == teacherId || x.Kjblszh == teacherId)) | |
| 313 | + .Sum(x => x.Kjblsyj ?? 0m); | |
| 314 | + salary.RefundAchievement = refundPerformance; | |
| 315 | + | |
| 316 | + // 总业绩 | |
| 317 | + salary.TotalPerformance = salary.OrderAchievement + salary.ConsumeAchievement + salary.RefundAchievement; | |
| 318 | + | |
| 319 | + // 2.5 考勤数据 | |
| 320 | + var attendance = attendanceDict.ContainsKey(teacherId) ? attendanceDict[teacherId] : null; | |
| 321 | + salary.WorkingDays = attendance?.WorkDays ?? 0; | |
| 322 | + salary.LeaveDays = attendance?.LeaveDays ?? 0; | |
| 323 | + | |
| 324 | + // 3. 工资计算 | |
| 325 | + if (isTerminated) | |
| 326 | + { | |
| 327 | + // 离职员工特殊处理 | |
| 328 | + if (salary.TotalPerformance > 30000m) | |
| 329 | + { | |
| 330 | + // 总业绩 > 30,000元:只计算2%提成 | |
| 331 | + salary.BaseSalary = 0; | |
| 332 | + salary.BaseSalaryLevel = 0; | |
| 333 | + salary.PerformanceCommissionRate = 2m; | |
| 334 | + salary.PerformanceCommissionAmount = salary.TotalPerformance * 0.02m; | |
| 335 | + salary.ConsumeCommissionRate = 0; | |
| 336 | + salary.ConsumeCommissionAmount = 0; | |
| 337 | + salary.TotalCommission = salary.PerformanceCommissionAmount; | |
| 338 | + } | |
| 339 | + else | |
| 340 | + { | |
| 341 | + // 总业绩 ≤ 30,000元:无任何工资 | |
| 342 | + salary.BaseSalary = 0; | |
| 343 | + salary.BaseSalaryLevel = 0; | |
| 344 | + salary.PerformanceCommissionRate = 0; | |
| 345 | + salary.PerformanceCommissionAmount = 0; | |
| 346 | + salary.ConsumeCommissionRate = 0; | |
| 347 | + salary.ConsumeCommissionAmount = 0; | |
| 348 | + salary.TotalCommission = 0; | |
| 349 | + } | |
| 350 | + } | |
| 351 | + else | |
| 352 | + { | |
| 353 | + // 在职员工正常计算 | |
| 354 | + | |
| 355 | + // 3.1 计算底薪(根据项目数和总业绩) | |
| 356 | + var baseSalaryResult = CalculateBaseSalary(salary.ProjectCount, salary.TotalPerformance); | |
| 357 | + salary.BaseSalary = baseSalaryResult.BaseSalary; | |
| 358 | + salary.BaseSalaryLevel = baseSalaryResult.Level; | |
| 359 | + | |
| 360 | + // 3.2 计算业绩提成(分段累进) | |
| 361 | + var performanceCommissionResult = CalculatePerformanceCommission(salary.TotalPerformance); | |
| 362 | + salary.PerformanceCommissionRate = performanceCommissionResult.Rate; | |
| 363 | + salary.PerformanceCommissionAmount = performanceCommissionResult.Amount; | |
| 364 | + | |
| 365 | + // 3.3 计算消耗提成(分段累进,可能为负数) | |
| 366 | + var consumeCommissionResult = CalculateConsumeCommission(salary.ConsumeAchievement); | |
| 367 | + salary.ConsumeCommissionRate = consumeCommissionResult.Rate; | |
| 368 | + salary.ConsumeCommissionAmount = consumeCommissionResult.Amount; | |
| 369 | + | |
| 370 | + // 3.4 提成合计 | |
| 371 | + salary.TotalCommission = salary.PerformanceCommissionAmount + salary.ConsumeCommissionAmount; | |
| 372 | + } | |
| 373 | + | |
| 374 | + // 3.5 初始化其他字段(默认值为0) | |
| 375 | + salary.TransportationAllowance = 0; | |
| 376 | + salary.LessRest = 0; | |
| 377 | + salary.FullAttendance = 0; | |
| 378 | + salary.CalculatedGrossSalary = salary.BaseSalary + salary.TotalCommission + salary.HandworkFee; | |
| 379 | + salary.GuaranteedSalary = 0; | |
| 380 | + salary.GuaranteedLeaveDeduction = 0; | |
| 381 | + salary.GuaranteedBaseSalary = 0; | |
| 382 | + salary.GuaranteedSupplement = 0; | |
| 383 | + salary.FinalGrossSalary = salary.CalculatedGrossSalary; | |
| 384 | + salary.MonthlyTrainingSubsidy = 0; | |
| 385 | + salary.MonthlyTransportSubsidy = 0; | |
| 386 | + salary.LastMonthTrainingSubsidy = 0; | |
| 387 | + salary.LastMonthTransportSubsidy = 0; | |
| 388 | + salary.TotalSubsidy = 0; | |
| 389 | + salary.MissingCard = 0; | |
| 390 | + salary.LateArrival = 0; | |
| 391 | + salary.LeaveDeduction = 0; | |
| 392 | + salary.SocialInsuranceDeduction = 0; | |
| 393 | + salary.RewardDeduction = 0; | |
| 394 | + salary.AccommodationDeduction = 0; | |
| 395 | + salary.StudyPeriodDeduction = 0; | |
| 396 | + salary.WorkClothesDeduction = 0; | |
| 397 | + salary.TotalDeduction = 0; | |
| 398 | + salary.Bonus = 0; | |
| 399 | + salary.ReturnPhoneDeposit = 0; | |
| 400 | + salary.ReturnAccommodationDeposit = 0; | |
| 401 | + salary.ActualSalary = salary.FinalGrossSalary - salary.TotalDeduction + salary.TotalSubsidy + salary.Bonus; | |
| 402 | + salary.MonthlyPaymentStatus = ""; | |
| 403 | + salary.PaidAmount = 0; | |
| 404 | + salary.PendingAmount = salary.ActualSalary; | |
| 405 | + salary.LastMonthSupplement = 0; | |
| 406 | + salary.MonthlyTotalPayment = 0; | |
| 407 | + | |
| 408 | + techTeacherStats[teacherId] = salary; | |
| 409 | + } | |
| 410 | + | |
| 411 | + // 4. 保存数据 | |
| 412 | + if (techTeacherStats.Any()) | |
| 413 | + { | |
| 414 | + // 先删除当月旧数据 (防止重复) | |
| 415 | + await _db.Deleteable<LqTechTeacherSalaryStatisticsEntity>() | |
| 416 | + .Where(x => x.StatisticsMonth == monthStr) | |
| 417 | + .ExecuteCommandAsync(); | |
| 418 | + | |
| 419 | + await _db.Insertable(techTeacherStats.Values.ToList()).ExecuteCommandAsync(); | |
| 420 | + } | |
| 421 | + } | |
| 422 | + | |
| 423 | + /// <summary> | |
| 424 | + /// 计算底薪(根据项目数和总业绩) | |
| 425 | + /// </summary> | |
| 426 | + /// <param name="projectCount">项目数</param> | |
| 427 | + /// <param name="totalPerformance">总业绩</param> | |
| 428 | + /// <returns>底薪金额和档位</returns> | |
| 429 | + private (decimal BaseSalary, int Level) CalculateBaseSalary(decimal projectCount, decimal totalPerformance) | |
| 430 | + { | |
| 431 | + // 从高到低判断档位,同时满足项目数和总业绩两个条件 | |
| 432 | + // 第三档:≥ 110个 且 ≥ 100,000元 → 3,500元 | |
| 433 | + if (projectCount >= 110m && totalPerformance >= 100000m) | |
| 434 | + { | |
| 435 | + return (3500m, 3); | |
| 436 | + } | |
| 437 | + // 第二档:≥ 95个 且 ≥ 80,000元 → 3,000元 | |
| 438 | + else if (projectCount >= 95m && totalPerformance >= 80000m) | |
| 439 | + { | |
| 440 | + return (3000m, 2); | |
| 441 | + } | |
| 442 | + // 第一档:≥ 80个 且 ≥ 40,000元 → 2,500元 | |
| 443 | + else if (projectCount >= 80m && totalPerformance >= 40000m) | |
| 444 | + { | |
| 445 | + return (2500m, 1); | |
| 446 | + } | |
| 447 | + // 都不满足:默认第一档 2,500元 | |
| 448 | + else | |
| 449 | + { | |
| 450 | + return (2500m, 1); | |
| 451 | + } | |
| 452 | + } | |
| 453 | + | |
| 454 | + /// <summary> | |
| 455 | + /// 计算业绩提成(分段累进) | |
| 456 | + /// </summary> | |
| 457 | + /// <param name="totalPerformance">总业绩</param> | |
| 458 | + /// <returns>提成比例和金额</returns> | |
| 459 | + private (decimal Rate, decimal Amount) CalculatePerformanceCommission(decimal totalPerformance) | |
| 460 | + { | |
| 461 | + if (totalPerformance < 10000m) | |
| 462 | + { | |
| 463 | + // < 10,000元 → 0% | |
| 464 | + return (0m, 0m); | |
| 465 | + } | |
| 466 | + else if (totalPerformance < 70000m) | |
| 467 | + { | |
| 468 | + // 10,000-70,000元 → 2% | |
| 469 | + return (2m, totalPerformance * 0.02m); | |
| 470 | + } | |
| 471 | + else if (totalPerformance < 150000m) | |
| 472 | + { | |
| 473 | + // 70,000-150,000元 → 2.5% | |
| 474 | + return (2.5m, totalPerformance * 0.025m); | |
| 475 | + } | |
| 476 | + else | |
| 477 | + { | |
| 478 | + // > 150,000元 → 3% | |
| 479 | + return (3m, totalPerformance * 0.03m); | |
| 480 | + } | |
| 481 | + } | |
| 482 | + | |
| 483 | + /// <summary> | |
| 484 | + /// 计算消耗提成(分段累进,可能为负数) | |
| 485 | + /// </summary> | |
| 486 | + /// <param name="consumeAchievement">消耗业绩</param> | |
| 487 | + /// <returns>提成比例和金额(金额可能为负数,比例用于显示)</returns> | |
| 488 | + private (decimal Rate, decimal Amount) CalculateConsumeCommission(decimal consumeAchievement) | |
| 489 | + { | |
| 490 | + if (consumeAchievement < 80000m) | |
| 491 | + { | |
| 492 | + // < 80,000元 → 扣除300元(负数) | |
| 493 | + // 比例显示为0,金额为-300 | |
| 494 | + return (0m, -300m); | |
| 495 | + } | |
| 496 | + else if (consumeAchievement < 100000m) | |
| 497 | + { | |
| 498 | + // 80,000-100,000元 → 0.5% | |
| 499 | + return (0.5m, consumeAchievement * 0.005m); | |
| 500 | + } | |
| 501 | + else if (consumeAchievement < 200000m) | |
| 502 | + { | |
| 503 | + // 100,000-200,000元 → 0.5% | |
| 504 | + return (0.5m, consumeAchievement * 0.005m); | |
| 505 | + } | |
| 506 | + else | |
| 507 | + { | |
| 508 | + // > 200,000元 → 1% | |
| 509 | + return (1m, consumeAchievement * 0.01m); | |
| 510 | + } | |
| 511 | + } | |
| 512 | + } | |
| 513 | +} | |
| 514 | + | ... | ... |
sql/创建大项目部老师归属设置表.sql
0 → 100644
| 1 | +-- ============================================ | |
| 2 | +-- 创建大项目部老师归属设置表 | |
| 3 | +-- 功能:存储各门店每月的大项目部老师归属设置 | |
| 4 | +-- 创建时间:2025年 | |
| 5 | +-- ============================================ | |
| 6 | + | |
| 7 | +-- 删除表(如果存在) | |
| 8 | +DROP TABLE IF EXISTS lq_md_major_project_teacher_assignment; | |
| 9 | + | |
| 10 | +-- ============================================ | |
| 11 | +-- 创建大项目部老师归属设置表 | |
| 12 | +-- ============================================ | |
| 13 | +CREATE TABLE lq_md_major_project_teacher_assignment ( | |
| 14 | + -- 主键 | |
| 15 | + F_Id VARCHAR(50) NOT NULL COMMENT '主键ID', | |
| 16 | + -- 基本信息 | |
| 17 | + F_StoreId VARCHAR(50) NOT NULL COMMENT '门店ID', | |
| 18 | + F_Year VARCHAR(4) NOT NULL COMMENT '年份(YYYY格式)', | |
| 19 | + F_Month VARCHAR(2) NOT NULL COMMENT '月份(MM格式)', | |
| 20 | + F_TeacherId VARCHAR(50) NOT NULL COMMENT '大项目部老师用户ID', | |
| 21 | + -- 备注说明 | |
| 22 | + F_Remark TEXT NULL COMMENT '备注说明', | |
| 23 | + -- 审计字段 | |
| 24 | + F_CreateTime DATETIME NULL COMMENT '创建时间', | |
| 25 | + F_CreateUserId VARCHAR(50) NULL COMMENT '创建人ID', | |
| 26 | + F_UpdateTime DATETIME NULL COMMENT '更新时间', | |
| 27 | + F_UpdateUserId VARCHAR(50) NULL COMMENT '更新人ID', | |
| 28 | + -- 主键约束 | |
| 29 | + PRIMARY KEY (F_Id) | |
| 30 | +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='门店大项目部老师归属设置表'; | |
| 31 | + | |
| 32 | +-- ============================================ | |
| 33 | +-- 创建索引 | |
| 34 | +-- ============================================ | |
| 35 | + | |
| 36 | +-- 门店ID + 年份 + 月份 + 老师ID唯一索引(同一门店同一年份同一月份同一老师只能有一条记录) | |
| 37 | +CREATE UNIQUE INDEX idx_store_year_month_teacher ON lq_md_major_project_teacher_assignment(F_StoreId, F_Year, F_Month, F_TeacherId); | |
| 38 | + | |
| 39 | +-- 门店ID索引(查询某个门店的所有设置) | |
| 40 | +CREATE INDEX idx_store_id ON lq_md_major_project_teacher_assignment(F_StoreId); | |
| 41 | + | |
| 42 | +-- 年份索引(查询某年的所有设置) | |
| 43 | +CREATE INDEX idx_year ON lq_md_major_project_teacher_assignment(F_Year); | |
| 44 | +-- 月份索引(查询某个月份的所有设置) | |
| 45 | +CREATE INDEX idx_month ON lq_md_major_project_teacher_assignment(F_Month); | |
| 46 | +-- 年份+月份组合索引(查询某年某月的所有设置) | |
| 47 | +CREATE INDEX idx_year_month ON lq_md_major_project_teacher_assignment(F_Year, F_Month); | |
| 48 | + | |
| 49 | +-- 老师ID索引(查询某个老师的所有门店设置) | |
| 50 | +CREATE INDEX idx_teacher_id ON lq_md_major_project_teacher_assignment(F_TeacherId); | |
| 51 | + | |
| 52 | +-- ============================================ | |
| 53 | +-- 表结构说明 | |
| 54 | +-- ============================================ | |
| 55 | +/* | |
| 56 | +业务规则: | |
| 57 | +1. 同一门店同一年份同一月份同一老师只能有一条归属设置记录 | |
| 58 | +2. 年份格式为YYYY(如:2025表示2025年) | |
| 59 | +3. 月份格式为MM(如:01表示1月) | |
| 60 | +4. 一个门店在一个月份可以有多个老师(通过多条记录实现) | |
| 61 | +5. 一个门店在一个月份也可以没有老师(不创建记录即可) | |
| 62 | +6. 老师ID关联BASE_USER.F_Id | |
| 63 | +7. 门店ID关联lq_mdxx.F_Id | |
| 64 | + | |
| 65 | +字段说明: | |
| 66 | +- F_Id: 主键,使用YitIdHelper生成 | |
| 67 | +- F_StoreId: 门店ID,关联lq_mdxx表 | |
| 68 | +- F_Year: 年份,格式YYYY(如:2025) | |
| 69 | +- F_Month: 月份,格式MM(如:01表示1月) | |
| 70 | +- F_TeacherId: 大项目部老师用户ID,关联BASE_USER表 | |
| 71 | +- F_Remark: 备注说明(可选) | |
| 72 | +- F_CreateTime/F_CreateUserId: 创建时间和创建人 | |
| 73 | +- F_UpdateTime/F_UpdateUserId: 更新时间和更新人 | |
| 74 | +*/ | ... | ... |
sql/创建科技部老师工资统计表.sql
0 → 100644
| 1 | +-- ============================================ | |
| 2 | +-- 创建科技部老师工资统计表 | |
| 3 | +-- 功能:存储科技部老师每月的工资计算数据,包括底薪、业绩提成、消耗提成、考核扣款、扣款、补贴、奖金、支付等信息 | |
| 4 | +-- 创建时间:2025年 | |
| 5 | +-- ============================================ | |
| 6 | + | |
| 7 | +-- 删除表(如果存在) | |
| 8 | +DROP TABLE IF EXISTS lq_tech_teacher_salary_statistics; | |
| 9 | + | |
| 10 | +-- ============================================ | |
| 11 | +-- 创建科技部老师工资统计表 | |
| 12 | +-- ============================================ | |
| 13 | +CREATE TABLE lq_tech_teacher_salary_statistics ( | |
| 14 | + -- 主键 | |
| 15 | + F_Id VARCHAR(50) NOT NULL COMMENT '主键ID', | |
| 16 | + | |
| 17 | + -- 一、基础信息字段 | |
| 18 | + F_StatisticsMonth VARCHAR(6) NOT NULL COMMENT '统计月份(YYYYMM格式)', | |
| 19 | + F_StoreId VARCHAR(50) NOT NULL COMMENT '门店ID', | |
| 20 | + F_StoreName VARCHAR(200) NOT NULL COMMENT '门店名称', | |
| 21 | + F_Position VARCHAR(50) NOT NULL DEFAULT '科技部老师' COMMENT '核算岗位(固定为"科技部老师")', | |
| 22 | + F_EmployeeName VARCHAR(100) NOT NULL COMMENT '员工姓名', | |
| 23 | + F_EmployeeId VARCHAR(50) NOT NULL COMMENT '员工ID', | |
| 24 | + F_EmployeeAccount VARCHAR(100) NOT NULL COMMENT '员工账号', | |
| 25 | + F_StoreType INT NULL COMMENT '门店类型(200平/旗舰店)', | |
| 26 | + F_StoreCategory INT NULL COMMENT '门店分类(1=A类,2=B类,3=C类)', | |
| 27 | + F_IsNewStore VARCHAR(10) NULL COMMENT '是否新店(是/否)', | |
| 28 | + F_NewStoreProtectionStage INT NOT NULL DEFAULT 0 COMMENT '新店保护阶段(0/1/2)', | |
| 29 | + | |
| 30 | + -- 二、业绩相关字段 | |
| 31 | + F_OrderAchievement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '开单业绩(从lq_kd_kjbsyj表统计)', | |
| 32 | + F_ConsumeAchievement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '消耗业绩(对应规则中的"消耗",从lq_xh_kjbsyj表统计)', | |
| 33 | + F_RefundAchievement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '退卡业绩(从lq_hytk_kjbsyj表统计)', | |
| 34 | + F_TotalPerformance DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '总业绩(开单业绩 + 消耗业绩 + 退卡业绩,用于底薪和业绩提成计算)', | |
| 35 | + F_ProjectCount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '项目数(用于底薪计算,主要来源于耗卡品相次数F_hdpxNumber)', | |
| 36 | + | |
| 37 | + -- 三、底薪相关字段 | |
| 38 | + F_BaseSalaryLevel INT NOT NULL DEFAULT 0 COMMENT '底薪档位(1=第一档2500, 2=第二档3000, 3=第三档3500)', | |
| 39 | + F_BaseSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '底薪金额(根据项目数和业绩计算,2500/3000/3500)', | |
| 40 | + | |
| 41 | + -- 四、业绩提成相关字段 | |
| 42 | + F_PerformanceCommissionRate DECIMAL(18,4) NOT NULL DEFAULT 0.0000 COMMENT '业绩提成比例(百分比,如2.00表示2%)', | |
| 43 | + F_PerformanceCommissionAmount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '业绩提成金额(总业绩 × 业绩提成比例)', | |
| 44 | + | |
| 45 | + -- 五、消耗提成相关字段 | |
| 46 | + F_ConsumeCommissionRate DECIMAL(18,4) NOT NULL DEFAULT 0.0000 COMMENT '消耗提成比例(百分比,如0.50表示0.5%,负数表示扣除,如-300表示扣除300元)', | |
| 47 | + F_ConsumeCommissionAmount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '消耗提成金额(可能为负数,如扣除300元)', | |
| 48 | + F_TotalCommission DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '提成合计(业绩提成 + 消耗提成)', | |
| 49 | + | |
| 50 | + -- 六、其他收入字段 | |
| 51 | + F_HandworkFee DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '手工费', | |
| 52 | + F_TransportationAllowance DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '车补', | |
| 53 | + F_LessRest DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '少休费', | |
| 54 | + F_FullAttendance DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '全勤奖', | |
| 55 | + | |
| 56 | + -- 七、考勤相关字段 | |
| 57 | + F_WorkingDays DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '在店天数', | |
| 58 | + F_LeaveDays DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '请假天数', | |
| 59 | + | |
| 60 | + -- 八、工资计算字段 | |
| 61 | + F_CalculatedGrossSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '核算应发工资(底薪 + 提成合计 + 其他收入)', | |
| 62 | + F_GuaranteedSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '保底工资', | |
| 63 | + F_GuaranteedLeaveDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '保底请假扣款', | |
| 64 | + F_GuaranteedBaseSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '保底底薪', | |
| 65 | + F_GuaranteedSupplement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '保底补差', | |
| 66 | + F_FinalGrossSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '最终应发工资(取核算应发工资和保底工资的较大值)', | |
| 67 | + | |
| 68 | + -- 九、补贴相关字段 | |
| 69 | + F_MonthlyTrainingSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '当月培训补贴', | |
| 70 | + F_MonthlyTransportSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '当月交通补贴', | |
| 71 | + F_LastMonthTrainingSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '上月培训补贴', | |
| 72 | + F_LastMonthTransportSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '上月交通补贴', | |
| 73 | + F_TotalSubsidy DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '补贴合计', | |
| 74 | + | |
| 75 | + -- 十、扣款相关字段 | |
| 76 | + F_MissingCard DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '缺卡扣款', | |
| 77 | + F_LateArrival DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '迟到扣款', | |
| 78 | + F_LeaveDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '请假扣款', | |
| 79 | + F_SocialInsuranceDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣社保', | |
| 80 | + F_RewardDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣除奖励', | |
| 81 | + F_AccommodationDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣住宿费', | |
| 82 | + F_StudyPeriodDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣学习期费用', | |
| 83 | + F_WorkClothesDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣工作服费用', | |
| 84 | + F_TotalDeduction DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '扣款合计', | |
| 85 | + | |
| 86 | + -- 十一、奖金相关字段 | |
| 87 | + F_Bonus DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '发奖金', | |
| 88 | + F_ReturnPhoneDeposit DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '退手机押金', | |
| 89 | + F_ReturnAccommodationDeposit DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '退住宿押金', | |
| 90 | + | |
| 91 | + -- 十二、支付相关字段 | |
| 92 | + F_ActualSalary DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '实发工资(最终应发工资 - 扣款合计 + 补贴合计 + 奖金)', | |
| 93 | + F_MonthlyPaymentStatus VARCHAR(20) NOT NULL DEFAULT '未发放' COMMENT '当月是否发放(已发放/未发放/部分发放)', | |
| 94 | + F_PaidAmount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '支付金额', | |
| 95 | + F_PendingAmount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '待支付金额', | |
| 96 | + F_LastMonthSupplement DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '补发上月', | |
| 97 | + F_MonthlyTotalPayment DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '当月支付总额', | |
| 98 | + | |
| 99 | + -- 十三、系统字段 | |
| 100 | + F_IsLocked INT NOT NULL DEFAULT 0 COMMENT '是否锁定(0=未锁定,1=已锁定)', | |
| 101 | + F_IsTerminated INT NOT NULL DEFAULT 0 COMMENT '是否离职(0=在职,1=离职)', | |
| 102 | + F_CreateTime DATETIME NOT NULL COMMENT '创建时间', | |
| 103 | + F_UpdateTime DATETIME NOT NULL COMMENT '更新时间', | |
| 104 | + F_CreateUser VARCHAR(50) NULL COMMENT '创建人', | |
| 105 | + F_UpdateUser VARCHAR(50) NULL COMMENT '更新人', | |
| 106 | + | |
| 107 | + -- 主键约束 | |
| 108 | + PRIMARY KEY (F_Id), | |
| 109 | + | |
| 110 | + -- 唯一索引:确保同一员工同一月份只有一条记录 | |
| 111 | + UNIQUE KEY `uk_employee_month` (F_EmployeeId, F_StatisticsMonth), | |
| 112 | + | |
| 113 | + -- 普通索引 | |
| 114 | + KEY `idx_store_id` (F_StoreId), | |
| 115 | + KEY `idx_statistics_month` (F_StatisticsMonth), | |
| 116 | + KEY `idx_employee_id` (F_EmployeeId), | |
| 117 | + KEY `idx_employee_account` (F_EmployeeAccount), | |
| 118 | + KEY `idx_store_category` (F_StoreCategory), | |
| 119 | + KEY `idx_is_terminated` (F_IsTerminated), | |
| 120 | + KEY `idx_create_time` (F_CreateTime) | |
| 121 | +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='科技部老师工资统计表'; | ... | ... |
报销退回后重新走流程-接口调用示例.md
0 → 100644
| 1 | +# 报销退回后修改并重新走流程 - 接口调用示例 | |
| 2 | + | |
| 3 | +## 前置条件 | |
| 4 | + | |
| 5 | +- 已创建报销申请并提交审批 | |
| 6 | +- 申请已被退回(状态为"已退回") | |
| 7 | +- 申请ID:`767672243453953285`(示例) | |
| 8 | +- Token:`Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`(需要替换为实际token) | |
| 9 | + | |
| 10 | +--- | |
| 11 | + | |
| 12 | +## 完整流程 | |
| 13 | + | |
| 14 | +### 步骤1:退回申请(如果还未退回) | |
| 15 | + | |
| 16 | +**接口地址:** `POST /api/Extend/LqReimbursementApplication/{id}/Actions/Approve` | |
| 17 | + | |
| 18 | +**请求参数:** | |
| 19 | +- `result`: 审批结果,值为 `退回`(需要URL编码为 `%E9%80%80%E5%9B%9E`) | |
| 20 | +- `opinion`: 退回原因 | |
| 21 | + | |
| 22 | +**cURL 示例:** | |
| 23 | +```bash | |
| 24 | +curl -X POST "http://localhost:2011/api/Extend/LqReimbursementApplication/767672243453953285/Actions/Approve?result=%E9%80%80%E5%9B%9E&opinion=%E9%9C%80%E8%A6%81%E4%BF%AE%E6%94%B9%E9%87%91%E9%A2%9D" \ | |
| 25 | + -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiJhZG1pbiIsIkFjY291bnQiOiJhZG1pbiIsIlVzZXJOYW1lIjoi566h55CG5ZGYIiwiQWRtaW5pc3RyYXRvciI6MSwiVGVuYW50SWQiOiJkYiIsIlRlbmFudERiTmFtZSI6ImxxZXJwX3Rlc3QiLCJpYXQiOjE3NjUxOTIzMDgsIm5iZiI6MTc2NTE5MjMwOCwiZXhwIjoxNzY1MjQ2MzA4LCJpc3MiOiJ5aW5tYWlzb2Z0IiwiYXVkIjoieWlubWFpc29mdCJ9.5YBxyOU5SmmIldlVp6V7uclsLrzLR8KIp51kraW7EGQ" \ | |
| 26 | + -H "Content-Type: application/json" | |
| 27 | +``` | |
| 28 | + | |
| 29 | +**返回示例:** | |
| 30 | +```json | |
| 31 | +{ | |
| 32 | + "code": 200, | |
| 33 | + "msg": "操作成功", | |
| 34 | + "data": null | |
| 35 | +} | |
| 36 | +``` | |
| 37 | + | |
| 38 | +--- | |
| 39 | + | |
| 40 | +### 步骤2:查看退回后的状态 | |
| 41 | + | |
| 42 | +**接口地址:** `GET /api/Extend/LqReimbursementApplication/{id}` | |
| 43 | + | |
| 44 | +**cURL 示例:** | |
| 45 | +```bash | |
| 46 | +curl -X GET "http://localhost:2011/api/Extend/LqReimbursementApplication/767672243453953285" \ | |
| 47 | + -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiJhZG1pbiIsIkFjY291bnQiOiJhZG1pbiIsIlVzZXJOYW1lIjoi566h55CG5ZGYIiwiQWRtaW5pc3RyYXRvciI6MSwiVGVuYW50SWQiOiJkYiIsIlRlbmFudERiTmFtZSI6ImxxZXJwX3Rlc3QiLCJpYXQiOjE3NjUxOTIzMDgsIm5iZiI6MTc2NTE5MjMwOCwiZXhwIjoxNzY1MjQ2MzA4LCJpc3MiOiJ5aW5tYWlzb2Z0IiwiYXVkIjoieWlubWFpc29mdCJ9.5YBxyOU5SmmIldlVp6V7uclsLrzLR8KIp51kraW7EGQ" \ | |
| 48 | + -H "Content-Type: application/json" | |
| 49 | +``` | |
| 50 | + | |
| 51 | +**返回示例:** | |
| 52 | +```json | |
| 53 | +{ | |
| 54 | + "code": 200, | |
| 55 | + "msg": "操作成功", | |
| 56 | + "data": { | |
| 57 | + "form": { | |
| 58 | + "id": "767672243453953285", | |
| 59 | + "applicationUserId": "admin", | |
| 60 | + "applicationUserName": "管理员", | |
| 61 | + "applicationStoreId": "1649328471923847168", | |
| 62 | + "amount": "200.00", | |
| 63 | + ... | |
| 64 | + }, | |
| 65 | + "approvalStatus": "已退回", | |
| 66 | + "currentNodeOrder": 0, | |
| 67 | + "returnedReason": "需要修改金额", | |
| 68 | + "nodes": [ | |
| 69 | + { | |
| 70 | + "nodeOrder": 1, | |
| 71 | + "nodeName": "部门经理审批", | |
| 72 | + "approvalRecords": [ | |
| 73 | + { | |
| 74 | + "approverName": "管理员", | |
| 75 | + "approvalResult": "退回", | |
| 76 | + "approvalOpinion": "需要修改金额", | |
| 77 | + "approvalTime": 1765192675000 | |
| 78 | + } | |
| 79 | + ] | |
| 80 | + } | |
| 81 | + ] | |
| 82 | + } | |
| 83 | +} | |
| 84 | +``` | |
| 85 | + | |
| 86 | +--- | |
| 87 | + | |
| 88 | +### 步骤3:修改报销单 | |
| 89 | + | |
| 90 | +**接口地址:** `PUT /api/Extend/LqReimbursementApplication/{id}` | |
| 91 | + | |
| 92 | +**请求体参数:** | |
| 93 | +```json | |
| 94 | +{ | |
| 95 | + "id": "767672243453953285", | |
| 96 | + "applicationUserId": "admin", | |
| 97 | + "applicationUserName": "管理员", | |
| 98 | + "applicationStoreId": "1649328471923847168", | |
| 99 | + "applicationTime": 1765123200000, | |
| 100 | + "amount": "300.00", | |
| 101 | + "selectedPurchaseRecordIds": [], | |
| 102 | + "purchaseRecordsId": null | |
| 103 | +} | |
| 104 | +``` | |
| 105 | + | |
| 106 | +**参数说明:** | |
| 107 | +- `id`: 申请编号(必填) | |
| 108 | +- `applicationUserId`: 申请人编号(可选,不修改可不传) | |
| 109 | +- `applicationUserName`: 申请人姓名(可选,不修改可不传) | |
| 110 | +- `applicationStoreId`: 申请门店ID(可选,不修改可不传) | |
| 111 | +- `applicationTime`: 申请时间(时间戳,可选) | |
| 112 | +- `amount`: 总金额(可选,要修改的字段) | |
| 113 | +- `selectedPurchaseRecordIds`: 选中的购买记录ID列表(可选,数组) | |
| 114 | +- `purchaseRecordsId`: 关联购买编号(可选,字符串,多个用逗号分隔) | |
| 115 | + | |
| 116 | +**cURL 示例:** | |
| 117 | +```bash | |
| 118 | +curl -X PUT "http://localhost:2011/api/Extend/LqReimbursementApplication/767672243453953285" \ | |
| 119 | + -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiJhZG1pbiIsIkFjY291bnQiOiJhZG1pbiIsIlVzZXJOYW1lIjoi566h55CG5ZGYIiwiQWRtaW5pc3RyYXRvciI6MSwiVGVuYW50SWQiOiJkYiIsIlRlbmFudERiTmFtZSI6ImxxZXJwX3Rlc3QiLCJpYXQiOjE3NjUxOTIzMDgsIm5iZiI6MTc2NTE5MjMwOCwiZXhwIjoxNzY1MjQ2MzA4LCJpc3MiOiJ5aW5tYWlzb2Z0IiwiYXVkIjoieWlubWFpc29mdCJ9.5YBxyOU5SmmIldlVp6V7uclsLrzLR8KIp51kraW7EGQ" \ | |
| 120 | + -H "Content-Type: application/json" \ | |
| 121 | + -d '{ | |
| 122 | + "id": "767672243453953285", | |
| 123 | + "amount": "300.00" | |
| 124 | + }' | |
| 125 | +``` | |
| 126 | + | |
| 127 | +**返回示例:** | |
| 128 | +```json | |
| 129 | +{ | |
| 130 | + "code": 200, | |
| 131 | + "msg": "操作成功", | |
| 132 | + "data": null | |
| 133 | +} | |
| 134 | +``` | |
| 135 | + | |
| 136 | +**注意:** | |
| 137 | +- 只有"待审批"(CurrentNodeOrder=0)或"已退回"状态的申请才能修改 | |
| 138 | +- 如果状态为"审批中"、"已通过"、"未通过",修改会被拒绝 | |
| 139 | + | |
| 140 | +--- | |
| 141 | + | |
| 142 | +### 步骤4:重新提交审批 | |
| 143 | + | |
| 144 | +**接口地址:** `POST /api/Extend/LqReimbursementApplication/{id}/Actions/SubmitApproval` | |
| 145 | + | |
| 146 | +**cURL 示例:** | |
| 147 | +```bash | |
| 148 | +curl -X POST "http://localhost:2011/api/Extend/LqReimbursementApplication/767672243453953285/Actions/SubmitApproval" \ | |
| 149 | + -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiJhZG1pbiIsIkFjY291bnQiOiJhZG1pbiIsIlVzZXJOYW1lIjoi566h55CG5ZGYIiwiQWRtaW5pc3RyYXRvciI6MSwiVGVuYW50SWQiOiJkYiIsIlRlbmFudERiTmFtZSI6ImxxZXJwX3Rlc3QiLCJpYXQiOjE3NjUxOTIzMDgsIm5iZiI6MTc2NTE5MjMwOCwiZXhwIjoxNzY1MjQ2MzA4LCJpc3MiOiJ5aW5tYWlzb2Z0IiwiYXVkIjoieWlubWFpc29mdCJ9.5YBxyOU5SmmIldlVp6V7uclsLrzLR8KIp51kraW7EGQ" \ | |
| 150 | + -H "Content-Type: application/json" | |
| 151 | +``` | |
| 152 | + | |
| 153 | +**返回示例:** | |
| 154 | +```json | |
| 155 | +{ | |
| 156 | + "code": 200, | |
| 157 | + "msg": "操作成功", | |
| 158 | + "data": null | |
| 159 | +} | |
| 160 | +``` | |
| 161 | + | |
| 162 | +**说明:** | |
| 163 | +- 重新提交审批后,会创建新的"待审批"记录 | |
| 164 | +- 之前的"退回"记录会被保留,不会删除 | |
| 165 | +- 申请状态会从"已退回"变为"审批中" | |
| 166 | + | |
| 167 | +--- | |
| 168 | + | |
| 169 | +### 步骤5:审批通过 | |
| 170 | + | |
| 171 | +**接口地址:** `POST /api/Extend/LqReimbursementApplication/{id}/Actions/Approve` | |
| 172 | + | |
| 173 | +**请求参数:** | |
| 174 | +- `result`: 审批结果,值为 `通过`(需要URL编码为 `%E9%80%9A%E8%BF%87`) | |
| 175 | +- `opinion`: 审批意见(可选) | |
| 176 | + | |
| 177 | +**cURL 示例:** | |
| 178 | +```bash | |
| 179 | +curl -X POST "http://localhost:2011/api/Extend/LqReimbursementApplication/767672243453953285/Actions/Approve?result=%E9%80%9A%E8%BF%87&opinion=%E4%BF%AE%E6%94%B9%E5%90%8E%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87" \ | |
| 180 | + -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiJhZG1pbiIsIkFjY291bnQiOiJhZG1pbiIsIlVzZXJOYW1lIjoi566h55CG5ZGYIiwiQWRtaW5pc3RyYXRvciI6MSwiVGVuYW50SWQiOiJkYiIsIlRlbmFudERiTmFtZSI6ImxxZXJwX3Rlc3QiLCJpYXQiOjE3NjUxOTIzMDgsIm5iZiI6MTc2NTE5MjMwOCwiZXhwIjoxNzY1MjQ2MzA4LCJpc3MiOiJ5aW5tYWlzb2Z0IiwiYXVkIjoieWlubWFpc29mdCJ9.5YBxyOU5SmmIldlVp6V7uclsLrzLR8KIp51kraW7EGQ" \ | |
| 181 | + -H "Content-Type: application/json" | |
| 182 | +``` | |
| 183 | + | |
| 184 | +**返回示例:** | |
| 185 | +```json | |
| 186 | +{ | |
| 187 | + "code": 200, | |
| 188 | + "msg": "操作成功", | |
| 189 | + "data": { | |
| 190 | + "approvalStatus": "已通过" | |
| 191 | + } | |
| 192 | +} | |
| 193 | +``` | |
| 194 | + | |
| 195 | +--- | |
| 196 | + | |
| 197 | +### 步骤6:查看最终状态和审批记录 | |
| 198 | + | |
| 199 | +**接口地址:** `GET /api/Extend/LqReimbursementApplication/{id}` | |
| 200 | + | |
| 201 | +**cURL 示例:** | |
| 202 | +```bash | |
| 203 | +curl -X GET "http://localhost:2011/api/Extend/LqReimbursementApplication/767672243453953285" \ | |
| 204 | + -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiJhZG1pbiIsIkFjY291bnQiOiJhZG1pbiIsIlVzZXJOYW1lIjoi566h55CG5ZGYIiwiQWRtaW5pc3RyYXRvciI6MSwiVGVuYW50SWQiOiJkYiIsIlRlbmFudERiTmFtZSI6ImxxZXJwX3Rlc3QiLCJpYXQiOjE3NjUxOTIzMDgsIm5iZiI6MTc2NTE5MjMwOCwiZXhwIjoxNzY1MjQ2MzA4LCJpc3MiOiJ5aW5tYWlzb2Z0IiwiYXVkIjoieWlubWFpc29mdCJ9.5YBxyOU5SmmIldlVp6V7uclsLrzLR8KIp51kraW7EGQ" \ | |
| 205 | + -H "Content-Type: application/json" | |
| 206 | +``` | |
| 207 | + | |
| 208 | +**返回示例:** | |
| 209 | +```json | |
| 210 | +{ | |
| 211 | + "code": 200, | |
| 212 | + "msg": "操作成功", | |
| 213 | + "data": { | |
| 214 | + "form": { | |
| 215 | + "id": "767672243453953285", | |
| 216 | + "amount": "300.00", | |
| 217 | + ... | |
| 218 | + }, | |
| 219 | + "approvalStatus": "已通过", | |
| 220 | + "currentNodeOrder": 2, | |
| 221 | + "nodes": [ | |
| 222 | + { | |
| 223 | + "nodeOrder": 1, | |
| 224 | + "nodeName": "部门经理审批", | |
| 225 | + "approvalRecords": [ | |
| 226 | + { | |
| 227 | + "approverName": "管理员", | |
| 228 | + "approvalResult": "退回", | |
| 229 | + "approvalOpinion": "需要修改金额", | |
| 230 | + "approvalTime": 1765192675000 | |
| 231 | + }, | |
| 232 | + { | |
| 233 | + "approverName": "管理员", | |
| 234 | + "approvalResult": "通过", | |
| 235 | + "approvalOpinion": "修改后审批通过", | |
| 236 | + "approvalTime": 1765192762000 | |
| 237 | + } | |
| 238 | + ] | |
| 239 | + } | |
| 240 | + ] | |
| 241 | + } | |
| 242 | +} | |
| 243 | +``` | |
| 244 | + | |
| 245 | +**说明:** | |
| 246 | +- 审批记录中包含完整的审批历史 | |
| 247 | +- "退回"记录和"通过"记录都会保留 | |
| 248 | +- 可以清楚地看到退回原因和重新审批的结果 | |
| 249 | + | |
| 250 | +--- | |
| 251 | + | |
| 252 | +## 完整流程总结 | |
| 253 | + | |
| 254 | +1. **退回申请** → 状态变为"已退回",当前节点为0 | |
| 255 | +2. **修改报销单** → 修改需要调整的字段(金额、购买记录等) | |
| 256 | +3. **重新提交审批** → 状态变为"审批中",创建新的"待审批"记录 | |
| 257 | +4. **审批通过** → 状态变为"已通过",审批记录中包含退回和通过两条记录 | |
| 258 | + | |
| 259 | +--- | |
| 260 | + | |
| 261 | +## 注意事项 | |
| 262 | + | |
| 263 | +1. **URL编码**:中文字符需要URL编码 | |
| 264 | + - `退回` → `%E9%80%80%E5%9B%9E` | |
| 265 | + - `通过` → `%E9%80%9A%E8%BF%87` | |
| 266 | + | |
| 267 | +2. **状态检查**: | |
| 268 | + - 只有"待审批"或"已退回"状态的申请才能修改 | |
| 269 | + - 只有"审批中"状态的申请才能进行审批操作 | |
| 270 | + | |
| 271 | +3. **审批记录**: | |
| 272 | + - 退回记录会被保留,不会删除 | |
| 273 | + - 重新提交审批后会创建新的"待审批"记录 | |
| 274 | + - 审批记录按时间顺序显示,包含完整的审批历史 | |
| 275 | + | |
| 276 | +4. **Token**:所有接口都需要在Header中携带有效的Authorization Token | |
| 277 | + | |
| 278 | +--- | |
| 279 | + | |
| 280 | +## JavaScript/Axios 示例 | |
| 281 | + | |
| 282 | +```javascript | |
| 283 | +const axios = require('axios'); | |
| 284 | +const BASE_URL = 'http://localhost:2011'; | |
| 285 | +const TOKEN = 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'; | |
| 286 | +const APPLICATION_ID = '767672243453953285'; | |
| 287 | + | |
| 288 | +// 1. 退回申请 | |
| 289 | +async function returnApplication() { | |
| 290 | + const response = await axios.post( | |
| 291 | + `${BASE_URL}/api/Extend/LqReimbursementApplication/${APPLICATION_ID}/Actions/Approve`, | |
| 292 | + null, | |
| 293 | + { | |
| 294 | + headers: { Authorization: TOKEN }, | |
| 295 | + params: { | |
| 296 | + result: '退回', | |
| 297 | + opinion: '需要修改金额' | |
| 298 | + } | |
| 299 | + } | |
| 300 | + ); | |
| 301 | + return response.data; | |
| 302 | +} | |
| 303 | + | |
| 304 | +// 2. 修改报销单 | |
| 305 | +async function updateApplication() { | |
| 306 | + const response = await axios.put( | |
| 307 | + `${BASE_URL}/api/Extend/LqReimbursementApplication/${APPLICATION_ID}`, | |
| 308 | + { | |
| 309 | + id: APPLICATION_ID, | |
| 310 | + amount: '300.00' | |
| 311 | + }, | |
| 312 | + { | |
| 313 | + headers: { Authorization: TOKEN } | |
| 314 | + } | |
| 315 | + ); | |
| 316 | + return response.data; | |
| 317 | +} | |
| 318 | + | |
| 319 | +// 3. 重新提交审批 | |
| 320 | +async function resubmitApproval() { | |
| 321 | + const response = await axios.post( | |
| 322 | + `${BASE_URL}/api/Extend/LqReimbursementApplication/${APPLICATION_ID}/Actions/SubmitApproval`, | |
| 323 | + null, | |
| 324 | + { | |
| 325 | + headers: { Authorization: TOKEN } | |
| 326 | + } | |
| 327 | + ); | |
| 328 | + return response.data; | |
| 329 | +} | |
| 330 | + | |
| 331 | +// 4. 审批通过 | |
| 332 | +async function approveApplication() { | |
| 333 | + const response = await axios.post( | |
| 334 | + `${BASE_URL}/api/Extend/LqReimbursementApplication/${APPLICATION_ID}/Actions/Approve`, | |
| 335 | + null, | |
| 336 | + { | |
| 337 | + headers: { Authorization: TOKEN }, | |
| 338 | + params: { | |
| 339 | + result: '通过', | |
| 340 | + opinion: '修改后审批通过' | |
| 341 | + } | |
| 342 | + } | |
| 343 | + ); | |
| 344 | + return response.data; | |
| 345 | +} | |
| 346 | + | |
| 347 | +// 完整流程 | |
| 348 | +async function completeFlow() { | |
| 349 | + try { | |
| 350 | + // 1. 退回 | |
| 351 | + await returnApplication(); | |
| 352 | + console.log('✅ 申请已退回'); | |
| 353 | + | |
| 354 | + // 2. 修改 | |
| 355 | + await updateApplication(); | |
| 356 | + console.log('✅ 申请已修改'); | |
| 357 | + | |
| 358 | + // 3. 重新提交 | |
| 359 | + await resubmitApproval(); | |
| 360 | + console.log('✅ 已重新提交审批'); | |
| 361 | + | |
| 362 | + // 4. 审批通过 | |
| 363 | + await approveApplication(); | |
| 364 | + console.log('✅ 审批已通过'); | |
| 365 | + | |
| 366 | + } catch (error) { | |
| 367 | + console.error('❌ 流程执行失败:', error.response?.data || error.message); | |
| 368 | + } | |
| 369 | +} | |
| 370 | +``` | |
| 371 | + | ... | ... |
科技部老师工资计算规则.md
0 → 100644
| 1 | +# 科技部老师工资计算规则 | |
| 2 | + | |
| 3 | +## 📋 目录 | |
| 4 | +- [计算规则](#计算规则) | |
| 5 | +- [数据来源](#数据来源) | |
| 6 | +- [特殊规则](#特殊规则) | |
| 7 | +- [计算流程](#计算流程) | |
| 8 | + | |
| 9 | +--- | |
| 10 | + | |
| 11 | +## 💰 计算规则 | |
| 12 | + | |
| 13 | +### 1. 底薪规则(分三档) | |
| 14 | + | |
| 15 | +底薪根据**项目数**和**总业绩**两个条件同时满足来确定档位: | |
| 16 | + | |
| 17 | +| 档位 | 项目数要求 | 总业绩要求 | 底薪金额 | | |
| 18 | +|------|-----------|-----------|---------| | |
| 19 | +| **第一档** | ≥ 80个 | ≥ 40,000元 | 2,500元 | | |
| 20 | +| **第二档** | ≥ 95个 | ≥ 80,000元 | 3,000元 | | |
| 21 | +| **第三档** | ≥ 110个 | ≥ 100,000元 | 3,500元 | | |
| 22 | +| **最低档** | 不满足第一档条件 | - | 2,500元(默认第一档) | | |
| 23 | + | |
| 24 | +**计算逻辑**: | |
| 25 | +- 从高到低判断,同时满足项目数和总业绩两个条件才能获得对应档位底薪 | |
| 26 | +- 如果都不满足,默认使用第一档(2,500元) | |
| 27 | + | |
| 28 | +--- | |
| 29 | + | |
| 30 | +### 2. 业绩提成规则 | |
| 31 | + | |
| 32 | +业绩提成基于**总业绩**计算,采用分段累进方式: | |
| 33 | + | |
| 34 | +| 总业绩范围 | 提成比例 | | |
| 35 | +|-----------|---------| | |
| 36 | +| < 10,000元 | 0% (无提成) | | |
| 37 | +| 10,000元 - 70,000元 | 2% | | |
| 38 | +| 70,000元 - 150,000元 | 2.5% | | |
| 39 | +| > 150,000元 | 3% | | |
| 40 | + | |
| 41 | +**计算说明**: | |
| 42 | +- 提成金额 = 总业绩 × 对应提成比例 | |
| 43 | +- 采用分段计算,不同区间按不同比例计算 | |
| 44 | + | |
| 45 | +--- | |
| 46 | + | |
| 47 | +### 3. 消耗提成规则 | |
| 48 | + | |
| 49 | +消耗提成基于**消耗业绩**计算,包含扣除机制: | |
| 50 | + | |
| 51 | +| 消耗业绩范围 | 提成规则 | | |
| 52 | +|------------|---------| | |
| 53 | +| < 80,000元 | **扣除300元**(负提成) | | |
| 54 | +| 80,000元 - 100,000元 | 0.5% 提成 | | |
| 55 | +| 100,000元 - 200,000元 | 0.5% 提成 | | |
| 56 | +| > 200,000元 | 1% 提成 | | |
| 57 | + | |
| 58 | +**重要说明**: | |
| 59 | +- 当消耗业绩 < 80,000元时,不是无提成,而是**直接扣除300元工资** | |
| 60 | +- 消耗提成金额可能为负数(扣除情况) | |
| 61 | + | |
| 62 | +--- | |
| 63 | + | |
| 64 | +## 📊 数据来源 | |
| 65 | + | |
| 66 | +### 总业绩(TotalPerformance) | |
| 67 | + | |
| 68 | +**定义**:开单业绩 + 消耗业绩 + 退卡业绩 | |
| 69 | + | |
| 70 | +**数据来源表及字段**: | |
| 71 | + | |
| 72 | +| 业绩类型 | 数据表 | 字段 | 说明 | | |
| 73 | +|---------|--------|------|------| | |
| 74 | +| **开单业绩** | `lq_kd_kjbsyj` | `kjblsyj` | 科技部老师开单业绩 | | |
| 75 | +| **消耗业绩** | `lq_xh_kjbsyj` | `kjblsyj` | 科技部老师消耗业绩 | | |
| 76 | +| **退卡业绩** | `lq_hytk_kjbsyj` | `kjblsyj` | 科技部老师退卡业绩 | | |
| 77 | + | |
| 78 | +**计算方式**: | |
| 79 | +```sql | |
| 80 | +总业绩 = SUM(开单业绩) + SUM(消耗业绩) + SUM(退卡业绩) | |
| 81 | +``` | |
| 82 | + | |
| 83 | +**过滤条件**: | |
| 84 | +- 所有表记录必须满足:`F_IsEffective = 1`(有效记录) | |
| 85 | +- 按统计月份(YYYYMM格式)过滤时间范围 | |
| 86 | +- 按科技老师ID(`kjblszh` 或 `kjbls`)关联 | |
| 87 | + | |
| 88 | +--- | |
| 89 | + | |
| 90 | +### 消耗(ConsumeAchievement) | |
| 91 | + | |
| 92 | +**定义**:科技部老师在耗卡记录中的业绩总和 | |
| 93 | + | |
| 94 | +**数据来源**: | |
| 95 | +- **表名**:`lq_xh_kjbsyj`(耗卡科技部老师业绩表) | |
| 96 | +- **字段**:`kjblsyj`(科技部老师业绩) | |
| 97 | +- **关联表**:`lq_xh_hyhk`(耗卡主表,用于时间过滤) | |
| 98 | + | |
| 99 | +**计算方式**: | |
| 100 | +```sql | |
| 101 | +消耗 = SUM(lq_xh_kjbsyj.kjblsyj) | |
| 102 | +WHERE lq_xh_kjbsyj.F_IsEffective = 1 | |
| 103 | + AND lq_xh_hyhk.F_IsEffective = 1 | |
| 104 | + AND DATE_FORMAT(lq_xh_hyhk.hksj, '%Y%m') = @统计月份 | |
| 105 | + AND lq_xh_kjbsyj.kjblszh = @科技老师账号 | |
| 106 | +``` | |
| 107 | + | |
| 108 | +**对应实体字段**: | |
| 109 | +- `LqTechTeacherSalaryStatisticsEntity.F_ConsumeAchievement` | |
| 110 | + | |
| 111 | +--- | |
| 112 | + | |
| 113 | +### 项目数(ProjectCount) | |
| 114 | + | |
| 115 | +**定义**:科技部老师在耗卡记录中的项目次数总和 | |
| 116 | + | |
| 117 | +**数据来源**: | |
| 118 | +- **表名**:`lq_xh_kjbsyj`(耗卡科技部老师业绩表) | |
| 119 | +- **字段**:`F_hdpxNumber`(耗卡品项次数) | |
| 120 | +- **关联表**:`lq_xh_hyhk`(耗卡主表,用于时间过滤) | |
| 121 | + | |
| 122 | +**计算方式**: | |
| 123 | +```sql | |
| 124 | +项目数 = SUM(lq_xh_kjbsyj.F_hdpxNumber) | |
| 125 | +WHERE lq_xh_kjbsyj.F_IsEffective = 1 | |
| 126 | + AND lq_xh_hyhk.F_IsEffective = 1 | |
| 127 | + AND DATE_FORMAT(lq_xh_hyhk.hksj, '%Y%m') = @统计月份 | |
| 128 | + AND lq_xh_kjbsyj.kjblszh = @科技老师账号 | |
| 129 | +``` | |
| 130 | + | |
| 131 | +**对应实体字段**: | |
| 132 | +- `LqTechTeacherSalaryStatisticsEntity.F_ProjectCount` | |
| 133 | + | |
| 134 | +--- | |
| 135 | + | |
| 136 | +## ⚠️ 特殊规则 | |
| 137 | + | |
| 138 | +### 离职员工规则 | |
| 139 | + | |
| 140 | +**适用条件**: | |
| 141 | +- 员工状态:`BASE_USER.F_IsOnJob = 0`(离职) | |
| 142 | + | |
| 143 | +**计算规则**: | |
| 144 | +- 如果离职员工当月**总业绩 > 30,000元**: | |
| 145 | + - **提成**:总业绩 × 2% | |
| 146 | + - **无底薪**:不计算底薪 | |
| 147 | + - **无奖励**:不计算任何奖励 | |
| 148 | + - **无消耗提成**:不计算消耗提成 | |
| 149 | +- 如果离职员工当月总业绩 ≤ 30,000元: | |
| 150 | + - 无任何工资 | |
| 151 | + | |
| 152 | +**记录标识**: | |
| 153 | +- 在 `LqTechTeacherSalaryStatisticsEntity.F_IsTerminated` 字段中记录: | |
| 154 | + - `0` = 在职 | |
| 155 | + - `1` = 离职 | |
| 156 | + | |
| 157 | +**重要说明**: | |
| 158 | +- 离职员工规则优先级最高,一旦判定为离职且业绩>3万,只按2%提成计算,其他规则不适用 | |
| 159 | + | |
| 160 | +--- | |
| 161 | + | |
| 162 | +## 🔄 计算流程 | |
| 163 | + | |
| 164 | +### 步骤1:识别科技部老师 | |
| 165 | +- 从 `BASE_USER` 表中筛选:`Gw == "科技老师"` 且 `DeleteMark == null` 且 `EnabledMark == 1` | |
| 166 | + | |
| 167 | +### 步骤2:判断是否离职 | |
| 168 | +- 检查 `BASE_USER.F_IsOnJob`: | |
| 169 | + - `F_IsOnJob == 0` → 离职员工 | |
| 170 | + - `F_IsOnJob == 1` → 在职员工 | |
| 171 | + | |
| 172 | +### 步骤3:数据汇总(在职员工) | |
| 173 | +- 查询开单业绩:从 `lq_kd_kjbsyj` 表汇总 `kjblsyj` | |
| 174 | +- 查询消耗业绩:从 `lq_xh_kjbsyj` 表汇总 `kjblsyj` | |
| 175 | +- 查询退卡业绩:从 `lq_hytk_kjbsyj` 表汇总 `kjblsyj` | |
| 176 | +- 查询项目数:从 `lq_xh_kjbsyj` 表汇总 `F_hdpxNumber` | |
| 177 | +- 计算总业绩:开单业绩 + 消耗业绩 + 退卡业绩 | |
| 178 | + | |
| 179 | +### 步骤4:工资计算(在职员工) | |
| 180 | + | |
| 181 | +#### 4.1 计算底薪 | |
| 182 | +- 根据项目数和总业绩,从高到低判断档位: | |
| 183 | + - 同时满足第三档条件 → 底薪 3,500元 | |
| 184 | + - 同时满足第二档条件 → 底薪 3,000元 | |
| 185 | + - 同时满足第一档条件 → 底薪 2,500元 | |
| 186 | + - 都不满足 → 默认第一档 2,500元 | |
| 187 | + | |
| 188 | +#### 4.2 计算业绩提成 | |
| 189 | +- 根据总业绩范围确定提成比例: | |
| 190 | + - < 10,000元 → 0% | |
| 191 | + - 10,000-70,000元 → 2% | |
| 192 | + - 70,000-150,000元 → 2.5% | |
| 193 | + - > 150,000元 → 3% | |
| 194 | +- 业绩提成金额 = 总业绩 × 提成比例 | |
| 195 | + | |
| 196 | +#### 4.3 计算消耗提成 | |
| 197 | +- 根据消耗业绩范围确定提成规则: | |
| 198 | + - < 80,000元 → 扣除300元(负数) | |
| 199 | + - 80,000-100,000元 → 0.5% | |
| 200 | + - 100,000-200,000元 → 0.5% | |
| 201 | + - > 200,000元 → 1% | |
| 202 | +- 消耗提成金额 = 消耗业绩 × 提成比例(或直接扣除300元) | |
| 203 | + | |
| 204 | +### 步骤5:工资计算(离职员工) | |
| 205 | +- 如果总业绩 > 30,000元: | |
| 206 | + - 底薪 = 0 | |
| 207 | + - 业绩提成 = 总业绩 × 2% | |
| 208 | + - 消耗提成 = 0 | |
| 209 | + - 奖励 = 0 | |
| 210 | +- 如果总业绩 ≤ 30,000元: | |
| 211 | + - 所有工资项 = 0 | |
| 212 | + | |
| 213 | +### 步骤6:保存结果 | |
| 214 | +- 将计算结果保存到 `lq_tech_teacher_salary_statistics` 表 | |
| 215 | +- 记录 `F_IsTerminated` 字段标识是否离职 | |
| 216 | + | |
| 217 | +--- | |
| 218 | + | |
| 219 | +## 📝 数据表结构 | |
| 220 | + | |
| 221 | +### 主表:`lq_tech_teacher_salary_statistics` | |
| 222 | + | |
| 223 | +**关键字段说明**: | |
| 224 | + | |
| 225 | +| 字段名 | 说明 | 数据来源 | | |
| 226 | +|--------|------|---------| | |
| 227 | +| `F_StatisticsMonth` | 统计月份(YYYYMM) | 计算参数 | | |
| 228 | +| `F_EmployeeId` | 员工ID | `BASE_USER.F_Id` | | |
| 229 | +| `F_EmployeeAccount` | 员工账号 | `BASE_USER.F_Account` | | |
| 230 | +| `F_EmployeeName` | 员工姓名 | `BASE_USER.F_RealName` | | |
| 231 | +| `F_StoreId` | 门店ID | `lq_mdxx.F_Id` | | |
| 232 | +| `F_StoreName` | 门店名称 | `lq_mdxx.dm` | | |
| 233 | +| `F_TotalPerformance` | 总业绩 | 计算得出 | | |
| 234 | +| `F_ConsumeAchievement` | 消耗业绩 | `lq_xh_kjbsyj.kjblsyj` | | |
| 235 | +| `F_ProjectCount` | 项目数 | `lq_xh_kjbsyj.F_hdpxNumber` | | |
| 236 | +| `F_BaseSalary` | 底薪 | 根据规则计算 | | |
| 237 | +| `F_PerformanceCommissionAmount` | 业绩提成金额 | 根据规则计算 | | |
| 238 | +| `F_ConsumeCommissionAmount` | 消耗提成金额 | 根据规则计算(可能为负数) | | |
| 239 | +| `F_IsTerminated` | 是否离职(0=在职,1=离职) | `BASE_USER.F_IsOnJob` | | |
| 240 | + | |
| 241 | +--- | |
| 242 | + | |
| 243 | +## 🔍 查询示例 | |
| 244 | + | |
| 245 | +### 查询科技部老师消耗数据(参考 `LqStatisticsService.GetTechTeacherStatistics`) | |
| 246 | + | |
| 247 | +```sql | |
| 248 | +-- 消耗业绩和项目数查询 | |
| 249 | +SELECT | |
| 250 | + kjbsyj.kjblszh as F_UserId, | |
| 251 | + kjbsyj.kjblsxm as F_UserName, | |
| 252 | + hyhk.md as F_StoreId, | |
| 253 | + md.dm as F_StoreName, | |
| 254 | + @statisticsMonth as F_StatisticsMonth, | |
| 255 | + COALESCE(SUM(kjbsyj.kjblsyj), 0) as F_ConsumePerformance, -- 消耗业绩 | |
| 256 | + COALESCE(SUM(kjbsyj.F_hdpxNumber), 0) as F_ConsumeQuantity, -- 项目数 | |
| 257 | + COALESCE(SUM(kjbsyj.F_LaborCost), 0) as F_ManualFee | |
| 258 | +FROM lq_xh_kjbsyj kjbsyj | |
| 259 | +INNER JOIN lq_xh_hyhk hyhk ON kjbsyj.glkdbh = hyhk.F_Id AND hyhk.F_IsEffective = 1 | |
| 260 | +LEFT JOIN lq_mdxx md ON hyhk.md = md.F_Id | |
| 261 | +WHERE kjbsyj.F_IsEffective = 1 | |
| 262 | + AND DATE_FORMAT(hyhk.hksj, '%Y%m') = @statisticsMonth | |
| 263 | +GROUP BY kjbsyj.kjblszh, kjbsyj.kjblsxm, hyhk.md, md.mdbm, md.dm | |
| 264 | +``` | |
| 265 | + | |
| 266 | +--- | |
| 267 | + | |
| 268 | +## ✅ 验证要点 | |
| 269 | + | |
| 270 | +1. **数据准确性**: | |
| 271 | + - 确保所有业绩数据来自有效记录(`F_IsEffective = 1`) | |
| 272 | + - 确保时间范围正确(按月份YYYYMM格式) | |
| 273 | + | |
| 274 | +2. **计算逻辑**: | |
| 275 | + - 底薪档位判断必须同时满足项目数和总业绩两个条件 | |
| 276 | + - 消耗提成 < 80,000元时是扣除300元,不是0 | |
| 277 | + - 离职员工规则优先级最高 | |
| 278 | + | |
| 279 | +3. **数据一致性**: | |
| 280 | + - 总业绩 = 开单业绩 + 消耗业绩 + 退卡业绩 | |
| 281 | + - 消耗和项目数必须来自同一数据源(`lq_xh_kjbsyj`) | |
| 282 | + | |
| 283 | +--- | |
| 284 | + | |
| 285 | +## 📌 注意事项 | |
| 286 | + | |
| 287 | +1. **离职员工处理**: | |
| 288 | + - 必须先判断 `F_IsOnJob`,离职员工走特殊逻辑 | |
| 289 | + - 离职员工不计算底薪和消耗提成 | |
| 290 | + | |
| 291 | +2. **消耗提成扣除**: | |
| 292 | + - 消耗 < 80,000元时,`F_ConsumeCommissionAmount` 字段值为 `-300`(负数) | |
| 293 | + | |
| 294 | +3. **数据汇总**: | |
| 295 | + - 同一科技部老师可能在不同门店有数据,需要按门店分别计算 | |
| 296 | + - 或者按科技部老师汇总所有门店数据(根据业务需求) | |
| 297 | + | |
| 298 | +4. **月份格式**: | |
| 299 | + - 统计月份统一使用 `YYYYMM` 格式(如:202501) | |
| 300 | + | |
| 301 | +--- | |
| 302 | + | |
| 303 | +## 🔗 相关文件 | |
| 304 | + | |
| 305 | +- **实体类**:`LqTechTeacherSalaryStatisticsEntity.cs` | |
| 306 | +- **薪酬规则文档**:`项目信息-薪酬规则与名词解释.md` | |
| 307 | +- **参考服务**:`LqSalaryService.cs`(健康师工资计算)、`LqAssistantSalaryService.cs`(店助工资计算) | |
| 308 | +- **统计数据服务**:`LqStatisticsService.GetTechTeacherStatistics`(科技部老师业绩统计) | ... | ... |