From 5d5b1358529e74608ba5874fdcc5155675900eaf Mon Sep 17 00:00:00 2001 From: chenlin Date: Fri, 10 Nov 2023 17:49:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=95=86=E5=93=81=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E3=80=81=E5=95=86=E5=93=81=E8=B5=84=E6=96=99=E6=89=B9?= =?UTF-8?q?=E9=87=8F=E5=AF=BC=E5=85=A5=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/apis/basic/category.go | 15 +- app/admin/apis/basic/commodity.go | 75 +++- app/admin/models/category.go | 6 +- app/admin/models/file.go | 502 +++++++++++++++++++---- app/admin/models/tools/productCounter.go | 34 ++ app/admin/router/commodity.go | 1 + docs/docs.go | 81 +++- docs/swagger.json | 81 +++- docs/swagger.yaml | 55 ++- 9 files changed, 729 insertions(+), 121 deletions(-) create mode 100644 app/admin/models/tools/productCounter.go diff --git a/app/admin/apis/basic/category.go b/app/admin/apis/basic/category.go index 722c063..f3c48a3 100644 --- a/app/admin/apis/basic/category.go +++ b/app/admin/apis/basic/category.go @@ -236,7 +236,7 @@ func CategoryImportView(c *gin.Context) { } fmt.Println("header:", header.Filename) - _, colsMap, err := models.FileExcelImport([]byte(readAll), nil) + _, colsMap, err := models.FileExcelReader([]byte(readAll), nil) if err != nil { //logger.Error("file excel reader err:", err) app.Error(c, http.StatusInternalServerError, err, err.Error()) @@ -275,10 +275,10 @@ func CategoryImport(c *gin.Context) { } fmt.Println("header:", header.Filename) - _, colsMap, err := models.FileExcelReader([]byte(readAll), nil) + _, colsMap, err := models.FileExcelImport([]byte(readAll), nil, 1) if err != nil { //logger.Error("file excel reader err:", err) - app.Error(c, http.StatusInternalServerError, err, "预览失败") + app.Error(c, http.StatusInternalServerError, err, err.Error()) return } fmt.Println("colsMap:", colsMap) @@ -286,6 +286,13 @@ func CategoryImport(c *gin.Context) { colsMap = colsMap[1:] } - app.OK(c, &colsMap, "") + err = models.ImportCategoryData(colsMap, (middleware.GetCooperativeBusinessId(c))) + if err != nil { + //logger.Error("file excel reader err:", err) + app.Error(c, http.StatusInternalServerError, err, err.Error()) + return + } + + app.OK(c, nil, "导入成功") return } diff --git a/app/admin/apis/basic/commodity.go b/app/admin/apis/basic/commodity.go index a88871a..3b689cb 100644 --- a/app/admin/apis/basic/commodity.go +++ b/app/admin/apis/basic/commodity.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "github.com/gin-gonic/gin" + "go-admin/app/admin/middleware" "go-admin/app/admin/models" orm "go-admin/common/global" "go-admin/tools/app" @@ -89,18 +90,24 @@ func CommodityCreate(c *gin.Context) { } commodity.IdInit() - var catCommodity models.ErpCommodity - err = orm.Eloquent.Table("erp_commodity").Where("erp_category_id=?", req.ErpCategoryId). - Order("id DESC").Limit(1).Find(&catCommodity).Error - if err != nil && err != models.RecordNotFound { - //logger.Error("cat erp commodity err:", err) - app.Error(c, http.StatusInternalServerError, err, "创建失败") + //var catCommodity models.ErpCommodity + //err = orm.Eloquent.Table("erp_commodity").Where("erp_category_id=?", req.ErpCategoryId). + // Order("id DESC").Limit(1).Find(&catCommodity).Error + //if err != nil && err != models.RecordNotFound { + // //logger.Error("cat erp commodity err:", err) + // app.Error(c, http.StatusInternalServerError, err, "创建失败") + // return + //} + //if catCommodity.Number != 0 { + // commodity.Number = catCommodity.Number + 1 + //} + //commodity.SerialNumber = fmt.Sprintf("%06d%04d", commodity.ErpCategory.FullNum, commodity.Number) + + commodity.SerialNumber, err = models.GenerateSerialNumber(req.ErpCategoryId) + if err != nil { + app.Error(c, http.StatusInternalServerError, err, err.Error()) return } - if catCommodity.Number != 0 { - commodity.Number = catCommodity.Number + 1 - } - commodity.SerialNumber = fmt.Sprintf("%06d%04d", commodity.ErpCategory.FullNum, commodity.Number) err = orm.Eloquent.Create(commodity).Error if err != nil { @@ -316,7 +323,7 @@ func CommodityDel(c *gin.Context) { return } -// BatchImportView 导入商品资料预览 +// CommodityImportView 导入商品资料预览 // @Summary 导入商品资料预览 // @Tags 商品资料 // @Produce json @@ -354,3 +361,49 @@ func CommodityImportView(c *gin.Context) { app.OK(c, &colsMap, "") return } + +// CommodityImport 导入商品资料 +// @Summary 导入商品资料 +// @Tags 商品资料 +// @Produce json +// @Accept json +// @Param file body string true "上传excel文件" +// @Success 200 {object} app.Response +// @Router /api/v1/commodity/import_commodity [post] +func CommodityImport(c *gin.Context) { + file, header, err := c.Request.FormFile("file") + if err != nil { + //logger.Error("form file err:", err) + app.Error(c, http.StatusInternalServerError, err, "预览失败") + return + } + + readAll, err := io.ReadAll(file) + if err != nil { + //logger.Error("read all err:", err) + app.Error(c, http.StatusInternalServerError, err, "预览失败") + return + } + + fmt.Println("header:", header.Filename) + _, colsMap, err := models.FileExcelImport([]byte(readAll), nil, 2) + if err != nil { + //logger.Error("file excel reader err:", err) + app.Error(c, http.StatusInternalServerError, err, err.Error()) + return + } + fmt.Println("colsMap:", colsMap) + if len(colsMap) != 0 { + colsMap = colsMap[1:] + } + + err = models.ImportCommodityData(colsMap, middleware.GetCooperativeBusinessId(c)) + if err != nil { + //logger.Error("file excel reader err:", err) + app.Error(c, http.StatusInternalServerError, err, err.Error()) + return + } + + app.OK(c, nil, "导入成功") + return +} diff --git a/app/admin/models/category.go b/app/admin/models/category.go index febfd2a..ed5f411 100644 --- a/app/admin/models/category.go +++ b/app/admin/models/category.go @@ -12,10 +12,10 @@ type Category struct { Model Name string `json:"name"` // 分类名称 - Number string `json:"number"` //编号 + Number string `json:"number"` // 编号 Display int8 `json:"display"` // 1 展示 0 隐藏 - Pid uint32 `json:"pid" gorm:"index"` //父分类的编号 - CooperativeBusinessId uint32 `json:"cooperative_business_id"` //合作商id + Pid uint32 `json:"pid" gorm:"index"` // 父分类的编号 + CooperativeBusinessId uint32 `json:"cooperative_business_id"` // 合作商id } var ( diff --git a/app/admin/models/file.go b/app/admin/models/file.go index 0032daa..7e17b26 100644 --- a/app/admin/models/file.go +++ b/app/admin/models/file.go @@ -7,7 +7,12 @@ import ( "fmt" "github.com/codinl/go-logger" "github.com/xuri/excelize/v2" + "go-admin/app/admin/models/tools" + orm "go-admin/common/global" + "gorm.io/gorm" "reflect" + "strconv" + "strings" ) type CategoryExcel struct { @@ -57,163 +62,147 @@ func getJSONTagNames(s interface{}) []string { func FileExcelReader(d []byte, cols []string) ([]byte, []map[string]interface{}, error) { reader, err := excelize.OpenReader(bytes.NewReader(d)) if err != nil { - logger.Error("open reader err:", err) - return nil, nil, err + return nil, nil, fmt.Errorf("open reader error: %v", err) } sheetList := reader.GetSheetList() if len(sheetList) == 0 { - logger.Error("sheet list nil") - return nil, nil, err + return nil, nil, errors.New("sheet list is empty") } + rows, err := reader.Rows(sheetList[0]) if err != nil { - logger.Error("reader rows err:", err) - return nil, nil, err + return nil, nil, fmt.Errorf("reader rows error: %v", err) } + sheetCols, err := reader.GetCols(sheetList[0]) if err != nil { - logger.Error("reader get cols err:", err) - return nil, nil, err + return nil, nil, fmt.Errorf("reader get cols error: %v", err) } if len(sheetCols) == 0 { - logger.Error("get cols null err") - return nil, nil, err + return nil, nil, errors.New("get cols is empty") } - colsMap := make([]map[string]interface{}, 0) + + var colsMap []map[string]interface{} if len(cols) == 0 { - if sheetList[0] == "导分类" { + switch sheetList[0] { + case "导分类": cols = getJSONTagNames(CategoryExcel{}) - } else if sheetList[0] == "导商品" { + case "导商品": cols = getJSONTagNames(CommodityExcel{}) - } else { + default: cols = make([]string, len(sheetCols)) - for i := 0; i < len(sheetCols); i++ { + for i := range sheetCols { cols[i] = fmt.Sprintf("c%02d", i) } } - } else { - fmt.Println("cols", len(cols)) - fmt.Println("sheetCols", len(sheetCols)) - if len(cols) != len(sheetCols) { - logger.Error("cols length not equal columns") - return nil, nil, errors.New("cols length not equal columns") - } + } else if len(cols) != len(sheetCols) { + return nil, nil, errors.New("cols length does not match the number of columns") } for rows.Next() { columns, err := rows.Columns() if err != nil { - logger.Error("rows columns err:", err) - return nil, nil, err + return nil, nil, fmt.Errorf("rows columns error: %v", err) } - columnMap := make(map[string]interface{}, 0) - for i, _ := range cols { - columnMap[cols[i]] = "" + columnMap := make(map[string]interface{}, len(cols)) + for i, col := range cols { + if i < len(columns) { + columnMap[col] = columns[i] + } else { + columnMap[col] = "" + } } - for i, _ := range columns { - columnMap[cols[i]] = columns[i] - } - fmt.Println("columnMap:", columnMap) + + logger.Info("columnMap:", columnMap) colsMap = append(colsMap, columnMap) } - fmt.Println("colsMap:", colsMap) + logger.Info("colsMap:", colsMap) mCols, err := json.Marshal(colsMap) if err != nil { - logger.Error("marshal err:", err) - return mCols, nil, err + return mCols, nil, fmt.Errorf("marshal error: %v", err) } return mCols, colsMap, nil } // 导入excel数据(校验必填项) -func FileExcelImport(d []byte, cols []string) ([]byte, []map[string]interface{}, error) { +func FileExcelImport(d []byte, cols []string, ntype int) ([]byte, []map[string]interface{}, error) { reader, err := excelize.OpenReader(bytes.NewReader(d)) if err != nil { - logger.Error("open reader err:", err) - return nil, nil, err + return nil, nil, fmt.Errorf("open reader error: %v", err) } sheetList := reader.GetSheetList() if len(sheetList) == 0 { - logger.Error("sheet list nil") - return nil, nil, err + return nil, nil, errors.New("sheet list is empty") } + rows, err := reader.Rows(sheetList[0]) if err != nil { - logger.Error("reader rows err:", err) - return nil, nil, err + return nil, nil, fmt.Errorf("reader rows err: %v", err) } + sheetCols, err := reader.GetCols(sheetList[0]) if err != nil { - logger.Error("reader get cols err:", err) - return nil, nil, err + return nil, nil, fmt.Errorf("reader get cols err: %v", err) } + if len(sheetCols) == 0 { - logger.Error("get cols null err") - return nil, nil, err + return nil, nil, errors.New("get cols is empty") } - colsMap := make([]map[string]interface{}, 0) + + var colsMap []map[string]interface{} if len(cols) == 0 { - if sheetList[0] == "导分类" { - //校验商品分类导入规则 - err := checkCategoryExcel(sheetCols) - if err != nil { + switch ntype { // 导入类型:1 商品分类 2 商品资料 + case 1: + if sheetList[0] != "导分类" { + return nil, nil, errors.New("格式错误,不是分类模版excel") + } + if err := checkCategoryExcel(sheetCols); err != nil { return nil, nil, err } cols = getJSONTagNames(CategoryExcel{}) - } else if sheetList[0] == "导商品" { - //校验商品资料导入规则 - err := checkCommodityExcel(sheetCols) - if err != nil { + case 2: + if sheetList[0] != "导商品" { + return nil, nil, errors.New("格式错误,不是商品模版excel") + } + if err := checkCommodityExcel(sheetCols); err != nil { return nil, nil, err } cols = getJSONTagNames(CommodityExcel{}) - } else { - cols = make([]string, len(sheetCols)) - for i := 0; i < len(sheetCols); i++ { - cols[i] = fmt.Sprintf("c%02d", i) - } - } - } else { - fmt.Println("cols", len(cols)) - fmt.Println("sheetCols", len(sheetCols)) - if len(cols) != len(sheetCols) { - logger.Error("cols length not equal columns") - return nil, nil, errors.New("cols length not equal columns") + default: + return nil, nil, errors.New("格式错误,不是商品分类或资料模版excel") } + } else if len(cols) != len(sheetCols) { + return nil, nil, errors.New("cols length does not match the number of columns") } for rows.Next() { columns, err := rows.Columns() if err != nil { - logger.Error("rows columns err:", err) - return nil, nil, err + return nil, nil, fmt.Errorf("rows columns err: %v", err) } - columnMap := make(map[string]interface{}, 0) - for i, _ := range cols { - columnMap[cols[i]] = "" - for j, _ := range columns { - columnMap[cols[j]] = columns[j] + columnMap := make(map[string]interface{}, len(cols)) + for i, col := range cols { + if i < len(columns) { + columnMap[col] = columns[i] + } else { + columnMap[col] = "" } } - //for i, _ := range columns { - // columnMap[cols[i]] = columns[i] - //} - fmt.Println("columnMap:", columnMap) + logger.Info("columnMap:", columnMap) colsMap = append(colsMap, columnMap) } - fmt.Println("colsMap:", colsMap) + logger.Info("colsMap:", colsMap) mCols, err := json.Marshal(colsMap) if err != nil { - logger.Error("marshal err:", err) - return mCols, nil, err + return mCols, nil, fmt.Errorf("marshal err: %v", err) } return mCols, colsMap, nil @@ -240,9 +229,30 @@ func checkCategoryExcel(sheetCols [][]string) error { } } + if duplicateName, nFlag := hasDuplicateNames(sheetCols); nFlag { + return fmt.Errorf("分类名称不允许重复,请检查:[%v]", duplicateName) + } + return nil } +// 校验名称是否相同,有则false +func hasDuplicateNames(sheetCols [][]string) (string, bool) { + nameMap := make(map[string]struct{}) + + for _, col := range sheetCols { + for _, name := range col { + if _, exists := nameMap[name]; exists && name != "" { + // 有重复的名称 + return name, true + } + nameMap[name] = struct{}{} + } + } + // 没有重复的名称 + return "", false +} + // 校验商品资料导入规则 // 导入商品资料校验报错:必填项缺少数据(除了产地、备注,其他都是必填项) func checkCommodityExcel(sheetCols [][]string) error { @@ -262,3 +272,335 @@ func checkCommodityExcel(sheetCols [][]string) error { } return nil } + +// 将读取的excel数据转换成CategoryExcel struct +func transCategoryData(colsMap []map[string]interface{}) []CategoryExcel { + var categories []CategoryExcel + + // 遍历 colsMap 进行类型断言和转换 + for _, col := range colsMap { + var category CategoryExcel + + for key, value := range col { + switch key { + case "first_category": + if name, ok := value.(string); ok { + category.FirstCategory = name + } + case "second_category": + if name, ok := value.(string); ok { + category.SecondCategory = name + } + case "three_category": + if name, ok := value.(string); ok { + category.ThreeCategory = name + } + } + } + + // 将处理后的数据追加到 categories 中 + categories = append(categories, category) + } + + return categories +} + +// 导入商品分类到数据库 +// 规则:分类只有3级,所有分类不允许名称完全相同 +func ImportCategoryData(colsMap []map[string]interface{}, businessId uint32) error { + data := transCategoryData(colsMap) + + if duplicateName, nFlag := hasDuplicateInDb(data); nFlag { + return fmt.Errorf("数据库已有此分类名称,不允许重复,请检查:[%v]", duplicateName) + } + + for _, item := range data { + var firstCategory, secondCategory, threeCategory Category + if item.FirstCategory == "" { // 一级分类名称为空则跳过,继续遍历 + continue + } + + // 插入或获取一级分类 + err := orm.Eloquent.Debug().FirstOrCreate(&firstCategory, + Category{ + Name: item.FirstCategory, + Pid: 0, + Display: 1, + CooperativeBusinessId: businessId, + }).Error + if err != nil { + return err + } + + // 插入或获取二级分类 + if item.SecondCategory != "" { + err = orm.Eloquent.Debug().FirstOrCreate(&secondCategory, + Category{ + Name: item.SecondCategory, + Pid: firstCategory.ID, + Display: 1, + CooperativeBusinessId: businessId, + }).Error + if err != nil { + return err + } + + } + + // 插入三级分类 + if item.ThreeCategory != "" { + err = orm.Eloquent.Debug().FirstOrCreate(&threeCategory, + Category{ + Name: item.ThreeCategory, + Pid: secondCategory.ID, + Display: 1, + CooperativeBusinessId: businessId, + }).Error + if err != nil { + return err + } + } + } + + return nil +} + +// 判断是否存在重复数据 +func hasDuplicateInDb(data []CategoryExcel) (string, bool) { + for _, item := range data { + if exists := isCategoryExists(item.FirstCategory); exists { + return item.FirstCategory, true + } + + if exists := isCategoryExists(item.SecondCategory); exists { + return item.SecondCategory, true + } + + if exists := isCategoryExists(item.ThreeCategory); exists { + return item.ThreeCategory, true + } + } + + return "", false +} + +// 判断分类是否存在 +func isCategoryExists(categoryName string) bool { + var count int64 + orm.Eloquent.Debug().Model(&Category{}). + Where("name = ?", categoryName). + Count(&count) + + return count > 0 +} + +// 导入商品资料 +func ImportCommodityData(colsMap []map[string]interface{}, businessId uint32) error { + data, err := transCommodityData(colsMap) + if err != nil { + return err + } + + var erpCommodities []ErpCommodity + erpCommodities, err = convertToErpCommodities(data) + if err != nil { + return err + } + + err = updateOrInsertCommodities(erpCommodities) + if err != nil { + return err + } + + return nil +} + +// 将读取的excel数据转换成CommodityExcel struct +func transCommodityData(colsMap []map[string]interface{}) ([]CommodityExcel, error) { + var commodities []CommodityExcel + + // 遍历 colsMap 进行类型断言和转换 + for _, col := range colsMap { + var commodity CommodityExcel + + // 将 col 转换为 JSON 字符串 + jsonData, err := json.Marshal(col) + if err != nil { + return nil, fmt.Errorf("failed to marshal data to JSON: %v", err) + } + + // 将 JSON 字符串反序列化为 CommodityExcel + if err := json.Unmarshal(jsonData, &commodity); err != nil { + return nil, fmt.Errorf("failed to unmarshal JSON to CommodityExcel: %v", err) + } + + // 将处理后的数据追加到 commodities 中 + commodities = append(commodities, commodity) + } + + return commodities, nil +} + +func convertToErpCommodities(data []CommodityExcel) ([]ErpCommodity, error) { + var erpCommodities []ErpCommodity + + productCounter := tools.NewProductCounter() + for _, item := range data { + category, err := getCategoryByName(item.Category) + if err != nil { + return nil, err + } + + list, err := GetSupplier(GetSupplierRequest{Name: item.SupplierName}) + if len(list) == 0 || errors.Is(err, gorm.ErrRecordNotFound) { + return nil, fmt.Errorf("有供应商未导入,请检查:[%v]", item.SupplierName) + } + + serialNumber := fmt.Sprintf("%s%04d", category.Number, + getNumberOnCategory(category.ID)+int64(productCounter.GetNextProductNumber(category.Number))) + fmt.Println("商品编号:", serialNumber) + + erpCommodity, err := convertToErpCommodity(item, category, list[0], serialNumber) + if err != nil { + return nil, err + } + + erpCommodities = append(erpCommodities, erpCommodity) + } + + return erpCommodities, nil +} + +// 查询商品分类 +func getCategoryByName(name string) (*Category, error) { + var category Category + err := orm.Eloquent.Debug().Model(&Category{}). + Where("name = ?", name).First(&category).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, fmt.Errorf("有商品分类未导入,请检查:[%v]", name) + } + return &category, err +} + +// 转换格式,匹配Commodity的model +func convertToErpCommodity(item CommodityExcel, category *Category, supplier *Supplier, serialNumber string) (ErpCommodity, error) { + brokerage1Float, err := strconv.ParseFloat(strings.TrimRight(item.SellBrokerage, "%"), 64) // 销售毛利 + if err != nil { + return ErpCommodity{}, fmt.Errorf("销售毛利转换有误:[%v]", err) + } + brokerage2Float, err := strconv.ParseFloat(strings.TrimRight(item.StaffBrokerage, "%"), 64) // 员工毛利提成 + if err != nil { + return ErpCommodity{}, fmt.Errorf("员工毛利提成转换有误:[%v]", err) + } + memberDiscountFloat, err := strconv.ParseFloat(item.MemberDiscount, 64) // 会员优惠 + if err != nil { + return ErpCommodity{}, fmt.Errorf("会员优惠转换有误:[%v]", err) + } + nRetailPrice, err := strconv.ParseUint(item.RetailPrice, 10, 32) // 指导零售价 + if err != nil { + return ErpCommodity{}, fmt.Errorf("指导零售价转换有误:[%v]", err) + } + nMinRetailPrice, err := strconv.ParseUint(item.MinRetailPrice, 10, 32) // 最低零售价 + if err != nil { + return ErpCommodity{}, fmt.Errorf("最低零售价转换有误:[%v]", err) + } + nStaffCostPrice, err := strconv.ParseUint(item.StaffCostPrice, 10, 32) // 员工成本价加价 + if err != nil { + return ErpCommodity{}, fmt.Errorf("员工成本价加价转换有误:[%v]", err) + } + nWholesalePrice, err := strconv.ParseUint(item.WholesalePrice, 10, 32) // 指导采购价 + if err != nil { + return ErpCommodity{}, fmt.Errorf("指导采购价转换有误:[%v]", err) + } + + //将是否串码转换为数字 1-无串码 2-串码(系统生成) 3-串码(手动添加) + var nIMEIType uint32 + switch item.IMEIType { + case "串码类": + if item.SysGenerate == "是" { + nIMEIType = 2 + } else if item.SysGenerate == "否" { + nIMEIType = 3 + } else { + return ErpCommodity{}, errors.New("[系统生成串码]列有非法字段") + } + case "非串码": + nIMEIType = 1 + default: + return ErpCommodity{}, errors.New("[是否串码]列有非法字段") + } + + //serialNumber := fmt.Sprintf("%s%04d", category.Number, getNumberOnCategory(category.ID)+1) + //fmt.Println("商品编号:", serialNumber) + + return ErpCommodity{ + SerialNumber: serialNumber, + Name: item.Name, + ErpCategoryId: category.ID, + ErpCategoryName: item.Category, + IMEIType: nIMEIType, + ErpSupplierId: supplier.ID, + ErpSupplierName: item.SupplierName, + RetailPrice: uint32(nRetailPrice), + MinRetailPrice: uint32(nMinRetailPrice), + StaffCostPrice: uint32(nStaffCostPrice), + WholesalePrice: uint32(nWholesalePrice), + Brokerage1: brokerage1Float, + Brokerage2: brokerage2Float, + MemberDiscount: memberDiscountFloat, + Origin: item.Origin, + Remark: item.Remark, + }, nil +} + +// 操作数据库,通过商品名称查找,没有则插入,有则更新 +func updateOrInsertCommodities(erpCommodities []ErpCommodity) error { + for _, erpCommodity := range erpCommodities { + var existingCommodity ErpCommodity + result := orm.Eloquent.Where("name = ?", erpCommodity.Name).First(&existingCommodity) + + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + orm.Eloquent.Create(&erpCommodity) + fmt.Println("Inserted:", erpCommodity.Name) + } else { + fmt.Println("Error:", result.Error) + return result.Error + } + } else { + orm.Eloquent.Model(&existingCommodity).Updates(&erpCommodity) + fmt.Println("Updated:", erpCommodity.Name) + } + } + + return nil +} + +// 查询商品列表中同一类商品分类下商品的个数 +func getNumberOnCategory(categoryId uint32) int64 { + var count int64 + orm.Eloquent.Debug().Model(&ErpCommodity{}). + Where("erp_category_id = ?", categoryId). + Count(&count) + + return count +} + +// 生成商品编号 +func GenerateSerialNumber(categoryId uint32) (string, error) { + var category Category + err := orm.Eloquent.Debug().Model(&Category{}). + Where("id = ?", categoryId).First(&category).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + return "", errors.New("未查到商品分类") + } + + var count int64 + orm.Eloquent.Debug().Model(&ErpCommodity{}). + Where("erp_category_id = ?", category.ID). + Count(&count) + + serialNumber := fmt.Sprintf("%s%04d", category.Number, count+1) + fmt.Println("商品编号:", serialNumber) + return serialNumber, nil +} diff --git a/app/admin/models/tools/productCounter.go b/app/admin/models/tools/productCounter.go new file mode 100644 index 0000000..04c7554 --- /dev/null +++ b/app/admin/models/tools/productCounter.go @@ -0,0 +1,34 @@ +package tools + +import ( + "sync" +) + +type ProductCounter struct { + mu sync.Mutex + counters map[string]int +} + +func NewProductCounter() *ProductCounter { + return &ProductCounter{ + counters: make(map[string]int), + } +} + +func (pc *ProductCounter) GetNextProductNumber(categoryID string) int { + pc.mu.Lock() + defer pc.mu.Unlock() + + // 如果之前没有这个分类的计数器,初始化为1 + if _, ok := pc.counters[categoryID]; !ok { + pc.counters[categoryID] = 1 + } + + // 生成商品编号 + productNumber := pc.counters[categoryID] + + // 增加计数器 + pc.counters[categoryID]++ + + return productNumber +} diff --git a/app/admin/router/commodity.go b/app/admin/router/commodity.go index f0435e3..736d41c 100644 --- a/app/admin/router/commodity.go +++ b/app/admin/router/commodity.go @@ -15,4 +15,5 @@ func registerCommodityRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMidd r.POST("list", basic.CommodityList) r.POST("detail", basic.CommodityDetail) r.POST("import_commodity_view", basic.CommodityImportView) + r.POST("import_commodity", basic.CommodityImport) } diff --git a/docs/docs.go b/docs/docs.go index ed587e2..a90ddd8 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -112,6 +112,75 @@ const docTemplate = `{ } } }, + "/api/v1/category/import_category": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "商品分类" + ], + "summary": "导入商品分类", + "parameters": [ + { + "description": "上传excel文件", + "name": "file", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/app.Response" + } + } + } + } + }, + "/api/v1/category/import_category_view": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "商品分类" + ], + "summary": "导入商品分类预览", + "parameters": [ + { + "description": "上传excel文件", + "name": "file", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.CategoryExcel" + } + } + } + } + } + }, "/api/v1/category/list": { "post": { "produces": [ @@ -310,7 +379,7 @@ const docTemplate = `{ } } }, - "/api/v1/commodity/import_category_view": { + "/api/v1/commodity/import_commodity": { "post": { "consumes": [ "application/json" @@ -319,9 +388,9 @@ const docTemplate = `{ "application/json" ], "tags": [ - "商品分类" + "商品资料" ], - "summary": "导入商品分类预览", + "summary": "导入商品资料", "parameters": [ { "description": "上传excel文件", @@ -337,10 +406,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.CategoryExcel" - } + "$ref": "#/definitions/app.Response" } } } @@ -3187,7 +3253,6 @@ const docTemplate = `{ "basic.CommodityEditRequest": { "type": "object", "required": [ - "brokerage_1", "erp_category_id", "erp_supplier_id", "id", diff --git a/docs/swagger.json b/docs/swagger.json index 43002be..a857c8b 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -104,6 +104,75 @@ } } }, + "/api/v1/category/import_category": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "商品分类" + ], + "summary": "导入商品分类", + "parameters": [ + { + "description": "上传excel文件", + "name": "file", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/app.Response" + } + } + } + } + }, + "/api/v1/category/import_category_view": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "商品分类" + ], + "summary": "导入商品分类预览", + "parameters": [ + { + "description": "上传excel文件", + "name": "file", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.CategoryExcel" + } + } + } + } + } + }, "/api/v1/category/list": { "post": { "produces": [ @@ -302,7 +371,7 @@ } } }, - "/api/v1/commodity/import_category_view": { + "/api/v1/commodity/import_commodity": { "post": { "consumes": [ "application/json" @@ -311,9 +380,9 @@ "application/json" ], "tags": [ - "商品分类" + "商品资料" ], - "summary": "导入商品分类预览", + "summary": "导入商品资料", "parameters": [ { "description": "上传excel文件", @@ -329,10 +398,7 @@ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.CategoryExcel" - } + "$ref": "#/definitions/app.Response" } } } @@ -3179,7 +3245,6 @@ "basic.CommodityEditRequest": { "type": "object", "required": [ - "brokerage_1", "erp_category_id", "erp_supplier_id", "id", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 2d19cb6..7ff2f37 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -152,7 +152,6 @@ definitions: description: 指导采购价 type: integer required: - - brokerage_1 - erp_category_id - erp_supplier_id - id @@ -1526,6 +1525,50 @@ paths: summary: 隐藏或展示分类 tags: - 商品分类 + /api/v1/category/import_category: + post: + consumes: + - application/json + parameters: + - description: 上传excel文件 + in: body + name: file + required: true + schema: + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/app.Response' + summary: 导入商品分类 + tags: + - 商品分类 + /api/v1/category/import_category_view: + post: + consumes: + - application/json + parameters: + - description: 上传excel文件 + in: body + name: file + required: true + schema: + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.CategoryExcel' + type: array + summary: 导入商品分类预览 + tags: + - 商品分类 /api/v1/category/list: post: parameters: @@ -1652,7 +1695,7 @@ paths: summary: 编辑商品 tags: - 商品资料 - /api/v1/commodity/import_category_view: + /api/v1/commodity/import_commodity: post: consumes: - application/json @@ -1669,12 +1712,10 @@ paths: "200": description: OK schema: - items: - $ref: '#/definitions/models.CategoryExcel' - type: array - summary: 导入商品分类预览 + $ref: '#/definitions/app.Response' + summary: 导入商品资料 tags: - - 商品分类 + - 商品资料 /api/v1/commodity/import_commodity_view: post: consumes: