import_attendance.go 9.3 KB
package service

import (
	"errors"
	"strconv"
	"strings"
	"time"

	"github.com/linmadan/egglib-go/core/application"
	"github.com/linmadan/egglib-go/utils/excel"
	"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/application/ecelData/command"
	"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/application/factory"
	"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/domain"
	"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/infrastructure/utils/converter"
)

type importAttendance struct {
	ProductDate    string `json:"productDate"`    //日期
	WorkshopName   string `json:"workshopName"`   //车间名称
	LineName       string `json:"lineName"`       //线别名称
	SectionName    string `json:"sectionName"`    //工位名称
	WorkerName     string `json:"workerName"`     //工人姓名
	AttendanceType string `json:"attendanceType"` //考勤类型 正常 支援
	SignIn         string `json:"signIn"`         //上岗时间
	SignOut        string `json:"signOut"`        //离岗时间
	BreakTime      string `json:"breakTime"`      //休息时间
	FailReason     string `json:"failReason"`     //数据校验失败的理由
}

func (data *importAttendance) validField() error {
	if len(data.ProductDate) == 0 {
		return errors.New("日期未填写。")
	}
	if len(data.WorkerName) == 0 {
		return errors.New("车间名称未填写。")
	}
	if len(data.LineName) == 0 {
		return errors.New("线别名称未填写。")
	}
	if len(data.SectionName) == 0 {
		return errors.New("工位名称未填写。")
	}
	if len(data.WorkerName) == 0 {
		return errors.New("工人姓名未填写。")
	}
	if len(data.AttendanceType) == 0 {
		return errors.New("类型未填写。")
	}
	if len(data.SignIn) == 0 {
		return errors.New("上岗时间未填写。")
	}
	if len(data.SignOut) == 0 {
		return errors.New("下岗时间未填写。")
	}
	if len(data.BreakTime) == 0 {
		return errors.New("休息时间未填写。")
	}

	return nil
}

// 导入生产计划
func (srv ExcelDataService) ImportDataAttendance(importDataCommand *command.ImportDataCommand) (interface{}, error) {
	excelImport := excel.NewExcelImport()
	excelImport.RowBegin = 3 //第二行开始读取
	excelImport.DataFields = []excel.DataField{
		{EnName: "productDate", CnName: "日期"},
		{EnName: "workshopName", CnName: "车间"},
		{EnName: "lineName", CnName: "线别"},
		{EnName: "sectionName", CnName: "工段"},
		{EnName: "workerName", CnName: "姓名"},
		{EnName: "attendanceType", CnName: "类型"},
		{EnName: "signIn", CnName: "上岗时间"},
		{EnName: "signOut", CnName: "离岗时间"},
		{EnName: "breakTime", CnName: "休息时长(小时)"},
	}
	excelData, err := converter.OpenImportFileFromIoReader(excelImport, importDataCommand.Reader, importDataCommand.FileExt) //excelImport.OpenExcelFromIoReader(importDataCommand.Reader)
	if err != nil {
		return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
	}
	items := make([]importAttendance, 0)
	for _, v := range excelData {
		item := importAttendance{
			ProductDate:    strings.TrimSpace(v["productDate"]),
			WorkshopName:   strings.TrimSpace(v["workshopName"]),
			LineName:       strings.TrimSpace(v["lineName"]),
			SectionName:    strings.TrimSpace(v["sectionName"]),
			WorkerName:     strings.TrimSpace(v["workerName"]),
			AttendanceType: strings.TrimSpace(v["attendanceType"]),
			SignIn:         strings.TrimSpace(v["signIn"]),
			SignOut:        strings.TrimSpace(v["signOut"]),
			BreakTime:      strings.TrimSpace(v["breakTime"]),
			FailReason:     "",
		}
		items = append(items, item)
	}
	failRows, err := srv.BatchAddAttendance(*importDataCommand.Operator, items)
	if err != nil {
		return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
	}
	return srv.importResultWithHeader(excelImport.DataFields, failRows, len(items)), nil
}

