批量更新功能
This commit is contained in:
@@ -30,11 +30,20 @@ type crmProductPayload struct {
|
||||
TaxRate float64 `json:"tax_rate"`
|
||||
LineType string `json:"line_type"`
|
||||
DevUnitPrice float64 `json:"dev_unit_price"`
|
||||
DevMode string `json:"dev_mode"`
|
||||
DevTree json.RawMessage `json:"dev_tree"`
|
||||
Status int8 `json:"status"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// normalizeDevMode 规范软件开发「研发方式」:self=自行研发(默认)/ outsource=外协研发(别人帮我们研发)。
|
||||
func normalizeDevMode(v string) string {
|
||||
if strings.TrimSpace(v) == "outsource" {
|
||||
return "outsource"
|
||||
}
|
||||
return "self"
|
||||
}
|
||||
|
||||
// crmProductItem 项目产品清单中的单行(也用于项目生成时写入产品管理)。
|
||||
type crmProductItem struct {
|
||||
ProductNo string `json:"product_no"`
|
||||
@@ -148,9 +157,11 @@ func (c *BackendCrmProductController) Create() {
|
||||
}
|
||||
// 非开发行不保留开发字段,避免残留(如 dev_tree="[]")导致清单调用时被误判为软件开发行
|
||||
devUnitPrice := p.DevUnitPrice
|
||||
devMode := normalizeDevMode(p.DevMode)
|
||||
devTree := string(p.DevTree)
|
||||
if lineType != "dev" {
|
||||
devUnitPrice = 0
|
||||
devMode = ""
|
||||
devTree = ""
|
||||
}
|
||||
now := time.Now()
|
||||
@@ -166,6 +177,7 @@ func (c *BackendCrmProductController) Create() {
|
||||
TaxRate: p.TaxRate,
|
||||
LineType: lineType,
|
||||
DevUnitPrice: devUnitPrice,
|
||||
DevMode: devMode,
|
||||
DevTree: devTree,
|
||||
Status: status,
|
||||
Remark: p.Remark,
|
||||
@@ -221,9 +233,11 @@ func (c *BackendCrmProductController) Update() {
|
||||
}
|
||||
// 非开发行清空开发字段,避免残留导致清单调用时被误判为软件开发行
|
||||
devUnitPrice := p.DevUnitPrice
|
||||
devMode := normalizeDevMode(p.DevMode)
|
||||
devTree := string(p.DevTree)
|
||||
if lineType != "dev" {
|
||||
devUnitPrice = 0
|
||||
devMode = ""
|
||||
devTree = ""
|
||||
}
|
||||
now := time.Now()
|
||||
@@ -240,6 +254,7 @@ func (c *BackendCrmProductController) Update() {
|
||||
"tax_rate": p.TaxRate,
|
||||
"line_type": lineType,
|
||||
"dev_unit_price": devUnitPrice,
|
||||
"dev_mode": devMode,
|
||||
"dev_tree": devTree,
|
||||
"status": status,
|
||||
"remark": p.Remark,
|
||||
@@ -454,9 +469,10 @@ func SyncContractProducts(tenantID, uid string, projectID uint64, projectName st
|
||||
CreateTime: now,
|
||||
UpdateTime: now,
|
||||
}
|
||||
// 软件开发行:写入统一人天单价与模块树,作为可复用的「开发包」
|
||||
// 软件开发行:写入统一人天单价、研发方式与模块树,作为可复用的「开发包」
|
||||
if lineType == "dev" {
|
||||
row.DevUnitPrice = toFloat64(it["dev_unit_price"])
|
||||
row.DevMode = normalizeDevMode(productFieldStr(it["dev_mode"]))
|
||||
if tree := it["dev_tree"]; tree != nil {
|
||||
if b, me := json.Marshal(tree); me == nil {
|
||||
row.DevTree = string(b)
|
||||
@@ -504,7 +520,7 @@ func productFieldStr(v interface{}) string {
|
||||
return strings.TrimSpace(fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
// syncDevTreeToProduct 软件开发行引用到产品档案时,回写最新模块树与人天单价
|
||||
// syncDevTreeToProduct 软件开发行引用到产品档案时,回写最新模块树、人天单价与研发方式
|
||||
// (仅在有变化时更新;销售/成本单价不回写,仍由产品管理主导),
|
||||
// 保证后续合同再选该产品能拿到最新的开发包。
|
||||
func syncDevTreeToProduct(p *models.TenantCrmProduct, it map[string]interface{}) {
|
||||
@@ -521,12 +537,18 @@ func syncDevTreeToProduct(p *models.TenantCrmProduct, it map[string]interface{})
|
||||
}
|
||||
newTree := string(b)
|
||||
newUnitPrice := toFloat64(it["dev_unit_price"])
|
||||
if newTree == p.DevTree && newUnitPrice == p.DevUnitPrice {
|
||||
// 研发方式:清单行传了值就跟随回写(自行研发 / 外协研发)
|
||||
newMode := p.DevMode
|
||||
if m := productFieldStr(it["dev_mode"]); m != "" {
|
||||
newMode = normalizeDevMode(m)
|
||||
}
|
||||
if newTree == p.DevTree && newUnitPrice == p.DevUnitPrice && newMode == p.DevMode {
|
||||
return
|
||||
}
|
||||
p.DevTree = newTree
|
||||
p.DevUnitPrice = newUnitPrice
|
||||
_, _ = models.Orm.Update(p, "DevTree", "DevUnitPrice")
|
||||
p.DevMode = newMode
|
||||
_, _ = models.Orm.Update(p, "DevTree", "DevUnitPrice", "DevMode")
|
||||
}
|
||||
|
||||
// genProductNo 生成产品编号 P-yyyymmdd-4位序号,并保证本租户内不重复。
|
||||
|
||||
Reference in New Issue
Block a user