Files
bj_power/bj_power_wms/internal/handler/excel.go
T
SunYF 68f50ee46e refactor(wms): 合并库存表为统一inventory,重构业务逻辑
1. 合并inventory_batch与serial_number为统一inventory表,用manage_mode区分结构件批次/精密件SN
2. 移除冗余的material_type字段与相关逻辑
3. 重构库存查询、检验、入库出库等业务逻辑适配新表结构
4. 调整前端路由与菜单,拆分基础数据为区域维护和物料档案
5. 优化入库校验逻辑,避免空单问题
6. 调整Vite构建配置,关闭自动清空输出目录
7. 为各模块添加详细中文注释,统一业务术语
8. 生成并更新Ent自动代码文件
2026-09-02 08:21:11 +08:00

135 lines
3.6 KiB
Go

package handler
import (
"fmt"
"net/http"
"strings"
"bj_power_wms/ent/inventory"
"bj_power_wms/ent/material"
"bj_power_wms/internal/svc"
"github.com/xuri/excelize/v2"
)
// excelInboundHandler Excel 批量导入入库(结构件)
// 列头(第一行忽略):物料编码 | 批次号(可空,自动生成) | 数量 | 生产日期 | 供应商 | 区域 | 备注
func excelInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseMultipartForm(20 << 20); err != nil {
fail(w, http.StatusBadRequest, "文件上传失败: "+err.Error())
return
}
f, _, err := r.FormFile("file")
if err != nil {
fail(w, http.StatusBadRequest, "缺少 file 字段")
return
}
defer f.Close()
xl, err := excelize.OpenReader(f)
if err != nil {
fail(w, http.StatusBadRequest, "无法解析 Excel: "+err.Error())
return
}
defer xl.Close()
sheet := xl.GetSheetList()[0]
rows, err := xl.GetRows(sheet)
if err != nil {
fail(w, http.StatusBadRequest, "读取工作表失败: "+err.Error())
return
}
type resultRow struct {
Row int `json:"row"`
Code string `json:"materialCode"`
BatchNo string `json:"batchNo"`
Qty int `json:"quantity"`
Error string `json:"error,omitempty"`
}
results := []resultRow{}
success := 0
for i, row := range rows {
if i == 0 {
continue // 表头
}
cell := func(idx int) string {
if idx < len(row) {
return strings.TrimSpace(row[idx])
}
return ""
}
code := cell(0)
batchNo := cell(1)
qtyStr := cell(2)
qty := atoi(qtyStr, 0)
prodDate := cell(3)
supplier := cell(4)
zone := cell(5)
remark := cell(6)
res := resultRow{Row: i + 1, Code: code, BatchNo: batchNo, Qty: qty}
switch {
case code == "":
res.Error = "物料编码为空"
case qty <= 0:
res.Error = "数量必须大于 0"
default:
m, err := ctx.EntClient.Material.Query().
Where(material.CodeEQ(code)).Only(ctx0())
if err != nil {
res.Error = "物料不存在"
} else if m.ManageMode == 2 {
res.Error = "精密件请使用 SN 扫码入库,不支持 Excel 导入"
} else {
if batchNo == "" {
batchNo = genBatchNo(code)
}
// 同批次追加或新建
existing, err := ctx.EntClient.Inventory.Query().
Where(inventory.ManageModeEQ(1), inventory.BatchNoEQ(batchNo)).Only(ctx0())
if err == nil {
ctx.EntClient.Inventory.UpdateOneID(existing.ID).
AddQuantity(qty).
SetNillableSupplier(strPtr(supplier)).
ExecX(ctx0())
} else {
ctx.EntClient.Inventory.Create().
SetManageMode(1).
SetBatchNo(batchNo).
SetMaterialCode(code).
SetNillableMaterialName(strPtr(m.Name)).
SetQuantity(qty).
SetLockedQty(0).
SetNillableProductionDate(strPtr(prodDate)).
SetNillableSupplier(strPtr(supplier)).
SetQualityStatus("未检").
SetNillableZoneCode(strPtr(zone)).
SetStatus("在库").
SaveX(ctx0())
}
inboundNo := "IB" + nowStr() + fmt.Sprintf("%03d", i)
ctx.EntClient.InboundOrder.Create().
SetInboundNo(inboundNo).
SetNillableInboundType(strPtr("purchase")).
SetMaterialCode(code).
SetNillableMaterialName(strPtr(m.Name)).
SetManageMode(1).
SetNillableZoneCode(strPtr(zone)).
SetQuantity(qty).
SetNillableRemark(strPtr(remark)).
SetOperator("excel-import").
SaveX(ctx0())
res.BatchNo = batchNo
success++
}
}
results = append(results, res)
}
ok(w, map[string]any{"total": len(results), "success": success, "rows": results})
}
}