// BatchAddAttendance 工时管理,导入工时数据
func (srv ExcelDataService) BatchAddAttendance(operate domain.OperateInfo, param []importAttendance) (
	failRows []interface{}, err error) {
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	//车间数据
	//生产班组 数据
	productGroupRepo, _ := factory.CreateProductGroupRepository(map[string]interface{}{
		"transactionContext": transactionContext,
	})

	_, productGroupList, err := productGroupRepo.Find(map[string]interface{}{
		"companyId": operate.CompanyId,
		"orgId":     operate.OrgId,
	})
	if err != nil {
		return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
	}
	//车间名称+/+线别名称+/+工段名称  作为键名
	workStationMap := map[string]*domain.WorkStation{}
	//车间名称+/+工人名  作为键名
	workerMap := map[string][]*domain.User{}
	for _, v := range productGroupList {
		workStationName := strings.Join([]string{
			v.WorkStation.WorkshopName, v.WorkStation.LineName, v.WorkStation.SectionName,
		}, "/")
		workStationMap[workStationName] = v.WorkStation
		for _, vv := range v.GroupMembers {
			k := v.WorkStation.WorkshopName + "/" + vv.UserName
			isIn := false
			for _, vvv := range workerMap[k] {
				if vvv.UserId == vv.UserId {
					isIn = true
					break
				}
			}
			if !isIn {
				workerMap[k] = append(workerMap[k], vv)
			}
		}
	}
	var attendanceList []*domain.ProductAttendanceRecord
	nowTime := time.Now()
	//检查导入的数据
	for i := range param {
		//检查字段值
		err := param[i].validField()
		if err != nil {
			param[i].FailReason = err.Error()
			failRows = append(failRows, param[i])
			continue
		}
		//检查日期格式
		productDate, err := time.ParseInLocation("2006-01-02", param[i].ProductDate, time.Local)
		if err != nil {
			param[i].FailReason = "日期格式错误,例 2006-01-02。"
			failRows = append(failRows, param[i])
			continue
		}
		//检查类型
		attendanceType := 0
		// 考勤类型 1.正常 2.支援
		if param[i].AttendanceType == "支援" {
			attendanceType = 1
		} else if param[i].AttendanceType == "正常" {
			attendanceType = 2
		} else {
			param[i].FailReason = "类型内容异常。"
			failRows = append(failRows, param[i])
			continue
		}
		//检查上岗时间格式
		signIn, err := time.ParseInLocation("15:04:05", param[i].SignIn, time.Local)
		if err != nil {
			param[i].FailReason = "上岗时间格式错误,例 15:04:05。"
			failRows = append(failRows, param[i])
			continue
		}
		signIn = productDate.Add(time.Duration(signIn.Second()) * time.Second)
		//检查离岗时间格式
		signOut, err := time.ParseInLocation("15:04:05", param[i].SignOut, time.Local)
		if err != nil {
			param[i].FailReason = "离岗时间格式错误,例 15:04:05。"
			failRows = append(failRows, param[i])
			continue
		}
		signOut = productDate.Add(time.Duration(signOut.Second()) * time.Second)
		//检查员工姓名
		var worker *domain.User
		workKey := param[i].WorkshopName + "/" + param[i].WorkerName
		if u, ok := workerMap[workKey]; ok {
			if len(u) > 1 {
				param[i].FailReason = "当前车间存在重复的用户名"
				failRows = append(failRows, param[i])
				continue
			}
			worker = u[0]
		} else {
			param[i].FailReason = "当前车间不存在用户" + param[i].WorkerName
			failRows = append(failRows, param[i])
			continue
		}
		//检查工位
		var workStation *domain.WorkStation
		workStationName := param[i].WorkshopName + "/" + param[i].LineName + "/" + param[i].SectionName
		if v, ok := workStationMap[workStationName]; ok {
			workStation = v
		} else {
			param[i].FailReason = "车间、线别、工段不存在"
			failRows = append(failRows, param[i])
			continue
		}
		//休息时间(小时)
		beakTime, err := strconv.ParseFloat(param[i].BreakTime, 64)
		if err != nil {
			param[i].FailReason = "休息时长填写错误"
			failRows = append(failRows, param[i])
			continue
		}

		tempItem := &domain.ProductAttendanceRecord{
			ProductAttendanceId: 0,
			CompanyId:           operate.CompanyId,
			OrgId:               operate.OrgId,
			AttendanceType:      attendanceType,
			ProductWorker:       worker,
			WorkStation:         workStation,
			SignIn:              signIn,
			SignOut:             signOut,
			AttendanceStatus:    domain.AttendanceAutoApproved, //自动审核
			WorkTimeBefore:      0.0,
			WorkTimeAfter:       0.0,
			CreatedAt:           nowTime,
			UpdatedAt:           nowTime,
			DeletedAt:           time.Time{},
			ProductDate:         productDate,
		}
		//计算工时
		workTime := tempItem.ComputeWorkTime(beakTime)
		tempItem.WorkTimeAfter = workTime
		tempItem.WorkTimeBefore = workTime
		attendanceList = append(attendanceList, tempItem)
	}
	if len(failRows) > 0 {
		return failRows, nil
	}
	attendanceRepo, _ := factory.CreateProductAttendanceRecordRepository(map[string]interface{}{
		"transactionContext": transactionContext,
	})
	for i := range attendanceList {
		_, err = attendanceRepo.Save(attendanceList[i])
		if err != nil {
			return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
		}
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return nil, nil
}