作者 tangxvhui

暂存

1 package adapter 1 package adapter
2 2
3 type AssessCycleDayResp struct { 3 type AssessCycleDayResp struct {
4 - CycleId int `json:"cycleId"`  
5 - CycleName string `json:"cycleName"`  
6 - BeginDay string `json:"beginDay"` 4 + CycleId int `json:"cycleId"`
  5 + CycleName string `json:"cycleName"`
  6 + BeginDay string `json:"beginDay"`
  7 + AssessTaskId []int `json:"assessTaskId"`
7 } 8 }
1 package query 1 package query
2 2
  3 +//个人的获取周期任务完成情况描述
3 type AssessCycleDescQuery struct { 4 type AssessCycleDescQuery struct {
4 - CycleId int `json:"cycleId"` //评估任务的id  
5 - BeginDay string `json:"beginDay"` //开始时间 2022-01-02  
6 - UserId int `json:"userId"` //当前登录人的id  
7 - CompanyId int `json:"companyId"` //当前登录的公司 5 + AssessTaskId []int `json:"assessTaskId"` //评估任务的id
  6 + UserId int `json:"userId"` //当前登录人的id
  7 + CompanyId int `json:"companyId"` //当前登录的公司
8 } 8 }
  1 +package query
  2 +
  3 +type ListExecutorInviteAssessQuery struct {
  4 + PageNumber int `json:"pageNumber"`
  5 + PageSize int `json:"pageSize"`
  6 + UserName string `json:"userName"` //查询条件 员工的名称
  7 + CompanyId int `json:"companyId"` //
  8 + ExecutorId int `json:"executorId,string"` //评估的执行人,必填
  9 + CycleId int `json:"cycleId"` //评估任务id 必填
  10 + BeginDay string `json:"beginDay"`
  11 +}
