优化项目管理
This commit is contained in:
@@ -60,10 +60,12 @@ type paybackPayload struct {
|
||||
ReceiptName string `json:"receipt_name"` // 流水回执文件名(选填)
|
||||
}
|
||||
|
||||
// paybackResp 列表 / 详情响应:items 解析为 JSON 数组透出。
|
||||
// paybackResp 列表 / 详情响应:items 解析为 JSON 数组透出;
|
||||
// children 为回款明细(树形子集:该计划下一笔笔实际回款记录)。
|
||||
type paybackResp struct {
|
||||
models.TenantCrmPayback
|
||||
Items json.RawMessage `json:"items"`
|
||||
Items json.RawMessage `json:"items"`
|
||||
Children []models.TenantCrmPaybackRecord `json:"children"`
|
||||
}
|
||||
|
||||
// paybackProgress 回款进度行(跨计划摊平的计划明细)。
|
||||
@@ -109,6 +111,8 @@ func (c *BackendCrmPaybackController) List() {
|
||||
|
||||
tenantID := pipelineTenantID(claims)
|
||||
cond := orm.NewCondition().And("tenant_id", tenantID).And("delete_time__isnull", true)
|
||||
// 数据范围:平台/租户管理员可见全部,其他用户仅本人(负责人或创建人)
|
||||
cond = crmApplyOwnerScope(cond, claims)
|
||||
if keyword != "" {
|
||||
cond = cond.AndCond(orm.NewCondition().
|
||||
Or("contract_name__contains", keyword).
|
||||
@@ -138,9 +142,32 @@ func (c *BackendCrmPaybackController) List() {
|
||||
// 排序:进行中(1) 在前、已完成(2) 在后,同状态内按最新创建优先
|
||||
_, _ = qs.OrderBy("status", "-id").Offset((page - 1) * pageSize).Limit(pageSize).All(&list)
|
||||
}
|
||||
// 组装树形数据:每个回款计划挂上它的回款记录作为明细子集
|
||||
planIDs := make([]uint64, 0, len(list))
|
||||
for i := range list {
|
||||
planIDs = append(planIDs, list[i].ID)
|
||||
}
|
||||
recordsByPlan := make(map[uint64][]models.TenantCrmPaybackRecord, len(list))
|
||||
if len(planIDs) > 0 {
|
||||
var recs []models.TenantCrmPaybackRecord
|
||||
_, _ = models.Orm.QueryTable(new(models.TenantCrmPaybackRecord)).
|
||||
Filter("tenant_id", tenantID).
|
||||
Filter("payback_id__in", planIDs).
|
||||
Filter("delete_time__isnull", true).
|
||||
OrderBy("-received_date", "-id").All(&recs)
|
||||
for _, r := range recs {
|
||||
recordsByPlan[r.PaybackID] = append(recordsByPlan[r.PaybackID], r)
|
||||
}
|
||||
}
|
||||
items := make([]paybackResp, 0, len(list))
|
||||
for i := range list {
|
||||
items = append(items, buildPaybackResp(&list[i]))
|
||||
resp := buildPaybackResp(&list[i])
|
||||
if recs := recordsByPlan[list[i].ID]; len(recs) > 0 {
|
||||
resp.Children = recs
|
||||
} else {
|
||||
resp.Children = []models.TenantCrmPaybackRecord{}
|
||||
}
|
||||
items = append(items, resp)
|
||||
}
|
||||
|
||||
// 汇总(当前筛选条件下全部计划的计划总额 / 已回款 / 待回款),用于列表页统计卡片
|
||||
@@ -271,6 +298,11 @@ func (c *BackendCrmPaybackController) Update() {
|
||||
pipelineErr(&c.Controller, 404, 404, "回款计划未找到")
|
||||
return
|
||||
}
|
||||
// 数据范围校验:非管理员仅能操作本人(负责人或创建人)的数据
|
||||
if !canAccessCrmRecord(claims, row.OwnerUserID, row.CreateUserID) {
|
||||
pipelineErr(&c.Controller, 403, 403, "无权操作该回款计划数据")
|
||||
return
|
||||
}
|
||||
|
||||
if p.ContractID > 0 {
|
||||
row.ContractID = &p.ContractID
|
||||
@@ -302,20 +334,23 @@ func (c *BackendCrmPaybackController) Update() {
|
||||
row.Status = pickInt8(p.Status, 1, 2)
|
||||
}
|
||||
if p.Items != nil {
|
||||
itemsJSON, _, err := normalizePaybackItems(p.Items)
|
||||
itemsJSON, total, err := normalizePaybackItems(p.Items)
|
||||
if err != nil {
|
||||
pipelineErr(&c.Controller, 400, 400, "计划明细格式错误")
|
||||
return
|
||||
}
|
||||
row.Items = itemsJSON
|
||||
row.TotalAmount = total // 计划总额随明细重算
|
||||
}
|
||||
applyPaybackReceived(&row)
|
||||
row.UpdateTime = time.Now()
|
||||
|
||||
if _, err := models.Orm.Update(&row); err != nil {
|
||||
pipelineErr(&c.Controller, 500, 500, "更新失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
// 已回款金额一律以「回款记录」为准重新汇总:
|
||||
// 明细里不承载实收数据,若此处按明细重算,编辑计划(如调整回款日期)会把已回款冲成 0。
|
||||
refreshPlanReceived(tenantID, row.ID)
|
||||
crmWriteLog(tenantID, 4, row.ID, "update", "更新回款计划:"+row.ContractName, claims)
|
||||
pipelineOk(&c.Controller, map[string]interface{}{"id": row.ID})
|
||||
}
|
||||
@@ -340,10 +375,20 @@ func (c *BackendCrmPaybackController) Delete() {
|
||||
pipelineErr(&c.Controller, 404, 404, "回款计划未找到")
|
||||
return
|
||||
}
|
||||
// 数据范围校验:非管理员仅能操作本人(负责人或创建人)的数据
|
||||
if !canAccessCrmRecord(claims, row.OwnerUserID, row.CreateUserID) {
|
||||
pipelineErr(&c.Controller, 403, 403, "无权操作该回款计划数据")
|
||||
return
|
||||
}
|
||||
if !canDeleteCrmRecord(claims, row.CreateUserID) {
|
||||
pipelineErr(&c.Controller, 403, 403, "只有创建人、租户管理员或平台管理员可以删除该回款计划")
|
||||
return
|
||||
}
|
||||
// 已完成(回款已收齐)的回款计划不允许删除
|
||||
if row.Status == 2 {
|
||||
pipelineErr(&c.Controller, 400, 400, "该回款计划已完成(回款已收齐),不允许删除")
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
_, err = models.Orm.QueryTable(new(models.TenantCrmPayback)).
|
||||
Filter("id", id).Filter("tenant_id", tenantID).
|
||||
@@ -369,6 +414,8 @@ func (c *BackendCrmPaybackController) ProgressList() {
|
||||
contractID := strings.TrimSpace(c.GetString("contract_id"))
|
||||
|
||||
cond := orm.NewCondition().And("tenant_id", tenantID).And("delete_time__isnull", true)
|
||||
// 数据范围:平台/租户管理员可见全部,其他用户仅本人(负责人或创建人)
|
||||
cond = crmApplyOwnerScope(cond, claims)
|
||||
if keyword != "" {
|
||||
cond = cond.AndCond(orm.NewCondition().
|
||||
Or("contract_name__contains", keyword).
|
||||
@@ -456,6 +503,11 @@ func (c *BackendCrmPaybackController) Receive() {
|
||||
pipelineErr(&c.Controller, 404, 404, "回款计划未找到")
|
||||
return
|
||||
}
|
||||
// 数据范围校验:非管理员仅能操作本人(负责人或创建人)的数据
|
||||
if !canAccessCrmRecord(claims, row.OwnerUserID, row.CreateUserID) {
|
||||
pipelineErr(&c.Controller, 403, 403, "无权操作该回款计划数据")
|
||||
return
|
||||
}
|
||||
items := parsePaybackItems(row.Items)
|
||||
matched := false
|
||||
for i := range items {
|
||||
@@ -664,6 +716,8 @@ func (c *BackendCrmPaybackController) RecordList() {
|
||||
paybackID, _ := c.GetUint64("payback_id")
|
||||
|
||||
cond := orm.NewCondition().And("tenant_id", tenantID).And("delete_time__isnull", true)
|
||||
// 数据范围:平台/租户管理员可见全部,其他用户仅本人(负责人或创建人)
|
||||
cond = crmApplyOwnerScope(cond, claims)
|
||||
if contractID > 0 {
|
||||
cond = cond.And("contract_id", contractID)
|
||||
}
|
||||
@@ -678,6 +732,7 @@ func (c *BackendCrmPaybackController) RecordList() {
|
||||
// (已回款由回款记录汇总回写,兼容历史计划)
|
||||
var totalPlanned, totalReceived float64
|
||||
planCond := orm.NewCondition().And("tenant_id", tenantID).And("delete_time__isnull", true)
|
||||
planCond = crmApplyOwnerScope(planCond, claims)
|
||||
if contractID > 0 {
|
||||
planCond = planCond.And("contract_id", contractID)
|
||||
}
|
||||
@@ -792,6 +847,14 @@ func (c *BackendCrmPaybackController) DeleteRecord() {
|
||||
pipelineErr(&c.Controller, 404, 404, "回款记录不存在")
|
||||
return
|
||||
}
|
||||
// 所属回款计划已完成(回款已收齐)时不允许删除回款记录,避免破坏已完成状态
|
||||
var plan models.TenantCrmPayback
|
||||
if err := models.Orm.QueryTable(new(models.TenantCrmPayback)).
|
||||
Filter("id", row.PaybackID).Filter("tenant_id", tenantID).
|
||||
Filter("delete_time__isnull", true).One(&plan); err == nil && plan.Status == 2 {
|
||||
pipelineErr(&c.Controller, 400, 400, "所属回款计划已完成(回款已收齐),不允许删除回款记录")
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
if _, err := models.Orm.QueryTable(new(models.TenantCrmPaybackRecord)).
|
||||
Filter("id", id).Filter("tenant_id", tenantID).
|
||||
|
||||
Reference in New Issue
Block a user