103 lines
2.5 KiB
Go
103 lines
2.5 KiB
Go
|
|
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
|
|||
|
|
}
|