From 38c6f7308c1dd22a8ea286c3ea1de3a4e714f78f Mon Sep 17 00:00:00 2001
From: yinbentan <yinbentan@live.com>
Date: 星期五, 02 八月 2024 16:44:51 +0800
Subject: [PATCH] BUG修复,新的工资计算方式添加遗漏的“考勤及补贴数据”(工作日加班时长、休息日加班时长、带徒天数、满勤奖、请假天数、工龄)

---
 utils/timex.go         |   27 +++++++++++++
 service/salary_plan.go |   88 +++++++++++++++++++++++++++++++++++--------
 2 files changed, 97 insertions(+), 18 deletions(-)

diff --git a/service/salary_plan.go b/service/salary_plan.go
index d93c850..5c6c3b1 100644
--- a/service/salary_plan.go
+++ b/service/salary_plan.go
@@ -9,13 +9,19 @@
 	"silkserver/constvar"
 	"silkserver/models"
 	"silkserver/pkg/logx"
+	"silkserver/utils"
 	"silkserver/utils/calculator"
 	"strconv"
 	"strings"
+	"time"
 )
 
 // WorkingHours 瀛樿〃锛氬伐鏃惰绠楋紙鏃ユ湡锛堝勾鏈堟棩锛夈�佸伐绉嶃�佸憳宸ュ鍚嶃�佸皬缁勩�佽溅鍙般�佷骇閲忓伐璧勩�佷笂鐝秴鏃讹紙灏忔椂锛夈�佷笂鐝秴鏃讹紙澶╋級銆佸姞鐝紙鍗曠嫭锛夈�佸姞鐝紙鍏ㄨ溅闂达級銆佸嚭鍕わ紙澶╋級銆佸甫寰掞紙澶╋級銆佷骇閲忥紙KG锛夈�佸叾瀹冿級
 func WorkingHours(date string) error {
+	dateTime, err := time.Parse("2006-01-02", date)
+	if err != nil {
+		return err
+	}
 	// 浜哄憳淇℃伅
 	workers, err := models.NewWorkerSearch().FindNotTotal()
 	if err != nil {
@@ -59,8 +65,13 @@
 				}
 				workingHours.ShiftClockInTime = attendance.StartWorkTime
 				workingHours.ShiftClockOutTime = attendance.EndWorkTime
-				workingHours.OvertimeType = constvar.ShiftOvertimeTypeTimeout
-				workingHours.OvertimeDuration = attendance.OverTimeDuration
+				if dateTime.Weekday() == 0 {
+					workingHours.OvertimeType = constvar.ShiftOvertimeTypeOvertime
+					workingHours.OvertimeDuration = decimal.NewFromInt32(1)
+				} else {
+					workingHours.OvertimeType = constvar.ShiftOvertimeTypeTimeout
+					workingHours.OvertimeDuration = attendance.OverTimeDuration
+				}
 			}
 		}
 		for _, position := range workerPositions {
@@ -456,7 +467,15 @@
 
 	GroupCarHeadAvgAmount decimal.Decimal // 鍚岀粍杞﹀ご宸ュ伐璧�
 	GroupWeaversAvgAmount decimal.Decimal // 鍚岀粍鎸¤溅宸ユ湀骞冲潎宸ヨ祫
-	JobDays               decimal.Decimal // 鍑哄嫟澶╂暟
+	WorkingDay            decimal.Decimal // 涓�涓湀宸ヤ綔澶╂暟
+	JobDays               decimal.Decimal // 涓�涓湀鍑哄嫟澶╂暟
+
+	ShiftTimeout        decimal.Decimal // 宸ヤ綔鏃ュ姞鐝椂闀匡紙灏忔椂锛�
+	ShiftOvertime       decimal.Decimal // 浼戞伅鏃ュ姞鐝椂闀匡紙澶╋級
+	MentorDays          decimal.Decimal // 甯﹀緬澶╂暟
+	FullAttendanceAward decimal.Decimal // 婊″嫟濂�
+	LeaveDays           decimal.Decimal // 璇峰亣澶╂暟
+	Seniority           decimal.Decimal // 宸ラ緞
 }
 
 // SalaryPlan 鐢熶骇宸ヨ祫璁$畻
