更新
This commit is contained in:
1 parent
5718a00e31
commit
1850ac640e
226 files changed
+37772
-12071
No files matched your search
@@ -0,0 +1,151 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"server/models"
|
||||
"server/pkg/jwtutil"
|
||||
"server/services"
|
||||
approvalEngine "server/services/approval"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
)
|
||||
|
||||
// reimburse_approval_core.go 报销单「审批人视角」操作共享逻辑。
|
||||
//
|
||||
// Web 端(/backend/reimbursements/approve|reject|my-approve-task)与
|
||||
// 小程序端(/api/oa/expense/approve|reject|my-approve-task)共用本文件;
|
||||
// 审批中心 TaskAct 也复用其中的 biz_type 判定与时间线回写。
|
||||
|
||||
// isReimburseBizType 判断审批任务/实例是否属于报销类单据。
|
||||
func isReimburseBizType(bizType string) bool {
|
||||
return approvalEngine.IsReimburseBizType(bizType)
|
||||
}
|
||||
|
||||
// claimsReimburseUIDs 当前登录用户可能出现在 approver_id 上的两种口径:
|
||||
// 认证中心 identity_id 与本租户 uid(历史上两种写法并存,这里都兼容)。
|
||||
func claimsReimburseUIDs(claims *jwtutil.Claims) []interface{} {
|
||||
raw := uint64(claims.UserID)
|
||||
out := []interface{}{raw}
|
||||
if uid := services.ResolveTenantUID(uint64(claims.TenantId), raw); uid != raw {
|
||||
out = append(out, uid)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// reimburseMyTaskCore 查当前用户在报销单 id 上的待办审批任务;无待办返回 (nil, nil)。
|
||||
func reimburseMyTaskCore(claims *jwtutil.Claims, id uint64) (*models.ApprovalTask, error) {
|
||||
tid := uint64(claims.TenantId)
|
||||
var task models.ApprovalTask
|
||||
err := models.Orm.QueryTable(new(models.ApprovalTask)).
|
||||
Filter("scope", models.ApprovalScopeTenant).
|
||||
Filter("tid", tid).
|
||||
Filter("biz_type", models.ApprovalBizReimburse).
|
||||
Filter("biz_id", id).
|
||||
Filter("status", models.ApprovalTaskPending).
|
||||
Filter("is_deleted", 0).
|
||||
Filter("approver_id__in", claimsReimburseUIDs(claims)...).
|
||||
OrderBy("-id").One(&task)
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &task, nil
|
||||
}
|
||||
|
||||
// reimburseActCore 报销单审批操作共享逻辑(pass=true 通过 / false 驳回)。
|
||||
//
|
||||
// 返回 (httpCode, errMsg, hint):errMsg 非空表示失败;成功时 hint 为提示文案。
|
||||
// 节点流转交由统一审批引擎,本函数负责定位当前用户的待办任务并补记业务时间线。
|
||||
func reimburseActCore(claims *jwtutil.Claims, id uint64, pass bool, comment string) (int, string, string) {
|
||||
if _, err := findOwnedReimbursement(claims, id); err != nil {
|
||||
return 404, "报销单不存在", ""
|
||||
}
|
||||
task, err := reimburseMyTaskCore(claims, id)
|
||||
if err != nil {
|
||||
return 500, "查询审批任务失败", ""
|
||||
}
|
||||
if task == nil {
|
||||
return 400, "当前没有待您审批的节点", ""
|
||||
}
|
||||
|
||||
result, err := approvalEngine.Approve(task.ID, approvalEngine.ApproveInput{
|
||||
ApproverID: task.ApproverID,
|
||||
Pass: pass,
|
||||
Comment: comment,
|
||||
})
|
||||
if err != nil {
|
||||
return 400, err.Error(), ""
|
||||
}
|
||||
|
||||
applyReimburseApprovalResult(uint64(claims.TenantId), id,
|
||||
uint64(claims.UserID), claims.Username, task.Sort,
|
||||
pass, comment, result.Finished, result.InstanceStat)
|
||||
|
||||
hint := result.Message
|
||||
if hint == "" {
|
||||
if pass {
|
||||
hint = "审批通过"
|
||||
} else {
|
||||
hint = "已驳回"
|
||||
}
|
||||
}
|
||||
return 200, "", hint
|
||||
}
|
||||
|
||||
// applyReimburseApprovalResult 把一次审批动作回写到报销业务侧:
|
||||
// 补记 yz_backend_approval_records 时间线;流程结束时同步单据终态(引擎的
|
||||
// SyncBizResult 也会做同样的事,这里按终态幂等,避免重复插记录)。
|
||||
func applyReimburseApprovalResult(tid, bizID, actorID uint64, actorName string, step int,
|
||||
pass bool, comment string, finished bool, instStatus int8) {
|
||||
if tid == 0 || bizID == 0 {
|
||||
return
|
||||
}
|
||||
action := int8(models.ApprovalActionApprove)
|
||||
if !pass {
|
||||
action = models.ApprovalActionReject
|
||||
}
|
||||
|
||||
var row models.BackendReimbursement
|
||||
if err := models.Orm.QueryTable(new(models.BackendReimbursement)).
|
||||
Filter("id", bizID).Filter("tid", tid).Filter("is_deleted", 0).One(&row); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 终态同步(审批中→通过/驳回),引擎已同步过则跳过
|
||||
var bizStatus int8
|
||||
if finished {
|
||||
switch instStatus {
|
||||
case models.ApprovalInstanceApproved:
|
||||
bizStatus = 2
|
||||
case models.ApprovalInstanceRejected:
|
||||
bizStatus = 3
|
||||
}
|
||||
if bizStatus != 0 && row.Status != bizStatus {
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendReimbursement)).
|
||||
Filter("id", bizID).Filter("tid", tid).
|
||||
Update(orm.Params{"status": bizStatus, "current_approver_id": 0, "update_time": time.Now()})
|
||||
}
|
||||
}
|
||||
|
||||
// 时间线去重:同一步骤同一动作只记一次
|
||||
dup := models.Orm.QueryTable(new(models.BackendApprovalRecord)).
|
||||
Filter("tid", tid).Filter("reimbursement_id", bizID).
|
||||
Filter("approver_id", actorID).Filter("action", action).
|
||||
Filter("step", int8(step)).Filter("is_deleted", 0).Exist()
|
||||
if dup {
|
||||
return
|
||||
}
|
||||
var commentPtr *string
|
||||
if comment != "" {
|
||||
commentPtr = &comment
|
||||
}
|
||||
_, _ = models.Orm.Insert(&models.BackendApprovalRecord{
|
||||
Tid: tid, UID: uint64Ptr(actorID), ReimbursementID: bizID,
|
||||
ApproverID: actorID, ApproverName: fmt.Sprintf("%s", actorName), Action: action,
|
||||
Comment: commentPtr, Step: int8(step), PrevStep: int8(step),
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user