@@ -51,9 +51,10 @@ func (srv StaffAssessServeice) SearchAssessCycelMe(param *query.SearchAssessMeQu @@ -51,9 +51,10 @@ func (srv StaffAssessServeice) SearchAssessCycelMe(param *query.SearchAssessMeQu
51 var temp adapter.AssessCycleDayResp 51 var temp adapter.AssessCycleDayResp
52 for _, v := range assessCycleList { 52 for _, v := range assessCycleList {
53 temp = adapter.AssessCycleDayResp{ 53 temp = adapter.AssessCycleDayResp{
54 - CycleId: v.CycleId,  
55 - CycleName: v.CycleName,  
56 - BeginDay: v.BeginDay, 54 + CycleId: v.CycleId,
  55 + CycleName: v.CycleName,
  56 + BeginDay: v.BeginDay,
  57 + AssessTaskId: v.AssessTaskId,
57 } 58 }
58 listData = append(listData, temp) 59 listData = append(listData, temp)
59 } 60 }
@@ -80,22 +81,31 @@ func (srv StaffAssessServeice) AssessCycleMeDesc(param *query.AssessCycleDescQue @@ -80,22 +81,31 @@ func (srv StaffAssessServeice) AssessCycleMeDesc(param *query.AssessCycleDescQue
80 staffAssessRepo := factory.CreateStaffAssessRepository(map[string]interface{}{ 81 staffAssessRepo := factory.CreateStaffAssessRepository(map[string]interface{}{
81 "transactionContext": transactionContext, 82 "transactionContext": transactionContext,
82 }) 83 })
83 - assessTaskDataAny, err := staffAssessTaskRepo.FindOne(map[string]interface{}{  
84 - "cycleId": param.CycleId,  
85 - "beginDay": param.BeginDay,  
86 - "limit": 1, 84 + if len(param.AssessTaskId) == 0 {
  85 + return &adapter.AssessCycleDescResp{}, nil
  86 + }
  87 + _, assessTaskList, err := staffAssessTaskRepo.Find(map[string]interface{}{
  88 + "ids": param.AssessTaskId,
  89 + "companyId": param.CompanyId,
87 }) 90 })
88 if err != nil { 91 if err != nil {
89 return nil, application.ThrowError(application.TRANSACTION_ERROR, "评估任务不存在,"+err.Error()) 92 return nil, application.ThrowError(application.TRANSACTION_ERROR, "评估任务不存在,"+err.Error())
90 } 93 }
91 - _, myAssessTask, err := staffAssessTaskRepo.Find(map[string]interface{}{  
92 - "cycleId": param.CycleId,  
93 - "beginDay": param.BeginDay,  
94 - "executorId": param.UserId,  
95 - "limit": 1,  
96 - })  
97 - if err != nil {  
98 - return nil, application.ThrowError(application.TRANSACTION_ERROR, "我的评估任务不存在,"+err.Error()) 94 + if len(assessTaskList) == 0 {
  95 + return &adapter.AssessCycleDescResp{}, nil
  96 + }
  97 + assessTaskDataAny := assessTaskList[0]
  98 + var myAssessTask *domain.StaffAssessTask
  99 + for _, v := range assessTaskList {
  100 + if myAssessTask != nil {
  101 + break
  102 + }
  103 + for _, vv := range v.ExecutorId {
  104 + if param.UserId == vv {
  105 + myAssessTask = v
  106 + break
  107 + }
  108 + }
99 } 109 }
100 //返回的数据结果 110 //返回的数据结果
101 result := adapter.AssessCycleDescResp{ 111 result := adapter.AssessCycleDescResp{
@@ -118,10 +128,10 @@ func (srv StaffAssessServeice) AssessCycleMeDesc(param *query.AssessCycleDescQue @@ -118,10 +128,10 @@ func (srv StaffAssessServeice) AssessCycleMeDesc(param *query.AssessCycleDescQue
118 } 128 }
119 switch v.LinkNodeType { 129 switch v.LinkNodeType {
120 case domain.LinkNodeSelfAssessment: 130 case domain.LinkNodeSelfAssessment:
121 - if len(myAssessTask) > 0 { 131 + if myAssessTask != nil {
122 //个人自评完成情况 132 //个人自评完成情况
123 _, assessSelfData, err := staffAssessRepo.Find(map[string]interface{}{ 133 _, assessSelfData, err := staffAssessRepo.Find(map[string]interface{}{
124 - "staffAssessTaskId": myAssessTask[0].Id, 134 + "staffAssessTaskId": myAssessTask.Id,
125 "executorId": param.UserId, 135 "executorId": param.UserId,
126 "typesList": []string{string(domain.AssessSelf)}, 136 "typesList": []string{string(domain.AssessSelf)},
127 }) 137 })
@@ -134,10 +144,10 @@ func (srv StaffAssessServeice) AssessCycleMeDesc(param *query.AssessCycleDescQue @@ -134,10 +144,10 @@ func (srv StaffAssessServeice) AssessCycleMeDesc(param *query.AssessCycleDescQue
134 stepItem.Desc = fmt.Sprintf("截止日期:%s", stepItem.EndTime) 144 stepItem.Desc = fmt.Sprintf("截止日期:%s", stepItem.EndTime)
135 } 145 }
136 case domain.LinkNodeAllInvite: 146 case domain.LinkNodeAllInvite:
137 - if len(myAssessTask) > 0 { 147 + if myAssessTask != nil {
138 //邀请别人评估自己 148 //邀请别人评估自己
139 _, assessInviteData, err := staffAssessRepo.Find(map[string]interface{}{ 149 _, assessInviteData, err := staffAssessRepo.Find(map[string]interface{}{
140 - "staffAssessTaskId": myAssessTask[0].Id, 150 + "staffAssessTaskId": myAssessTask.Id,
141 "targetUserId": param.UserId, //我被作为目标 151 "targetUserId": param.UserId, //我被作为目标
142 "typesList": []string{string(domain.AssessInviteDiffSuper), string(domain.AssessInviteSameSuper)}, 152 "typesList": []string{string(domain.AssessInviteDiffSuper), string(domain.AssessInviteSameSuper)},
143 "limit": 5, 153 "limit": 5,
@@ -160,8 +170,7 @@ func (srv StaffAssessServeice) AssessCycleMeDesc(param *query.AssessCycleDescQue @@ -160,8 +170,7 @@ func (srv StaffAssessServeice) AssessCycleMeDesc(param *query.AssessCycleDescQue
160 case domain.LinkNodeAllAssessment: 170 case domain.LinkNodeAllAssessment:
161 //我评估别人,被邀请评估 171 //我评估别人,被邀请评估
162 _, assessInviteList, err := staffAssessRepo.Find(map[string]interface{}{ 172 _, assessInviteList, err := staffAssessRepo.Find(map[string]interface{}{
163 - "beginDay": param.BeginDay,  
164 - "cycleId": param.CycleId, 173 + //TODO
165 "executorId": param.UserId, //我作为执行人 174 "executorId": param.UserId, //我作为执行人
166 "typesList": []string{string(domain.AssessInviteDiffSuper), string(domain.AssessInviteSameSuper)}, 175 "typesList": []string{string(domain.AssessInviteDiffSuper), string(domain.AssessInviteSameSuper)},
167 }) 176 })
@@ -180,24 +189,32 @@ func (srv StaffAssessServeice) AssessCycleMeDesc(param *query.AssessCycleDescQue @@ -180,24 +189,32 @@ func (srv StaffAssessServeice) AssessCycleMeDesc(param *query.AssessCycleDescQue
180 } 189 }
181 case domain.LinkNodeSuperiorAssessment: 190 case domain.LinkNodeSuperiorAssessment:
182 //我评估别人,上级评估 191 //我评估别人,上级评估
183 - _, assessSupperList, err := staffAssessRepo.Find(map[string]interface{}{ 192 + cnnt, _, err := staffAssessRepo.Find(map[string]interface{}{
184 "cycleId": param.CycleId, 193 "cycleId": param.CycleId,
185 "beginDay": param.BeginDay, 194 "beginDay": param.BeginDay,
186 "executorId": param.UserId, 195 "executorId": param.UserId,
187 "typesList": []string{string(domain.AssessSuper)}, 196 "typesList": []string{string(domain.AssessSuper)},
  197 + "status": domain.StaffAssessUncompleted,
  198 + "limit": 1,
188 }) 199 })
189 if err != nil { 200 if err != nil {
190 - return nil, application.ThrowError(application.TRANSACTION_ERROR, "获取个人的评估环节"+err.Error()) 201 + return nil, application.ThrowError(application.TRANSACTION_ERROR, "获取未完成的评估环节"+err.Error())
  202 + }
  203 + cnnt2, _, err := staffAssessRepo.Find(map[string]interface{}{
  204 + "cycleId": param.CycleId,
  205 + "beginDay": param.BeginDay,
  206 + "executorId": param.UserId,
  207 + "typesList": []string{string(domain.AssessSuper)},
  208 + "status": domain.StaffAssessCompleted,
  209 + "limit": 1,
  210 + })
  211 + if err != nil {
  212 + return nil, application.ThrowError(application.TRANSACTION_ERROR, "获取已完成的评估环节"+err.Error())
191 } 213 }
192 - if len(assessSupperList) > 0 { 214 + if cnnt+cnnt2 > 0 {
193 stepItem.Status = string(domain.StaffAssessCompleted) 215 stepItem.Status = string(domain.StaffAssessCompleted)
194 stepItem.Desc = fmt.Sprintf("截止日期:%s", stepItem.EndTime) 216 stepItem.Desc = fmt.Sprintf("截止日期:%s", stepItem.EndTime)
195 - uncompletedNum := 0  
196 - for _, v := range assessSupperList {  
197 - if v.Status == domain.StaffAssessUncompleted {  
198 - uncompletedNum += 1  
199 - }  
200 - } 217 + uncompletedNum := cnnt
201 if uncompletedNum > 0 { 218 if uncompletedNum > 0 {
202 stepItem.Status = string(domain.StaffAssessUncompleted) 219 stepItem.Status = string(domain.StaffAssessUncompleted)
203 stepItem.Desc = fmt.Sprintf("截止日期:%s 待评估%d人", stepItem.EndTime, uncompletedNum) 220 stepItem.Desc = fmt.Sprintf("截止日期:%s 待评估%d人", stepItem.EndTime, uncompletedNum)
@@ -287,7 +304,7 @@ func (srv StaffAssessServeice) ListAssessInviteUser(param query.ListAssessInvite @@ -287,7 +304,7 @@ func (srv StaffAssessServeice) ListAssessInviteUser(param query.ListAssessInvite
287 } 304 }
288 305
289 // 根据周期和日期获取我要执行的的360评估,用户列表和评估填写的值 306 // 根据周期和日期获取我要执行的的360评估,用户列表和评估填写的值
290 -func (srv StaffAssessServeice) ListExecutorInviteAssessDay(param *query.ListInviteUserAssessQuery) ( 307 +func (srv StaffAssessServeice) ListExecutorDayInviteAssess(param *query.ListExecutorInviteAssessQuery) (
291 *adapter.ListInviteUserAssessResp, error) { 308 *adapter.ListInviteUserAssessResp, error) {
292 transactionContext, err := factory.CreateTransactionContext(nil) 309 transactionContext, err := factory.CreateTransactionContext(nil)
293 if err != nil { 310 if err != nil {
@@ -306,13 +323,13 @@ func (srv StaffAssessServeice) ListExecutorInviteAssessDay(param *query.ListInvi @@ -306,13 +323,13 @@ func (srv StaffAssessServeice) ListExecutorInviteAssessDay(param *query.ListInvi
306 assessTaskRepo := factory.CreateStaffAssessTaskRepository(map[string]interface{}{ 323 assessTaskRepo := factory.CreateStaffAssessTaskRepository(map[string]interface{}{
307 "transactionContext": transactionContext, 324 "transactionContext": transactionContext,
308 }) 325 })
309 -  
310 //获取 executorId 对应的360评估任务 用户 326 //获取 executorId 对应的360评估任务 用户
311 condition := map[string]interface{}{ 327 condition := map[string]interface{}{
312 - "staffAssessTaskId": param.AssessTaskId,  
313 - "executorId": param.ExecutorId,  
314 - "typesList": []string{string(domain.AssessInviteDiffSuper), string(domain.AssessInviteSameSuper)},  
315 - "limit": 20, 328 + "beginDay": param.BeginDay,
  329 + "cycleId": param.CycleId,
  330 + "executorId": param.ExecutorId,
  331 + "typesList": []string{string(domain.AssessInviteDiffSuper), string(domain.AssessInviteSameSuper)},
  332 + "limit": 20,
316 } 333 }
317 if param.PageSize > 0 { 334 if param.PageSize > 0 {
318 condition["limit"] = param.PageSize 335 condition["limit"] = param.PageSize
@@ -372,17 +389,22 @@ func (srv StaffAssessServeice) ListExecutorInviteAssessDay(param *query.ListInvi @@ -372,17 +389,22 @@ func (srv StaffAssessServeice) ListExecutorInviteAssessDay(param *query.ListInvi
372 //获取360邀请评估完成情况 389 //获取360邀请评估完成情况
373 //我评估别人,被邀请评估 390 //我评估别人,被邀请评估
374 cnnt, _, err := assessRepo.Find(map[string]interface{}{ 391 cnnt, _, err := assessRepo.Find(map[string]interface{}{
375 - "staffAssessTaskId": param.AssessTaskId,  
376 - "executorId": param.ExecutorId,  
377 - "typesList": []string{string(domain.AssessInviteDiffSuper), string(domain.AssessInviteSameSuper)},  
378 - "status": domain.StaffAssessUncompleted, 392 + "beginDay": param.BeginDay,
  393 + "cycleId": param.CycleId,
  394 + "executorId": param.ExecutorId,
  395 + "typesList": []string{string(domain.AssessInviteDiffSuper), string(domain.AssessInviteSameSuper)},
  396 + "status": domain.StaffAssessUncompleted,
  397 + "limit": 1,
379 }) 398 })
380 if err != nil { 399 if err != nil {
381 return nil, application.ThrowError(application.TRANSACTION_ERROR, "获取个人的评估环节"+err.Error()) 400 return nil, application.ThrowError(application.TRANSACTION_ERROR, "获取个人的评估环节"+err.Error())
382 } 401 }
383 402
384 - assessTaskData, err := assessTaskRepo.FindOne(map[string]interface{}{  
385 - "id": param.AssessTaskId, 403 + _, myAssessTaskData, err := assessTaskRepo.Find(map[string]interface{}{
  404 + "beginDay": param.BeginDay,
  405 + "cycleId": param.CycleId,
  406 + "executorId": param.ExecutorId,
  407 + "limit": 1,
386 }) 408 })
387 if err != nil { 409 if err != nil {
388 return nil, application.ThrowError(application.TRANSACTION_ERROR, "获取评估任务"+err.Error()) 410 return nil, application.ThrowError(application.TRANSACTION_ERROR, "获取评估任务"+err.Error())
@@ -415,7 +437,6 @@ func (srv StaffAssessServeice) ListExecutorInviteAssessDay(param *query.ListInvi @@ -415,7 +437,6 @@ func (srv StaffAssessServeice) ListExecutorInviteAssessDay(param *query.ListInvi
415 case domain.StaffAssessUncompleted: 437 case domain.StaffAssessUncompleted:
416 m["status"] = "未完成" 438 m["status"] = "未完成"
417 } 439 }
418 -  
419 switch v.Types { 440 switch v.Types {
420 case domain.AssessInviteDiffSuper: 441 case domain.AssessInviteDiffSuper:
421 m["types"] = "不同上级同事" 442 m["types"] = "不同上级同事"
@@ -438,12 +459,19 @@ func (srv StaffAssessServeice) ListExecutorInviteAssessDay(param *query.ListInvi @@ -438,12 +459,19 @@ func (srv StaffAssessServeice) ListExecutorInviteAssessDay(param *query.ListInvi
438 List: listData, 459 List: listData,
439 Total: cnt, 460 Total: cnt,
440 } 461 }
441 - for _, v := range assessTaskData.StepList {  
442 - if v.LinkNodeType == domain.LinkNodeAllAssessment {  
443 - result.LinkNodeId = v.LinkNodeId  
444 - result.LinkNodeName = v.LinkNodeName  
445 - result.LintNodeDesc = fmt.Sprintf("截止时间 %s 待评估%d人", v.EndTime.Local().Format("2006-01-02 15:04:05"), cnnt) 462 + if len(myAssessTaskData) > 0 {
  463 + for _, v := range myAssessTaskData[0].StepList {
  464 + if v.LinkNodeType == domain.LinkNodeAllAssessment {
  465 + result.LinkNodeId = v.LinkNodeId
  466 + result.LinkNodeName = v.LinkNodeName
  467 + result.LintNodeDesc = fmt.Sprintf("截止时间 %s 待评估%d人", v.EndTime.Local().Format("2006-01-02 15:04:05"), cnnt)
  468 + }
446 } 469 }
447 } 470 }
448 return &result, nil 471 return &result, nil
449 } 472 }
  473 +
  474 +func (srv StaffAssessServeice) ListExecutorSupperAssessDay() (map[string]interface{}, error) {
  475 +
  476 + return nil, nil
  477 +}
@@ -381,8 +381,15 @@ func (d *StaffAssessDao) ExportDataUserAssess(param SearchConditin1) ([]ExportDa @@ -381,8 +381,15 @@ func (d *StaffAssessDao) ExportDataUserAssess(param SearchConditin1) ([]ExportDa
381 return result, err 381 return result, err
382 } 382 }
383 383
  384 +type AssessCycleDayMe struct {
  385 + BeginDay string `json:"beginDay"`
  386 + CycleId int `json:"cycleId"`
  387 + CycleName string `json:"cycleName"`
  388 + AssessTaskId []int `json:"assessTaskId"`
  389 +}
  390 +
384 // 根据评估的人执行人id,搜索 executorId参与的评估周期 391 // 根据评估的人执行人id,搜索 executorId参与的评估周期
385 -func (d *StaffAssessDao) SearchAssessCycleMe(executorId int, companyId int, limit int, offset int) ([]AssessCycleDay, error) { 392 +func (d *StaffAssessDao) SearchAssessCycleMe(executorId int, companyId int, limit int, offset int) ([]AssessCycleDayMe, error) {
386 if limit < 0 { 393 if limit < 0 {
387 limit = 20 394 limit = 20
388 } 395 }
@@ -390,19 +397,23 @@ func (d *StaffAssessDao) SearchAssessCycleMe(executorId int, companyId int, limi @@ -390,19 +397,23 @@ func (d *StaffAssessDao) SearchAssessCycleMe(executorId int, companyId int, limi
390 offset = 0 397 offset = 0
391 } 398 }
392 sqlStr := ` 399 sqlStr := `
393 - SELECT DISTINCT staff_assess_task.cycle_id ,staff_assess_task.cycle_name ,staff_assess_task.begin_day 400 + SELECT
  401 + jsonb_agg (staff_assess_task.id) as assess_task_id,
  402 + staff_assess_task.cycle_id ,staff_assess_task.cycle_name ,staff_assess_task.begin_day
394 FROM staff_assess_task 403 FROM staff_assess_task
395 JOIN staff_assess ON staff_assess_task."id" = staff_assess."staff_assess_task_id" 404 JOIN staff_assess ON staff_assess_task."id" = staff_assess."staff_assess_task_id"
396 WHERE staff_assess.company_id=? 405 WHERE staff_assess.company_id=?
397 and staff_assess_task.deleted_at isnull 406 and staff_assess_task.deleted_at isnull
398 and staff_assess.executor->>'userId'='?' 407 and staff_assess.executor->>'userId'='?'
  408 + group by staff_assess_task.cycle_id ,staff_assess_task.cycle_name ,staff_assess_task.begin_day
399 order by staff_assess_task.begin_day desc 409 order by staff_assess_task.begin_day desc
  410 + limit ? offset ?
400 ` 411 `
401 tx := d.transactionContext.PgTx 412 tx := d.transactionContext.PgTx
402 condition := []interface{}{ 413 condition := []interface{}{
403 companyId, executorId, limit, offset, 414 companyId, executorId, limit, offset,
404 } 415 }
405 - result := []AssessCycleDay{} 416 + result := []AssessCycleDayMe{}
406 _, err := tx.Query(&result, sqlStr, condition...) 417 _, err := tx.Query(&result, sqlStr, condition...)
407 return result, err 418 return result, err
408 } 419 }
@@ -410,7 +421,7 @@ func (d *StaffAssessDao) SearchAssessCycleMe(executorId int, companyId int, limi @@ -410,7 +421,7 @@ func (d *StaffAssessDao) SearchAssessCycleMe(executorId int, companyId int, limi
410 // 根据评估的人执行人id,统计executorId参与的评估周期 421 // 根据评估的人执行人id,统计executorId参与的评估周期
411 func (d *StaffAssessDao) CountAssessCycleMe(executorId int, companyId int) (int, error) { 422 func (d *StaffAssessDao) CountAssessCycleMe(executorId int, companyId int) (int, error) {
412 sqlStr := ` 423 sqlStr := `
413 - select count(DISTINCT (staff_assess_task.cycle_id ,staff_assess_task.cycle_name ,staff_assess_task.begin_day )) as cnt 424 + select count(DISTINCT (staff_assess_task.cycle_id,staff_assess_task.begin_day )) as cnt
414 FROM staff_assess_task 425 FROM staff_assess_task
415 JOIN staff_assess ON staff_assess_task."id" = staff_assess."staff_assess_task_id" 426 JOIN staff_assess ON staff_assess_task."id" = staff_assess."staff_assess_task_id"
416 WHERE staff_assess.company_id=? 427 WHERE staff_assess.company_id=?
@@ -144,6 +144,7 @@ func (repo *StaffAssessRepository) Find(queryOptions map[string]interface{}) (in @@ -144,6 +144,7 @@ func (repo *StaffAssessRepository) Find(queryOptions map[string]interface{}) (in
144 if v, ok := queryOptions["staffAssessTaskId"]; ok { 144 if v, ok := queryOptions["staffAssessTaskId"]; ok {
145 query.Where(`staff_assess_task_id=?`, v) 145 query.Where(`staff_assess_task_id=?`, v)
146 } 146 }
  147 +
147 if v, ok := queryOptions["id"]; ok { 148 if v, ok := queryOptions["id"]; ok {
148 query.Where("id=?", v) 149 query.Where("id=?", v)
149 } 150 }
@@ -129,6 +129,9 @@ func (repo *StaffAssessTaskRepository) Find(queryOptions map[string]interface{}) @@ -129,6 +129,9 @@ func (repo *StaffAssessTaskRepository) Find(queryOptions map[string]interface{})
129 if v, ok := queryOptions["evaluationProjectId"]; ok { 129 if v, ok := queryOptions["evaluationProjectId"]; ok {
130 query.Where("evaluation_project_id=?", v) 130 query.Where("evaluation_project_id=?", v)
131 } 131 }
  132 + if v, ok := queryOptions["ids"]; ok {
  133 + query.Where("id in (?) ", pg.In(v))
  134 + }
132 count, err := query.SelectAndCount() 135 count, err := query.SelectAndCount()
133 if err != nil { 136 if err != nil {
134 return 0, nil, err 137 return 0, nil, err