@@ -465,6 +484,10 @@
 		return errors.New("璇蜂紶鍏ユ纭殑鏌ヨ鏃堕棿锛�")
 	} else {
 		date = date[:7]
+	}
+	dateTime, err := time.Parse("2006-01", date)
+	if err != nil {
+		return err
 	}
 
 	hours, err := models.NewPayrollWorkingHoursSearch().SetOrder("worker_id").SetMonthly(date).FindNotTotal() // 鍛樺伐鐨勫伐鏃剁粺璁�
@@ -475,15 +498,28 @@
 		return errors.New(date + ":鍛樺伐鎵撳崱淇℃伅涓虹┖")
 	}
 
-	jobQuantityMap := make(map[string]int) // 鍛樺伐鍑哄嫟缁熻
+	jobQuantityMap := make(map[string]int)
+	shiftTimeoutMap := make(map[string]decimal.Decimal)
+	shiftOvertimeMap := make(map[string]decimal.Decimal)
 	for _, hour := range hours {
 		jobQuantityMap[hour.WorkerID] += 1
+		if hour.OvertimeType == constvar.ShiftOvertimeTypeOvertime {
+			shiftOvertimeMap[hour.WorkerID] = hour.OvertimeDuration.Add(shiftOvertimeMap[hour.WorkerID])
+		} else if hour.OvertimeType == constvar.ShiftOvertimeTypeTimeout {
+			shiftTimeoutMap[hour.WorkerID] = hour.OvertimeDuration.Add(shiftTimeoutMap[hour.WorkerID])
+		}
 	}
 
-	workers, err := models.NewWorkerSearch().FindNotTotal()
+	workers, _ := models.NewWorkerSearch().FindNotTotal()
 	workerMap := make(map[string]*models.Worker)
 	for _, worker := range workers {
 		workerMap[worker.ID] = worker
+	}
+
+	mentors, _ := models.NewMentorSearch().SetMonth(date).FindNotTotal()
+	mentorMap := make(map[string]int)
+	for _, mentor := range mentors {
+		mentorMap[mentor.WorkerId] = mentor.Days
 	}
 
 	// 鎸¤溅宸ュ伐璧�
@@ -648,24 +684,35 @@
 			CreatedBy: "auto",
 		}
 
