package service import ( "fmt" "strconv" "time" "github.com/linmadan/egglib-go/core/application" "github.com/linmadan/egglib-go/utils/tool_funs" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/evaluation_project/adapter" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/evaluation_project/command" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/factory" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/domain" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/utils" ) type EvaluationProjectService struct { } func NewEvaluationProjectService() *EvaluationProjectService { newRoleService := &EvaluationProjectService{} return newRoleService } // Create 创建 func (rs *EvaluationProjectService) Create(in *command.CreateProjectCommand) (interface{}, error) { transactionContext, err := factory.ValidateStartTransaction(in) if err != nil { return nil, err } defer func() { transactionContext.RollbackTransaction() }() projectRepository := factory.CreateEvaluationProjectRepository(map[string]interface{}{"transactionContext": transactionContext}) // 检测名称重复 count, err := projectRepository.Count(map[string]interface{}{"name": in.Name, "cycleId": in.CycleId, "companyId": in.CompanyId}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } if count > 0 { return nil, application.ThrowError(application.BUSINESS_ERROR, "名称已存在") } newProject := &domain.EvaluationProject{ Id: 0, Name: in.Name, Describe: in.Describe, CompanyId: in.CompanyId, CycleId: in.CycleId, CreatorId: in.CreatorId, State: domain.ProjectStateWaitConfig, HrBp: in.HrBp, Pmp: in.Pmp, PmpIds: in.PmpIds, } project, err := projectRepository.Insert(newProject) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } projectAdapter := &adapter.EvaluationProjectAdapter{} projectAdapter.EvaluationProject = project if len(project.PmpIds) > 0 { userRepository := factory.CreateUserRepository(map[string]interface{}{"transactionContext": transactionContext}) _, users, _ := userRepository.Find(map[string]interface{}{"ids": project.PmpIds, "limit": len(project.PmpIds)}) projectAdapter.TransformPmpAdapter(users) } if err := transactionContext.CommitTransaction(); err != nil { return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) } return projectAdapter, nil } func (rs *EvaluationProjectService) Update(in *command.UpdateProjectCommand) (interface{}, error) { transactionContext, err := factory.ValidateStartTransaction(in) if err != nil { return nil, err } defer func() { transactionContext.RollbackTransaction() }() projectRepository := factory.CreateEvaluationProjectRepository(map[string]interface{}{"transactionContext": transactionContext}) // 检测名称重复(排除自己) count, err := projectRepository.Count(map[string]interface{}{"name": in.Name, "cycleId": in.CycleId, "companyId": in.CompanyId, "notId": in.Id}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } if count > 0 { return nil, application.ThrowError(application.BUSINESS_ERROR, "名称已存在") } project, err := projectRepository.FindOne(map[string]interface{}{"id": in.Id}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } project.Name = in.Name project.Describe = in.Describe project.HrBp = in.HrBp project.Pmp = in.Pmp project.PmpIds = in.PmpIds project, err = projectRepository.Insert(project) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } projectAdapter := &adapter.EvaluationProjectAdapter{} projectAdapter.EvaluationProject = project if len(project.PmpIds) > 0 { userRepository := factory.CreateUserRepository(map[string]interface{}{"transactionContext": transactionContext}) _, users, _ := userRepository.Find(map[string]interface{}{"ids": project.PmpIds, "limit": len(project.PmpIds)}) projectAdapter.TransformPmpAdapter(users) } if err := transactionContext.CommitTransaction(); err != nil { return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) } return projectAdapter, nil } func (rs *EvaluationProjectService) UpdateTemplate(in *command.UpdateProjectTemplateCommand) (interface{}, error) { transactionContext, err := factory.ValidateStartTransaction(in) if err != nil { return nil, err } defer func() { transactionContext.RollbackTransaction() }() projectRepository := factory.CreateEvaluationProjectRepository(map[string]interface{}{"transactionContext": transactionContext}) cycleRepository := factory.CreateEvaluationCycleRepository(map[string]interface{}{"transactionContext": transactionContext}) cycleTemplateRepository := factory.CreateEvaluationCycleTemplateRepository(map[string]interface{}{"transactionContext": transactionContext}) project, err := projectRepository.FindOne(map[string]interface{}{"id": in.Id}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } // 如果是已经启用的项目,只能编辑环节的截至时间 if project.State == domain.ProjectStateEnable { end, err := time.ParseInLocation("2006-01-02 15:04:05", in.TimeEnd, time.Local) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } cycle, err := cycleRepository.FindOne(map[string]interface{}{"id": in.CycleId}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } maxTime := cycle.TimeEnd.Local() if end.After(maxTime) { return nil, application.ThrowError(application.BUSINESS_ERROR, "评估截至时间不能超出周期截至时间") } // 更新项目模板中的环节时间 if project.Template != nil { for i := range project.Template.LinkNodes { node := project.Template.LinkNodes[i] node.TimeEnd = &end } } // 更新项目截止时间(暂时环节中的时间未分开) project.EndTime = end project, err = projectRepository.Insert(project) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } // 项目调整截止时间,同步更新任务时间 if err := rs.updateTaskTime(transactionContext, in.Id, end); err != nil { return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) } if err := transactionContext.CommitTransaction(); err != nil { return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) } return project, nil } else { _, projects, err := projectRepository.Find(map[string]interface{}{"companyId": in.CompanyId, "cycleId": in.CycleId}, "template") if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } // 周期内的所有项目,员工不能重复被评估 rids := map[string]bool{} for i := range projects { // 排除当前项目 if in.Id != projects[i].Id { ids := projects[i].Recipients for j := range ids { rids[ids[j]] = true } } } repeatNum := 0 for i := range in.Recipients { id := in.Recipients[i] if _, ok := rids[id]; ok { repeatNum++ } } if repeatNum > 0 { return nil, application.ThrowError(application.BUSINESS_ERROR, fmt.Sprintf("有%d人已经在本周期其他项目内,需要将他们移除", repeatNum)) } cycleTemplate, err := cycleTemplateRepository.FindOne(map[string]interface{}{"id": in.TemplateId, "includeDeleted": true}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } if cycleTemplate == nil || cycleTemplate.Template == nil { return nil, application.ThrowError(application.BUSINESS_ERROR, "请添加模板") } start, err := time.ParseInLocation("2006-01-02 15:04:05", in.TimeStart, time.Local) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } end, err := time.ParseInLocation("2006-01-02 15:04:05", in.TimeEnd, time.Local) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } cycle, err := cycleRepository.FindOne(map[string]interface{}{"id": in.CycleId}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } minTime := cycle.TimeStart.Local() maxTime := cycle.TimeEnd.Local() if start.Before(minTime) { return nil, application.ThrowError(application.BUSINESS_ERROR, "评估起始时间不能超出周期起始时间") } if end.After(maxTime) { return nil, application.ThrowError(application.BUSINESS_ERROR, "评估截至时间不能超出周期截至时间") } if project.State == domain.ProjectStateWaitConfig { project.State = domain.ProjectStateWaitActive } project.Recipients = in.Recipients project.Template = cycleTemplate.Template // 项目起始截止时间(环节中的时间暂未分开计算) project.BeginTime = start project.EndTime = end for i := range project.Template.LinkNodes { node := project.Template.LinkNodes[i] node.KpiCycle = in.KpiCycle // 设置周期 node.TimeStart = &start node.TimeEnd = &end } project, err = projectRepository.Insert(project) 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 project, nil } } // 更新项目截止时间,同步任务截止时间 func (rs *EvaluationProjectService) updateTaskTime(context application.TransactionContext, projectId int64, end time.Time) error { // 查看任务过程,重新日计算任务截至期 taskRepository := factory.CreateNodeTaskRepository(map[string]interface{}{"transactionContext": context}) tasks, err := taskRepository.Find(map[string]interface{}{"projectId": projectId}) if err != nil { return application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } now := time.Now().Local() year, month, day := now.Date() nowO := time.Date(year, month, day, 0, 0, 0, 0, time.Local) // 当前时间0点0分0秒时刻 for i := range tasks { task := tasks[i] task.TimeEnd = &end // 先赋值 if task.NextSentAt == nil { // 重新计算 // 环节起始和截止本地时间 startLocal := task.TimeStart.Local() sY, sM, sD := startLocal.Date() startLocal = time.Date(sY, sM, sD, 0, 0, 0, 0, time.Local) // 开始时间以0点开始计算 // 在当前时间之前,则计算下一个周期时间 if startLocal.Before(nowO) { nextTime := utils.NextTime(nowO, startLocal, task.KpiCycle) task.NextSentAt = &nextTime } else { task.NextSentAt = &startLocal } // 注.最后一次发送时间和重新计算后的时间相同时,继续获取下一个周期 if task.LastSentAt != nil { nextY, nextM, nextD := task.NextSentAt.Local().Date() lastY, lastM, lastD := task.LastSentAt.Local().Date() if nextY == lastY && nextM == lastM && nextD == lastD { nextTime := utils.NextTimeInc(task.NextSentAt.Local(), task.KpiCycle) task.NextSentAt = &nextTime } } } // 如果超出截至时间,则周期置空 if task.NextSentAt.Local().After(task.TimeEnd.Local()) { task.NextSentAt = nil } // 更新任务 task, err := taskRepository.Insert(task) if err != nil { return application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } } return nil } func (rs *EvaluationProjectService) Get(in *command.GetProjectCommand) (interface{}, error) { transactionContext, err := factory.ValidateStartTransaction(in) if err != nil { return nil, err } defer func() { transactionContext.RollbackTransaction() }() projectRepository := factory.CreateEvaluationProjectRepository(map[string]interface{}{"transactionContext": transactionContext}) project, err := projectRepository.FindOne(map[string]interface{}{"id": in.Id}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } projectAdapter := &adapter.EvaluationProjectAdapter{} projectAdapter.EvaluationProject = project userRepository := factory.CreateUserRepository(map[string]interface{}{"transactionContext": transactionContext}) if len(project.PmpIds) > 0 { _, users, _ := userRepository.Find(map[string]interface{}{"ids": project.PmpIds, "limit": len(project.PmpIds)}) projectAdapter.TransformPmpAdapter(users) } if len(project.Recipients) > 0 { _, users, _ := userRepository.Find(map[string]interface{}{"ids": project.Recipients, "limit": len(project.Recipients)}) projectAdapter.TransformRecipientAdapter(users) } if err := transactionContext.CommitTransaction(); err != nil { return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) } return projectAdapter, nil } func (rs *EvaluationProjectService) Remove(in *command.DeleteProjectCommand) (interface{}, error) { transactionContext, err := factory.ValidateStartTransaction(in) if err != nil { return nil, err } defer func() { transactionContext.RollbackTransaction() }() projectRepository := factory.CreateEvaluationProjectRepository(map[string]interface{}{"transactionContext": transactionContext}) taskRepository := factory.CreateNodeTaskRepository(map[string]interface{}{"transactionContext": transactionContext}) staffRepository := factory.CreateStaffAssessTaskRepository(map[string]interface{}{"transactionContext": transactionContext}) project, err := projectRepository.FindOne(map[string]interface{}{"id": in.Id}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } if _, err := projectRepository.Remove(project); err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } // 删除项目已生成的周期评估数据 if err := staffRepository.RemoveByProjectId(int(project.Id)); err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } // 移除项目关联的所有定时任务 tasks, err := taskRepository.Find(map[string]interface{}{"projectId": project.Id}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } for i := range tasks { if _, err := taskRepository.Remove(tasks[i]); 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 project, nil } func (rs *EvaluationProjectService) List(in *command.QueryProjectCommand) (interface{}, error) { transactionContext, err := factory.ValidateStartTransaction(in) if err != nil { return nil, err } defer func() { transactionContext.RollbackTransaction() }() projectRepository := factory.CreateEvaluationProjectRepository(map[string]interface{}{"transactionContext": transactionContext}) total, projects, err := projectRepository.Find(tool_funs.SimpleStructToMap(in), "template") if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } now := time.Now().Unix() pmpUsers := make([]*domain.User, 0) pmpUserIds := make([]int64, 0) for i := range projects { project := projects[i] for j := range project.PmpIds { userId, _ := strconv.ParseInt(project.PmpIds[j], 10, 64) pmpUserIds = append(pmpUserIds, userId) } // 如果是已启用状态时,当前时间超过截至时间显示【已结束】 if project.State == domain.ProjectStateEnable { if now > project.EndTime.Unix() { project.State = domain.ProjectStateDisable } } } if len(pmpUserIds) > 0 { userRepository := factory.CreateUserRepository(map[string]interface{}{"transactionContext": transactionContext}) _, users, _ := userRepository.Find(map[string]interface{}{"ids": pmpUserIds, "limit": len(pmpUserIds)}) pmpUsers = users } if err := transactionContext.CommitTransaction(); err != nil { return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) } projectAdapters := adapter.TransformProjectListAdapter(projects, pmpUsers) return tool_funs.SimpleWrapGridMap(total, projectAdapters), nil } func (rs *EvaluationProjectService) Activate(in *command.ActivateProjectCommand) (interface{}, error) { transactionContext, err := factory.ValidateStartTransaction(in) if err != nil { return nil, err } defer func() { transactionContext.RollbackTransaction() }() projectRepository := factory.CreateEvaluationProjectRepository(map[string]interface{}{"transactionContext": transactionContext}) taskRepository := factory.CreateNodeTaskRepository(map[string]interface{}{"transactionContext": transactionContext}) project, err := projectRepository.FindOne(map[string]interface{}{"id": in.Id}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } if project.Template == nil { return nil, application.ThrowError(application.BUSINESS_ERROR, "请添加评估模板") } if len(project.Recipients) == 0 { return nil, application.ThrowError(application.BUSINESS_ERROR, "请添加被评估人") } if project.State == domain.TemplateStateEnable { return nil, application.ThrowError(application.BUSINESS_ERROR, "项目已启动") } project.State = domain.TemplateStateEnable project, err = projectRepository.Insert(project) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } now := time.Now().Local() year, month, day := now.Date() nowO := time.Date(year, month, day, 0, 0, 0, 0, time.Local) // 当前时间0点0分0秒时刻 for i := range project.Template.LinkNodes { node := project.Template.LinkNodes[i] task := &domain.NodeTask{ Id: 0, CompanyId: project.CompanyId, CycleId: project.CycleId, ProjectId: project.Id, NodeId: node.Id, NodeType: node.Type, NodeName: node.Name, NodeDescribe: node.Describe, NodeSort: i + 1, TimeStart: node.TimeStart, TimeEnd: node.TimeEnd, KpiCycle: node.KpiCycle, } // 环节起始和截止本地时间 startLocal := task.TimeStart.Local() sY, sM, sD := startLocal.Date() startLocal = time.Date(sY, sM, sD, 0, 0, 0, 0, time.Local) // 开始时间以0点开始计算 endLocal := task.TimeEnd.Local() // 在当前时间之前,则计算下一个周期时间 if startLocal.Before(nowO) { nextTime := utils.NextTime(nowO, startLocal, node.KpiCycle) task.NextSentAt = &nextTime } else { task.NextSentAt = &startLocal } // 如果超出截至时间,则周期置空 if task.NextSentAt.After(endLocal) { task.NextSentAt = nil } task, err := taskRepository.Insert(task) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } } err = rs.generateEvaluationItemUsed(transactionContext, project) 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 project, nil } func (rs *EvaluationProjectService) Copy(in *command.CopyProjectCommand) (interface{}, error) { transactionContext, err := factory.ValidateStartTransaction(in) if err != nil { return nil, err } defer func() { transactionContext.RollbackTransaction() }() projectRepository := factory.CreateEvaluationProjectRepository(map[string]interface{}{"transactionContext": transactionContext}) project, err := projectRepository.FindOne(map[string]interface{}{"id": in.Id}) if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } // ID重置 project.Id = 0 project.Name = project.Name + " 副本" project.CreatorId = in.CreatorId project.Recipients = make([]string, 0) // 重置被评估人 // 如果拷贝已经启用的模板,默认先设置为待启用 if project.State == domain.ProjectStateEnable { project.State = domain.ProjectStateWaitActive } project, err = projectRepository.Insert(project) 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 project, nil } func (rs *EvaluationProjectService) CheckRecipients(in *command.CheckRecipientCommand) (interface{}, error) { transactionContext, err := factory.ValidateStartTransaction(in) if err != nil { return nil, err } defer func() { transactionContext.RollbackTransaction() }() projectRepository := factory.CreateEvaluationProjectRepository(map[string]interface{}{"transactionContext": transactionContext}) _, projects, err := projectRepository.Find(map[string]interface{}{"companyId": in.CompanyId, "cycleId": in.CycleId}, "template") if err != nil { return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } // 周期内的所有项目,员工不能重复被评估 rids := map[string]bool{} for i := range projects { // 排除当前项目 if in.Id != projects[i].Id { ids := projects[i].Recipients for j := range ids { rids[ids[j]] = true } } } repeatNum := 0 for i := range in.Recipients { id := in.Recipients[i] if _, ok := rids[id]; ok { repeatNum++ } } if err := transactionContext.CommitTransaction(); err != nil { return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) } return map[string]interface{}{"repeatNum": repeatNum}, nil } func (rs *EvaluationProjectService) generateEvaluationItemUsed(transactionContext application.TransactionContext, project *domain.EvaluationProject) error { var itemUsedList []*domain.EvaluationItemUsed nowTime := time.Now() for _, v := range project.Template.LinkNodes { for i2, v2 := range v.NodeContents { item := domain.EvaluationItemUsed{ Id: 0, CompanyId: int(project.CompanyId), EvaluationProjectId: int(project.Id), NodeId: int(v.Id), NodeType: v.Type, SortBy: i2, Category: v2.Category, Name: v2.Name, PromptTitle: v2.PromptTitle, PromptText: v2.PromptText, EntryItems: v2.EntryItems, Weight: v2.Weight, Required: v2.Required, EvaluatorId: int(v2.EvaluatorId), CreatedAt: nowTime, UpdatedAt: nowTime, // RuleType: 0, // Rule: *v2.Rule, } if v2.Rule != nil { item.RuleType = v2.Rule.Type item.Rule = *v2.Rule } itemUsedList = append(itemUsedList, &item) } } itemUsedRepo := factory.CreateEvaluationItemUsedRepository(map[string]interface{}{ "transactionContext": transactionContext, }) err := itemUsedRepo.BatchInsert(itemUsedList) if err != nil { return application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) } return nil }