Files
Agent-System/internal/quote/quote.go
T

136 lines
4.4 KiB
Go

package quote
import (
"fmt"
"os"
"path/filepath"
"github.com/xuri/excelize/v2"
)
var StatutoryNotes = []string{
"1)以上价格覆盖服务范围:原理样机验证,工程样机开发,送检样机开发",
"2)以上价格不含样机物料费用,如需乙方采购,另行商议",
"3)以上不含开发阶段使用的专用测试设备和工具工装费用",
"4)以上价格不包括药监局、医疗器械检验所等任何委托测试的第三方费用,第三方费用由甲方直接与第三方结算",
"5)以上未计算临床阶段费用",
"6)不含无菌耗材委托生产费用(CMO)",
"7)不含体系搭建费用",
}
const (
bufferRate = 0.20
marginRate = 0.40
taxRate = 0.07
hoursPerPM = 160.0
)
func CalculateAndFill(in Input, templateXlsx string, outPath string) (*Summary, error) {
if _, err := os.Stat(templateXlsx); err != nil {
wd, _ := os.Getwd()
dir := wd
for i := 0; i < 10; i++ {
p := filepath.Join(dir, templateXlsx)
if _, err := os.Stat(p); err == nil {
templateXlsx = p
break
}
parent := filepath.Dir(dir)
if parent == dir {
break
}
dir = parent
}
}
f, err := excelize.OpenFile(templateXlsx)
if err != nil {
return nil, fmt.Errorf("open template %s: %w", templateXlsx, err)
}
defer f.Close()
var totalHours float64
for _, h := range in.Hours {
totalHours += h
}
pm := totalHours / hoursPerPM
baseCost := totalHours * 150.0
bufferVal := baseCost * bufferRate
marginVal := (baseCost + bufferVal) * marginRate
preTax := baseCost + bufferVal + marginVal
taxVal := preTax * taxRate
totalPrice := preTax + taxVal
summary := &Summary{
CustomerName: in.CustomerName,
ProductName: in.ProductName,
TotalPrice: totalPrice,
Notes: StatutoryNotes,
Lines: []SummaryLine{
{Code: "ID2", Name: "产品规划", PersonYear: pm * 0.1, Cost: baseCost * 0.1, Buffer: bufferVal * 0.1, Margin: marginVal * 0.1, Tax: taxVal * 0.1, Price: totalPrice * 0.1},
{Code: "ID3.3.1", Name: "设计开发工程化", PersonYear: pm * 0.7, Cost: baseCost * 0.7, Buffer: bufferVal * 0.7, Margin: marginVal * 0.7, Tax: taxVal * 0.7, Price: totalPrice * 0.7},
{Code: "ID6", Name: "DHF文档编写", PersonYear: pm * 0.2, Cost: baseCost * 0.2, Buffer: bufferVal * 0.2, Margin: marginVal * 0.2, Tax: taxVal * 0.2, Price: totalPrice * 0.2},
},
}
sheet := "报价模型"
if idx, _ := f.GetSheetIndex(sheet); idx != -1 {
_ = f.SetCellValue(sheet, "B3", in.CustomerName)
_ = f.SetCellValue(sheet, "B4", in.ProductName)
_ = f.SetCellValue(sheet, "B5", totalPrice)
_ = f.SetCellValue(sheet, "A7", "报价代码")
_ = f.SetCellValue(sheet, "B7", "服务阶段与内容")
_ = f.SetCellValue(sheet, "D7", "人年(PM)")
_ = f.SetCellValue(sheet, "E7", "基础成本(元)")
_ = f.SetCellValue(sheet, "F7", "缓冲金(20%)")
_ = f.SetCellValue(sheet, "G7", "毛利(40%)")
_ = f.SetCellValue(sheet, "H7", "税费(7%)")
_ = f.SetCellValue(sheet, "J7", "综合报价(元)")
writeSummaryLine(f, sheet, 8, summary.Lines[0])
writeSummaryLine(f, sheet, 9, summary.Lines[1])
writeSummaryLine(f, sheet, 10, summary.Lines[2])
var totalPersonYear, totalCost, totalBuffer, totalMargin, totalTax float64
for _, line := range summary.Lines {
totalPersonYear += line.PersonYear
totalCost += line.Cost
totalBuffer += line.Buffer
totalMargin += line.Margin
totalTax += line.Tax
}
writeSummaryLine(f, sheet, 18, SummaryLine{
Code: "总计",
Name: "全阶段综合报价",
PersonYear: totalPersonYear,
Cost: totalCost,
Buffer: totalBuffer,
Margin: totalMargin,
Tax: totalTax,
Price: totalPrice,
})
}
if err := os.MkdirAll(filepath.Dir(outPath), 0o755); err != nil {
return nil, err
}
if err := f.SaveAs(outPath); err != nil {
return nil, fmt.Errorf("save filled quote xlsx: %w", err)
}
return summary, nil
}
func writeSummaryLine(f *excelize.File, sheet string, row int, line SummaryLine) {
_ = f.SetCellValue(sheet, fmt.Sprintf("A%d", row), line.Code)
_ = f.SetCellValue(sheet, fmt.Sprintf("B%d", row), line.Name)
_ = f.SetCellValue(sheet, fmt.Sprintf("D%d", row), line.PersonYear)
_ = f.SetCellValue(sheet, fmt.Sprintf("E%d", row), line.Cost)
_ = f.SetCellValue(sheet, fmt.Sprintf("F%d", row), line.Buffer)
_ = f.SetCellValue(sheet, fmt.Sprintf("G%d", row), line.Margin)
_ = f.SetCellValue(sheet, fmt.Sprintf("H%d", row), line.Tax)
_ = f.SetCellValue(sheet, fmt.Sprintf("J%d", row), line.Price)
}