修复bug

This commit is contained in:
hero920103 committed 2026-11-03 17:48:07 +08:00
1 parent fc8c3ee3ad
commit 68617335f0
9 files changed
+645 -161

No files matched your search

+58 -24
View File
@@ -51,6 +51,7 @@ type projectPayload struct {
// 3=上中游项目(上游 A 公司 + 中游 B 公司,下游固定为本公司)
ProjectType int8 `json:"project_type"`
CustomerID uint64 `json:"customer_id"`
CustomerRefType int8 `json:"customer_ref_type"` // 上游主体来源:1客户 2供应商(缺省按客户库)
CustomerName string `json:"customer_name"`
SupplierID uint64 `json:"supplier_id"`
SupplierRefType int8 `json:"supplier_ref_type"` // 对方主体来源:1客户 2供应商(下游 / 中游)
@@ -68,7 +69,7 @@ type projectPayload struct {
// Reason 异常原因:状态改为「异常(5)」时必填,会写入操作日志便于追溯
Reason string `json:"reason"`
StartDate string `json:"start_date"`
EndDate string `json:"end_date"`
EndDate string `json:"end_date"`
// 上下游对接人:仅姓名 + 电话;Contact* 为旧字段,未传新字段时回退使用
UpstreamContact string `json:"upstream_contact"`
UpstreamPhone string `json:"upstream_phone"`
@@ -107,6 +108,40 @@ func normalizeProjectFields(p *projectPayload) (pt int8, upstream, downstream fl
return
}
// resolveProjectCustomer 解析项目上游主体:
// refType=2 关联供应商库(同一家单位可能只以供应商身份建档),其余按客户库(默认);
// 命中时以库中的 ID 与标准名称为准,未命中(或未选择库记录)时保留手工填写的名称、不保留关联。
func resolveProjectCustomer(tenantID string, refType int8, refID uint64, name string) (*uint64, int8, string) {
name = strings.TrimSpace(name)
if refID == 0 {
return nil, 0, name
}
if refType == 2 {
var sup models.TenantCrmSupplier
if err := models.Orm.QueryTable(new(models.TenantCrmSupplier)).
Filter("id", refID).Filter("tenant_id", tenantID).
Filter("delete_time__isnull", true).One(&sup); err != nil {
return nil, 0, name
}
id := sup.ID
if strings.TrimSpace(sup.SupplierName) != "" {
name = sup.SupplierName
}
return &id, 2, name
}
var cus models.TenantCrmCustomer
if err := models.Orm.QueryTable(new(models.TenantCrmCustomer)).
Filter("id", refID).Filter("tenant_id", tenantID).
Filter("delete_time__isnull", true).One(&cus); err != nil {
return nil, 0, name
}
id := cus.ID
if strings.TrimSpace(cus.CustomerName) != "" {
name = cus.CustomerName
}
return &id, 1, name
}
// resolveProjectSupplier 解析项目下游主体:
// refType=2 关联供应商库,refType=1 关联客户库(同一家单位可能以客户身份建档);
// 命中时以库中的 ID 与标准名称为准,未命中(或未选择库记录)时保留手工填写的名称、不保留关联。
@@ -190,7 +225,8 @@ func attachProjectContractPeriod(tenantID string, list []models.TenantCrmProject
// crmProjectNameDuplicated 项目重名校验:同租户 + 同名 + 同一客户(服务主体)才算重复。
// 不同客户的同名项目可正常创建(如两家公司都有「官网建设」项目);
// 未关联客户的项目按「客户为空」分组校验(与同样未关联客户的同名项目视为重复)。
func crmProjectNameDuplicated(tenantID, name string, customerID *uint64) bool {
// 上游来源库不同视为不同主体:客户库与供应商库各有一套 ID,需按 customer_ref_type 一并区分。
func crmProjectNameDuplicated(tenantID, name string, customerID *uint64, customerRefType int8) bool {
name = strings.TrimSpace(name)
if name == "" || strings.TrimSpace(tenantID) == "" || models.Orm == nil {
return false
@@ -201,6 +237,11 @@ func crmProjectNameDuplicated(tenantID, name string, customerID *uint64) bool {
And("project_name", name)
if customerID != nil && *customerID > 0 {
cond = cond.And("customer_id", *customerID)
if customerRefType == 2 {
cond = cond.And("customer_ref_type", 2)
} else {
cond = cond.And("customer_ref_type__in", []int{0, 1})
}
} else {
cond = cond.AndCond(orm.NewCondition().Or("customer_id__isnull", true).Or("customer_id", 0))
}
@@ -390,18 +431,8 @@ func (c *BackendCrmProjectController) Create() {
}
tenantID := pipelineTenantID(claims)
var custIDVal *uint64
customerName := strings.TrimSpace(p.CustomerName)
if p.CustomerID > 0 {
var cust models.TenantCrmCustomer
if err := models.Orm.QueryTable(new(models.TenantCrmCustomer)).
Filter("id", p.CustomerID).Filter("tenant_id", tenantID).
Filter("delete_time__isnull", true).One(&cust); err == nil {
cid := cust.ID
custIDVal = &cid
customerName = cust.CustomerName
}
}
// 上游主体:默认客户库,也可从供应商库选择(customer_ref_type=2)
custIDVal, custRefType, customerName := resolveProjectCustomer(tenantID, p.CustomerRefType, p.CustomerID, p.CustomerName)
status := p.Status
if status == 0 {
status = 1
@@ -419,6 +450,7 @@ func (c *BackendCrmProjectController) Create() {
ProjectNo: strings.TrimSpace(p.ProjectNo),
ProjectType: pt,
CustomerID: custIDVal,
CustomerRefType: custRefType,
CustomerName: customerName,
SupplierID: supplierID,
SupplierRefType: supplierRefType,
@@ -448,7 +480,7 @@ func (c *BackendCrmProjectController) Create() {
}
// 唯一性校验:同一客户(服务主体)下的同名项目不允许重复创建(重复数据请联系管理员转移跟进);
// 客户不同则允许同名创建(不同主体可各自立项,如两家客户都做「官网建设」)
if crmProjectNameDuplicated(tenantID, proj.ProjectName, proj.CustomerID) {
if crmProjectNameDuplicated(tenantID, proj.ProjectName, proj.CustomerID, proj.CustomerRefType) {
pipelineErr(&c.Controller, 409, 409, "该客户下已存在同名项目(可能由其他同事创建),如需继续跟进请联系管理员转移")
return
}
@@ -515,14 +547,11 @@ func (c *BackendCrmProjectController) Update() {
proj.ProjectName = strings.TrimSpace(p.ProjectName)
proj.ProjectNo = strings.TrimSpace(p.ProjectNo)
if p.CustomerID > 0 {
var cust models.TenantCrmCustomer
if err := models.Orm.QueryTable(new(models.TenantCrmCustomer)).
Filter("id", p.CustomerID).Filter("tenant_id", tenantID).
Filter("delete_time__isnull", true).One(&cust); err == nil {
cid := cust.ID
proj.CustomerID = &cid
proj.CustomerName = cust.CustomerName
}
// 上游主体:按来源库解析(默认客户库,也支持从供应商库选择)
cid, cref, cname := resolveProjectCustomer(tenantID, p.CustomerRefType, p.CustomerID, p.CustomerName)
proj.CustomerID = cid
proj.CustomerRefType = cref
proj.CustomerName = cname
} else if strings.TrimSpace(p.CustomerName) != "" {
proj.CustomerName = strings.TrimSpace(p.CustomerName)
}
@@ -728,7 +757,12 @@ func (c *BackendCrmProjectController) SaveContacts() {
if pt != 2 && pt != 3 {
pt = 1
}
upIDs := filterCompanyContactIDs(tenantID, "customer", proj.CustomerID, p.UpstreamContactIDs)
// 上游主体联系人:按上游来源库取(customer_ref_type=2 供应商库,其余客户库)
upCompanyType := "customer"
if proj.CustomerRefType == 2 {
upCompanyType = "supplier"
}
upIDs := filterCompanyContactIDs(tenantID, upCompanyType, proj.CustomerID, p.UpstreamContactIDs)
var downIDs []uint64
// 上下游 / 上中游项目:对方主体(下游 / 中游)联系人按 supplier_ref_type 选择对应库
if pt != 1 && proj.SupplierID != nil && *proj.SupplierID > 0 {