批量优化产品和产品分类
This commit is contained in:
@@ -81,6 +81,7 @@ func (c *BackendCrmContractController) List() {
|
||||
ourRole := strings.TrimSpace(c.GetString("our_role"))
|
||||
category := strings.TrimSpace(c.GetString("contract_category"))
|
||||
projectType := strings.TrimSpace(c.GetString("project_type"))
|
||||
projectID := strings.TrimSpace(c.GetString("project_id"))
|
||||
status := strings.TrimSpace(c.GetString("status"))
|
||||
|
||||
tenantID := pipelineTenantID(claims)
|
||||
@@ -110,6 +111,12 @@ func (c *BackendCrmContractController) List() {
|
||||
case "headless": // 无头合同
|
||||
cond = cond.And("project_id__isnull", true)
|
||||
}
|
||||
// 按项目精确筛选(项目详情「合同管理」Tab:一个项目可关联多份合同)
|
||||
if projectID != "" {
|
||||
if pid, err := strconv.ParseUint(projectID, 10, 64); err == nil && pid > 0 {
|
||||
cond = cond.And("project_id", pid)
|
||||
}
|
||||
}
|
||||
qs := models.Orm.QueryTable(new(models.TenantCrmContract)).SetCond(cond)
|
||||
|
||||
total, _ := qs.Count()
|
||||
@@ -244,6 +251,10 @@ func (c *BackendCrmContractController) Create() {
|
||||
return
|
||||
}
|
||||
row.Products = products
|
||||
// 合同产品清单同步到产品管理(新增产品自动建档、成本单价取产品管理)
|
||||
if synced, serr := SyncContractProducts(tenantID, pipelineUID(claims), json.RawMessage(products)); serr == nil {
|
||||
row.Products = string(synced)
|
||||
}
|
||||
applyContractAmounts(&row)
|
||||
|
||||
if _, err := models.Orm.Insert(&row); err != nil {
|
||||
@@ -336,6 +347,10 @@ func (c *BackendCrmContractController) Update() {
|
||||
return
|
||||
}
|
||||
row.Products = products
|
||||
// 合同产品清单同步到产品管理(新增产品自动建档、成本单价取产品管理)
|
||||
if synced, serr := SyncContractProducts(tenantID, pipelineUID(claims), json.RawMessage(products)); serr == nil {
|
||||
row.Products = string(synced)
|
||||
}
|
||||
}
|
||||
applyContractAmounts(&row)
|
||||
if p.Status != 0 {
|
||||
@@ -512,8 +527,11 @@ func normalizeContractJSON(raw json.RawMessage) (string, error) {
|
||||
}
|
||||
|
||||
// applyContractAmounts 按产品清单重算各部分金额(与前端 ProductList 汇总口径一致):
|
||||
// 硬件部分=Σ硬件小计;软件部分=Σ软件小计;其他部分=Σ服务/开发/其他小计;
|
||||
// 合同总金额=硬件+软件+其他;产品总成本=Σ(数量×成本单价);合同总利润=总金额-总成本。
|
||||
// 每行含税金额=数量×单价×(1+税率/100);
|
||||
// 硬件部分=Σ硬件含税小计;软件部分=Σ软件含税小计;其他部分=Σ服务/开发/其他含税小计;
|
||||
// 合同总金额(含税)=硬件+软件+其他;产品总成本=Σ(数量×成本单价)(成本通常不含税,原值汇总);
|
||||
// 合同总利润=总金额-总成本。
|
||||
// 归类口径:分类代码 1/2 或名称含「硬件」/「软件」分别计入硬件/软件,其余计入其他。
|
||||
func applyContractAmounts(row *models.TenantCrmContract) {
|
||||
var items []map[string]interface{}
|
||||
if strings.TrimSpace(row.Products) != "" {
|
||||
@@ -524,13 +542,14 @@ func applyContractAmounts(row *models.TenantCrmContract) {
|
||||
qty := toFloat64(item["quantity"])
|
||||
price := toFloat64(item["price"])
|
||||
costPrice := toFloat64(item["cost_price"])
|
||||
amount := round2(qty * price)
|
||||
taxRate := toFloat64(item["tax_rate"])
|
||||
amount := round2(qty * price * (1 + taxRate/100)) // 含税金额
|
||||
cost = round2(cost + round2(qty*costPrice))
|
||||
cat := fmt.Sprintf("%v", item["category"])
|
||||
switch cat {
|
||||
case "1":
|
||||
switch {
|
||||
case cat == "1" || strings.Contains(cat, "硬件"):
|
||||
hardware = round2(hardware + amount)
|
||||
case "2":
|
||||
case cat == "2" || strings.Contains(cat, "软件"):
|
||||
software = round2(software + amount)
|
||||
default:
|
||||
other = round2(other + amount)
|
||||
|
||||
Reference in New Issue
Block a user