Chever John 379fb28d92 chore: sync codebase with upstream
Align origin/main with upstream/main (GitHub). The two branches
diverged due to pre-rebase vs post-rebase merge commits for the
k8s-amd64-dockerfiles feature.

Includes: multi-stage Go compilation Dockerfiles, pan-bolt
inventory features, CRM relations, Excel import tooling,
proto/gRPC updates, migration scripts, and tools/ directory.

Excludes deploy/bin/ pre-compiled binaries (arm64, not needed
for amd64 K3s cluster; builds use multi-stage Dockerfiles now).
2026-06-14 15:24:02 +08:00

103 lines
2.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package excelparse
import (
"strconv"
"strings"
)
// MiaozhangParser handles Excel exports from 秒账 (miaozhang.cn).
//
// Expected headers:
// 图片1 | 图片2 | 图片3 | 名称 | 规格型号 | 颜色 | 条形码 | 匹数 | 库存数量 | 成本均价 | 参考售价 | 备注 | 更新日期
type MiaozhangParser struct{}
func (p *MiaozhangParser) Name() string { return "秒账" }
func (p *MiaozhangParser) Match(headers []string) bool {
required := map[string]bool{"名称": false, "规格型号": false, "颜色": false, "匹数": false, "库存数量": false}
for _, h := range headers {
h = strings.TrimSpace(h)
if _, ok := required[h]; ok {
required[h] = true
}
}
for _, found := range required {
if !found {
return false
}
}
return true
}
func (p *MiaozhangParser) ParseRows(headers []string, rows [][]string) (*ParseResult, error) {
idx := buildIndex(headers)
var products []ParsedProduct
skipped := 0
for _, row := range rows {
name := colVal(row, idx["名称"])
if name == "" || strings.HasPrefix(name, "总") {
skipped++
continue
}
rolls, _ := strconv.ParseInt(colVal(row, idx["匹数"]), 10, 64)
products = append(products, ParsedProduct{
ProductName: name,
Spec: colVal(row, idx["规格型号"]),
Color: colVal(row, idx["颜色"]),
UnitRolls: rolls,
StockQuantity: stripUnit(colVal(row, idx["库存数量"])),
CostPrice: stripCurrency(colVal(row, idx["成本均价"])),
SalesPrice: stripCurrency(colVal(row, idx["参考售价"])),
Remark: colVal(row, idx["备注"]),
})
}
return &ParseResult{Products: products, SkippedRows: skipped}, nil
}
func buildIndex(headers []string) map[string]int {
m := make(map[string]int, len(headers))
for i, h := range headers {
m[strings.TrimSpace(h)] = i
}
return m
}
func colVal(row []string, idx int) string {
if idx < 0 || idx >= len(row) {
return ""
}
return strings.TrimSpace(row[idx])
}
// stripUnit removes trailing unit markers like "米", "kg", etc.
func stripUnit(s string) string {
s = strings.TrimSpace(s)
for _, suffix := range []string{"米", "m", "kg", "KG"} {
s = strings.TrimSuffix(s, suffix)
}
s = strings.TrimSpace(s)
if s == "" {
return "0"
}
return s
}
// stripCurrency removes leading ¥ / $ / ¥ symbols.
func stripCurrency(s string) string {
s = strings.TrimSpace(s)
for _, prefix := range []string{"¥", "¥", "$", ""} {
s = strings.TrimPrefix(s, prefix)
}
s = strings.TrimSpace(s)
if s == "" {
return "0"
}
return s
}