-		monthKey := fmt.Sprintf("%v%v", worker.ShopNumber, worker.GroupNumber)
-		fallingSilkBucket := decimal.NewFromInt(0)
-		finishTotalAvgAmount := decimal.NewFromInt(0)
-		if group, ok := groupByMonthMap[monthKey]; ok {
-			fallingSilkBucket = group.FallingSilkBucket
-			finishTotalAvgAmount = group.FinishTotalAvgAmount
-		}
+		firstDay, lastDay := utils.GetLastMonthPeriod(dateTime)
+		_, days := utils.CalcWorkHour(firstDay, lastDay, []time.Weekday{time.Sunday}, 12.0)
 		parameter := SalaryParameter{
-			FallingSilkBucket:     fallingSilkBucket,
-			GroupWeaversAvgAmount: finishTotalAvgAmount,
-			GroupCarHeadAvgAmount: finishTotalAvgAmount.Div(ready70),
-			JobDays:               decimal.NewFromInt32(int32(dayCount)),
+			WorkingDay:          decimal.NewFromInt32(int32(days)),
+			JobDays:             decimal.NewFromInt32(int32(dayCount)),
+			FullAttendanceAward: decimal.NewFromInt32(0), // 婊″嫟濂�
+			LeaveDays:           decimal.NewFromInt32(0), // 璇峰亣澶╂暟
+			Seniority:           decimal.NewFromInt32(0), // 宸ラ緞
+		}
+		monthKey := fmt.Sprintf("%v%v", worker.ShopNumber, worker.GroupNumber)
+		if group, ok := groupByMonthMap[monthKey]; ok {
+			parameter.FallingSilkBucket = group.FallingSilkBucket
+			parameter.GroupWeaversAvgAmount = group.FinishTotalAvgAmount
+			parameter.GroupCarHeadAvgAmount = group.FinishTotalAvgAmount.Div(ready70)
+		}
+		if timeout, ok := shiftTimeoutMap[hourId]; ok {
+			parameter.ShiftTimeout = timeout
+		}
+		if overtime, ok := shiftOvertimeMap[hourId]; ok {
+			parameter.ShiftOvertime = overtime
+		}
+		if mentorDays, ok := mentorMap[hourId]; ok {
+			parameter.MentorDays = decimal.NewFromInt32(int32(mentorDays))
 		}
 
 		// 鎸夋湀绠楋細鍚岀粍鎸¤溅宸ユ湀骞冲潎宸ヨ祫銆佸悓缁勮溅澶村伐宸ヨ祫銆佸嚭鍕ゅぉ鏁�
 		if workType, ok := salaryPlansMap[worker.WorkTypeId]; ok {
 			for _, salaryPlan := range workType.SalaryPlans {
-				if matched, _ := regexp.MatchString("(鍚岀粍鎸¤溅宸ユ湀骞冲潎宸ヨ祫)|(鍚岀粍杞﹀ご宸ュ伐璧�)|(鍑哄嫟澶╂暟)", salaryPlan.SalaryFormula); matched {
+				if matched, _ := regexp.MatchString("(鍚岀粍鎸¤溅宸ユ湀骞冲潎宸ヨ祫)|(鍚岀粍杞﹀ご宸ュ伐璧�)|(鍑哄嫟澶╂暟)|(宸ヤ綔鏃ュ姞鐝椂闀�)|(浼戞伅鏃ュ姞鐝椂闀�)|(甯﹀緬澶╂暟)|(婊″嫟濂�)|(璇峰亣澶╂暟)|(宸ラ緞)", salaryPlan.SalaryFormula); matched {
 					temp := constitute
 					formula, s := salaryCalculate(&parameter, salaryPlan)
 					temp.SalaryFormula = formula
@@ -710,6 +757,13 @@
 	formula = strings.Replace(formula, "鍚岀粍杞﹀ご宸ュ伐璧�", parameter.GroupCarHeadAvgAmount.String(), -1)
 	formula = strings.Replace(formula, "鍑哄嫟澶╂暟", parameter.JobDays.String(), -1)
 
+	formula = strings.Replace(formula, "宸ヤ綔鏃ュ姞鐝椂闀�", parameter.ShiftTimeout.String(), -1)
+	formula = strings.Replace(formula, "浼戞伅鏃ュ姞鐝椂闀�", parameter.ShiftOvertime.String(), -1)
+	formula = strings.Replace(formula, "甯﹀緬澶╂暟", parameter.MentorDays.String(), -1)
+	formula = strings.Replace(formula, "婊″嫟濂�", parameter.FullAttendanceAward.String(), -1)
+	formula = strings.Replace(formula, "璇峰亣澶╂暟", parameter.LeaveDays.String(), -1)
+	formula = strings.Replace(formula, "宸ラ緞", parameter.Seniority.String(), -1)
+
 	logx.Debugf("salary formula: %v", formula)
 
 	result, err := calculator.ParseAndExec(formula)
diff --git a/utils/timex.go b/utils/timex.go
index 98ca7b1..75ac954 100644
--- a/utils/timex.go
+++ b/utils/timex.go
@@ -1,6 +1,9 @@
 package utils
 
-import "time"
+import (
+	"slices"
+	"time"
+)
 
 // IsOverlap 鍒ゆ柇涓や釜鏃堕棿娈垫槸鍚︽湁閲嶅彔
 func IsOverlap(start1, end1, start2, end2 string) bool {
@@ -22,6 +25,10 @@
 	return time.Now().AddDate(0, offset, 0)
 }
 
+func GetDayByOffset(offset int) time.Time {
+	return time.Now().AddDate(0, 0, offset)
+}
+
 // GetLastMonthPeriod 杩斿洖涓婁釜鏈堢殑鏈堝垵鏃堕棿鍜屾湀鏈椂闂�
 func GetLastMonthPeriod(now time.Time) (firstDay time.Time, lastDay time.Time) {
 	// 鑾峰彇鏈釜鏈堢殑绗竴澶╃殑鏃ユ湡锛堝嵆鏈湀鏈堝垵锛�
@@ -40,3 +47,21 @@
 func GetMonthDuration(d time.Time) (duration int) {
 	return d.AddDate(0, 1, -1).Day()
 }
+
+func CalcWorkHour(begin, end time.Time, dayOff []time.Weekday, cellHour float32) (workHour float32, workingCount int) {
+	var currentTime = begin
+	for {
+		if currentTime.After(end) {
+			break
+		}
+		if slices.Contains(dayOff, currentTime.Weekday()) {
+			// nothing
+		} else {
+			workHour += cellHour
+			workingCount++
+		}
+		currentTime = currentTime.AddDate(0, 0, 1) // .Add(24 * time.Hour)
+	}
+
+	return float32(workHour), workingCount
+}

--
Gitblit v1.8.0