From 985cef1822077eac4462acf191ddb089705ca9e9 Mon Sep 17 00:00:00 2001 From: xiaodongzhu825 <97694732@qq.com> Date: Thu, 18 Jun 2026 14:10:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E4=BA=86=E8=BF=87=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81=20=E4=BF=AE=E6=AD=A3=E4=BA=86?= =?UTF-8?q?=E7=BB=99=E5=A4=96=E9=83=A8=E4=BB=BB=E5=8A=A1=E6=B1=A0=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E7=9A=84=E5=9B=BE=E7=89=87=E6=A0=BC=E5=BC=8F=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controllers/process.go | 508 +------------------------------------- models/request/process.go | 14 +- service/process.go | 14 +- 3 files changed, 24 insertions(+), 512 deletions(-) diff --git a/controllers/process.go b/controllers/process.go index 8ba14e5..1c00f2f 100644 --- a/controllers/process.go +++ b/controllers/process.go @@ -4,15 +4,11 @@ import ( "bytes" "errors" "fmt" - "gorm.io/gorm" + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" "io" "mime/multipart" "net/http" - "strings" - "time" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" "psi/constant" "psi/database" "psi/models" @@ -21,6 +17,7 @@ import ( "psi/service" "psi/utils" "strconv" + "strings" ) type ProcessApi struct{} @@ -174,247 +171,11 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) { return } - // TODO: 添加入库单信息同步到主库的逻辑 // 同步入库单信息到主库 product_book_xx 分表 r.syncProductBookToMainDB(req, userInfo, c) - //itemProductIDs := make([]int64, len(req.Items)) - //for i, item := range req.Items { - // itemProductIDs[i] = item.ProductID - //} - //fmt.Printf("[DEBUG] itemProductIDs: %v\n", itemProductIDs) - // - //fmt.Printf("[DEBUG] 获取租户数据库, about_id: %d\n", userInfo.AboutID) - //tenantDB, err := database.GetTenantDB(userInfo.AboutID) - //if err != nil { - // fmt.Printf("[DEBUG] 获取租户数据库失败: %v\n", err) - // utils.FailWithRequestLog(constant.LoggerChannelWork, "获取租户数据库连接失败", err, c, gin.H{"about_id": userInfo.AboutID}) - // return - //} - //fmt.Println("[DEBUG] 租户数据库连接成功") - // - //fmt.Printf("[DEBUG] 查询入库单(租户库), receiving_order_id: %d\n", req.ReceivingOrderID) - //var receivingOrder models.ReceivingOrder - //if err := tenantDB.Where("id = ? AND is_del = 0", req.ReceivingOrderID).First(&receivingOrder).Error; err != nil { - // fmt.Printf("[DEBUG] 查询入库单失败: %v\n", err) - // utils.FailWithRequestLog(constant.LoggerChannelWork, "查询入库单失败", err, c, gin.H{"receiving_order_id": req.ReceivingOrderID}) - // return - //} - //fmt.Printf("[DEBUG] 入库单查询成功, warehouse_id: %d\n", receivingOrder.WarehouseID) - // - //fmt.Printf("[DEBUG] 查询仓库(租户库), warehouse_id: %d\n", receivingOrder.WarehouseID) - //var warehouse models.Warehouse - //if err := tenantDB.Where("id = ? AND is_del = 0", receivingOrder.WarehouseID).First(&warehouse).Error; err != nil { - // fmt.Printf("[DEBUG] 查询仓库失败: %v\n", err) - // utils.FailWithRequestLog(constant.LoggerChannelWork, "查询仓库失败", err, c, gin.H{"warehouse_id": receivingOrder.WarehouseID}) - // return - //} - //fmt.Printf("[DEBUG] 仓库查询成功, warehouse_name: %s\n", warehouse.Name) - // - //fmt.Printf("[DEBUG] 获取租户数据库, about_id: %d\n", userInfo.AboutID) - //tenantDB, err = database.GetTenantDB(userInfo.AboutID) - //if err != nil { - // fmt.Printf("[DEBUG] 获取租户数据库失败: %v\n", err) - // utils.FailWithRequestLog(constant.LoggerChannelWork, "获取租户数据库连接失败", err, c, gin.H{"about_id": userInfo.AboutID}) - // return - //} - //fmt.Println("[DEBUG] 租户数据库连接成功") - // - //var products []models.Product - //fmt.Printf("[DEBUG] 查询商品列表, product_ids: %v\n", itemProductIDs) - //if err := tenantDB.Where("id IN ? AND is_del = 0", itemProductIDs).Find(&products).Error; err != nil { - // fmt.Printf("[DEBUG] 查询商品列表失败: %v\n", err) - // utils.FailWithRequestLog(constant.LoggerChannelWork, "查询商品列表失败", err, c, gin.H{"product_ids": itemProductIDs}) - // return - //} - //fmt.Printf("[DEBUG] 商品查询成功, 共 %d 条\n", len(products)) - // - //type locationInfo struct { - // LocationID int64 - // Code string - //} - //locationMap := make(map[int64]locationInfo) - //fmt.Println("[DEBUG] 开始查询库位信息") - //for _, product := range products { - // var inventoryDetail models.InventoryDetail - // if err := tenantDB.Where("product_id = ? AND warehouse_id = ? AND is_del = 0", product.ID, receivingOrder.WarehouseID).First(&inventoryDetail).Error; err == nil { - // var location models.Location - // if err := tenantDB.Where("id = ? AND is_del = 0", inventoryDetail.LocationID).First(&location).Error; err == nil { - // locationMap[product.ID] = locationInfo{ - // LocationID: location.ID, - // Code: location.Code, - // } - // } - // } - //} - //fmt.Printf("[DEBUG] 库位查询完成, locationMap: %v\n", locationMap) - // - //bookInfoMap := make(map[int64]models.BookInfo) - //fmt.Println("[DEBUG] 开始查询BookInfo") - //for _, product := range products { - // if product.StandardProductID > 0 { - // if _, exists := bookInfoMap[product.StandardProductID]; !exists { - // var bookInfo models.BookInfo - // if err := database.DB.Where("id = ?", product.StandardProductID).First(&bookInfo).Error; err == nil { - // bookInfoMap[product.StandardProductID] = bookInfo - // } - // } - // } - //} - //fmt.Printf("[DEBUG] BookInfo查询完成, bookInfoMap数量: %d\n", len(bookInfoMap)) - // - //fmt.Println("[DEBUG] 开始写入product_book分表") - //for _, product := range products { - // isbn := product.Barcode - // if isbn == "" { - // fmt.Printf("[DEBUG] 跳过无条码商品, product_id: %d\n", product.ID) - // continue - // } - // - // tableName := models.ProductBookTableName(isbn) - // fmt.Printf("[DEBUG] 处理商品, product_id: %d, isbn: %s, table: %s\n", product.ID, isbn, tableName) - // - // var locInfo locationInfo - // if li, exists := locationMap[product.ID]; exists { - // locInfo = li - // } - // - // var bookInfo models.BookInfo - // if bi, exists := bookInfoMap[product.StandardProductID]; exists { - // bookInfo = bi - // } - // - // catID := bookInfo.CatID - // if catID == nil { - // catID = datatypes.JSON("[]") - // } - // liveImage := product.LiveImage - // if liveImage == nil { - // liveImage = datatypes.JSON("{}") - // } - // - // now := time.Now().Unix() - // - // fmt.Printf("[DEBUG] 查重, self_id: %d, about_id: %d\n", product.ID, userInfo.AboutID) - // var existingBook models.ProductBook - // err := database.DB.Table(tableName).Where("self_id = ? AND about_id = ? AND is_del = 0", product.ID, userInfo.AboutID).First(&existingBook).Error - // - // if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { - // fmt.Println("[DEBUG] 记录不存在,执行新增") - // bookRecord := models.ProductBook{ - // SelfID: product.ID, - // AboutId: userInfo.AboutID, - // WarehouseID: warehouse.ID, - // WarehouseName: warehouse.Name, - // LocationID: locInfo.LocationID, - // LocationName: locInfo.Code, - // CategoryID: product.CategoryID, - // StandardProductID: product.StandardProductID, - // Fid: bookInfo.Fid, - // Type: bookInfo.Type, - // ISBN: isbn, - // FISBN: bookInfo.FISBN, - // BookName: bookInfo.BookName, - // FBookName: bookInfo.FBookName, - // Author: bookInfo.Author, - // Publishing: bookInfo.Publishing, - // PublicationTime: bookInfo.PublicationTime, - // Binding: bookInfo.Binding, - // PagesCount: bookInfo.PagesCount, - // WordsCount: bookInfo.WordsCount, - // Format: bookInfo.Format, - // CatID: catID, - // Name: product.Name, - // Appearance: product.Appearance, - // Barcode: product.Barcode, - // Price: product.Price, - // SalePrice: product.SalePrice, - // Cost: product.Cost, - // LiveImage: liveImage, - // IsBatchManaged: product.IsBatchManaged, - // IsShelfLifeManaged: product.IsShelfLifeManaged, - // Status: product.Status, - // CreatedAt: now, - // UpdatedAt: now, - // IsDel: 0, - // } - // if createErr := database.DB.Table(tableName).Create(&bookRecord).Error; createErr != nil { - // fmt.Printf("[DEBUG] 新增失败: %v\n", createErr) - // stmt := database.DB.Session(&gorm.Session{DryRun: true}).Table(tableName).Create(&bookRecord) - // utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - // "source": "写入product_book分表失败", - // "user_id": userInfo.AboutID, - // "self_id": product.ID, - // "isbn": isbn, - // "table_name": tableName, - // "warehouse_id": warehouse.ID, - // "sql": stmt.Statement.SQL.String(), - // "vars": fmt.Sprintf("%v", stmt.Statement.Vars), - // "err_msg": createErr.Error(), - // }) - // utils.FailWithRequestLog(constant.LoggerChannelWork, "写入product_book分表失败", createErr, c, gin.H{ - // "product_id": product.ID, - // "isbn": isbn, - // "table_name": tableName, - // }) - // return - // } - // fmt.Println("[DEBUG] 新增成功") - // } else if err == nil { - // fmt.Println("[DEBUG] 记录已存在,执行更新") - // updateData := map[string]interface{}{ - // "warehouse_id": warehouse.ID, - // "warehouse_name": warehouse.Name, - // "location_id": locInfo.LocationID, - // "location_name": locInfo.Code, - // "category_id": product.CategoryID, - // "standard_product_id": product.StandardProductID, - // "name": product.Name, - // "book_name": bookInfo.BookName, - // "f_isbn": bookInfo.FISBN, - // "f_book_name": bookInfo.FBookName, - // "author": bookInfo.Author, - // "publishing": bookInfo.Publishing, - // "publication_time": bookInfo.PublicationTime, - // "binding": bookInfo.Binding, - // "pages_count": bookInfo.PagesCount, - // "words_count": bookInfo.WordsCount, - // "format": bookInfo.Format, - // "cat_id": catID, - // "appearance": product.Appearance, - // "barcode": product.Barcode, - // "price": product.Price, - // "sale_price": product.SalePrice, - // "cost": product.Cost, - // "live_image": liveImage, - // "is_batch_managed": product.IsBatchManaged, - // "is_shelf_life_managed": product.IsShelfLifeManaged, - // "status": product.Status, - // "updated_at": now, - // } - // if updateErr := database.DB.Table(tableName).Model(&existingBook).Updates(updateData).Error; updateErr != nil { - // fmt.Printf("[DEBUG] 更新失败: %v\n", updateErr) - // utils.FailWithRequestLog(constant.LoggerChannelWork, "更新product_book分表失败", updateErr, c, gin.H{ - // "product_id": product.ID, - // "isbn": isbn, - // "table_name": tableName, - // }) - // return - // } - // fmt.Println("[DEBUG] 更新成功") - // } else { - // fmt.Printf("[DEBUG] 查询分表异常: %v\n", err) - // utils.FailWithRequestLog(constant.LoggerChannelWork, "查询product_book分表失败", err, c, gin.H{ - // "product_id": product.ID, - // "isbn": isbn, - // "table_name": tableName, - // }) - // return - // } - //} - //fmt.Println("[DEBUG] product_book分表写入全部完成") - fmt.Printf("提交入库成功,入库单ID: %d, 波次任务ID: %d, 波次任务批次号: %s\n", req.ReceivingOrderID, req.WaveTaskID) + go func(receivingOrderID, aboutID, waveTaskID int64, itemProductIDs []int64) { databaseConn := database.DB @@ -438,214 +199,9 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) { return } - // 同步给主库对应的product_book_xx中 - // 获取租户数据库连接 - tenantDB, err := database.GetTenantDB(aboutID) - if err != nil { - utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "获取租户数据库连接失败", - "user_id": aboutID, - "err_msg": err.Error(), - }) - return - } - - // 查询商品详细信息 - var products []models.Product - if err := tenantDB.Where("id IN ? AND is_del = 0", itemProductIDs).Find(&products).Error; err != nil { - utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "查询商品列表失败", - "user_id": aboutID, - "product_ids": itemProductIDs, - "err_msg": err.Error(), - }) - return - } - - // 查询库位信息(获取库位ID和Code) - type locationInfo struct { - LocationID int64 - Code string - } - locationMap := make(map[int64]locationInfo) - for _, product := range products { - var inventoryDetail models.InventoryDetail - if err := tenantDB.Where("product_id = ? AND warehouse_id = ? AND is_del = 0", product.ID, receivingOrder.WarehouseID).First(&inventoryDetail).Error; err == nil { - var location models.Location - if err := tenantDB.Where("id = ? AND is_del = 0", inventoryDetail.LocationID).First(&location).Error; err == nil { - locationMap[product.ID] = locationInfo{ - LocationID: location.ID, - Code: location.Code, - } - } - } - } - - // 查询BookInfo(按StandardProductID关联) - bookInfoMap := make(map[int64]models.BookInfo) - for _, product := range products { - if product.StandardProductID > 0 { - if _, exists := bookInfoMap[product.StandardProductID]; !exists { - var bookInfo models.BookInfo - if err := database.DB.Where("id = ?", product.StandardProductID).First(&bookInfo).Error; err == nil { - bookInfoMap[product.StandardProductID] = bookInfo - } - } - } - } - - // 逐个写入主库 product_book_xx 分表 - for _, product := range products { - isbn := product.Barcode - if isbn == "" { - continue - } - - tableName := models.ProductBookTableName(isbn) - - var locInfo locationInfo - if li, exists := locationMap[product.ID]; exists { - locInfo = li - } - - var bookInfo models.BookInfo - if bi, exists := bookInfoMap[product.StandardProductID]; exists { - bookInfo = bi - } - - now := time.Now().Unix() - - // 按 self_id + about_id 查重,避免不同租户商品ID冲突 - var existingBook models.ProductBook - err := database.DB.Table(tableName).Where("self_id = ? AND about_id = ? AND is_del = 0", product.ID, aboutID).First(&existingBook).Error - - if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { - bookRecord := models.ProductBook{ - SelfID: product.ID, - AboutId: aboutID, - WarehouseID: warehouse.ID, - WarehouseName: warehouse.Name, - LocationID: locInfo.LocationID, - LocationName: locInfo.Code, - CategoryID: product.CategoryID, - StandardProductID: product.StandardProductID, - Fid: bookInfo.Fid, - Type: bookInfo.Type, - ISBN: isbn, - FISBN: bookInfo.FISBN, - BookName: bookInfo.BookName, - FBookName: bookInfo.FBookName, - Author: bookInfo.Author, - Publishing: bookInfo.Publishing, - PublicationTime: bookInfo.PublicationTime, - Binding: bookInfo.Binding, - PagesCount: bookInfo.PagesCount, - WordsCount: bookInfo.WordsCount, - Format: bookInfo.Format, - CatID: bookInfo.CatID, - Name: product.Name, - Appearance: product.Appearance, - Barcode: product.Barcode, - Price: product.Price, - SalePrice: product.SalePrice, - Cost: product.Cost, - LiveImage: product.LiveImage, - IsBatchManaged: product.IsBatchManaged, - IsShelfLifeManaged: product.IsShelfLifeManaged, - Status: product.Status, - CreatedAt: now, - UpdatedAt: now, - IsDel: 0, - } - if createErr := database.DB.Table(tableName).Create(&bookRecord).Error; createErr != nil { - utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "写入product_book分表失败", - "user_id": aboutID, - "self_id": product.ID, - "isbn": isbn, - "table_name": tableName, - "warehouse_id": warehouse.ID, - "err_msg": createErr.Error(), - }) - } else { - utils.InfoLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "写入product_book分表成功", - "user_id": aboutID, - "self_id": product.ID, - "isbn": isbn, - "table_name": tableName, - "warehouse_id": warehouse.ID, - "location_id": locInfo.LocationID, - }) - } - } else if err == nil { - updateData := map[string]interface{}{ - "warehouse_id": warehouse.ID, - "warehouse_name": warehouse.Name, - "location_id": locInfo.LocationID, - "location_name": locInfo.Code, - "category_id": product.CategoryID, - "standard_product_id": product.StandardProductID, - "name": product.Name, - "book_name": bookInfo.BookName, - "f_isbn": bookInfo.FISBN, - "f_book_name": bookInfo.FBookName, - "author": bookInfo.Author, - "publishing": bookInfo.Publishing, - "publication_time": bookInfo.PublicationTime, - "binding": bookInfo.Binding, - "pages_count": bookInfo.PagesCount, - "words_count": bookInfo.WordsCount, - "format": bookInfo.Format, - "cat_id": bookInfo.CatID, - "appearance": product.Appearance, - "barcode": product.Barcode, - "price": product.Price, - "sale_price": product.SalePrice, - "cost": product.Cost, - "live_image": product.LiveImage, - "is_batch_managed": product.IsBatchManaged, - "is_shelf_life_managed": product.IsShelfLifeManaged, - "status": product.Status, - "updated_at": now, - } - if updateErr := database.DB.Table(tableName).Model(&existingBook).Updates(updateData).Error; updateErr != nil { - utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "更新product_book分表失败", - "user_id": aboutID, - "self_id": product.ID, - "isbn": isbn, - "table_name": tableName, - "warehouse_id": warehouse.ID, - "err_msg": updateErr.Error(), - }) - } else { - utils.InfoLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "更新product_book分表成功", - "user_id": aboutID, - "self_id": product.ID, - "isbn": isbn, - "table_name": tableName, - "warehouse_id": warehouse.ID, - "location_id": locInfo.LocationID, - }) - } - } else { - utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "查询product_book分表失败", - "user_id": aboutID, - "self_id": product.ID, - "isbn": isbn, - "table_name": tableName, - "err_msg": err.Error(), - }) - } - } - warehouseId := warehouse.ID productIds := make([]string, len(itemProductIDs)) - for i, pid := range itemProductIDs { productIds[i] = fmt.Sprintf("%d", pid) } @@ -659,60 +215,6 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) { _ = writer.WriteField("userId", fmt.Sprintf("%d", aboutID)) _ = writer.WriteField("warehouseId", fmt.Sprintf("%d", warehouseId)) _ = writer.WriteField("productId", productIdsStr) - closeErr := writer.Close() - if closeErr != nil { - utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "关闭multipart writer失败", - "err_msg": closeErr.Error(), - }) - return - } - - client := &http.Client{} - httpReq, err := http.NewRequest(method, url, payload) - - if err != nil { - utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "创建HTTP请求失败", - "err_msg": err.Error(), - }) - return - } - httpReq.Header.Add("Authorization", "Basic ZWxhc3RpYzo1bVJESVVnNTJWQzBmcDE0bnctRg==") - httpReq.Header.Set("Content-Type", writer.FormDataContentType()) - - res, err := client.Do(httpReq) - if err != nil { - utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "调用外部API失败", - "err_msg": err.Error(), - }) - return - } - defer func(Body io.ReadCloser) { - closeBodyErr := Body.Close() - if closeBodyErr != nil { - utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "调用外部API失败-Body关闭失败", - "err_msg": closeBodyErr.Error(), - }) - } - }(res.Body) - - body, err := io.ReadAll(res.Body) - if err != nil { - utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ - "source": "读取响应失败", - "err_msg": err.Error(), - }) - return - } - - /*payload := &bytes.Buffer{} - writer := multipart.NewWriter(payload) - _ = writer.WriteField("userId", fmt.Sprintf("%d", aboutID)) - _ = writer.WriteField("warehouseId", fmt.Sprintf("%d", warehouseId)) - _ = writer.WriteField("productId", productIdsStr) err := writer.Close() if err != nil { utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ @@ -760,7 +262,7 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) { "err_msg": err.Error(), }) return - }*/ + } utils.InfoLog(constant.LoggerChannelWork, logrus.Fields{ "source": "外部API调用完成", diff --git a/models/request/process.go b/models/request/process.go index 2aa22eb..f87051f 100644 --- a/models/request/process.go +++ b/models/request/process.go @@ -18,13 +18,13 @@ type PurchaseOrderItemRequest struct { } type WaveRequest struct { - WaveID int64 `form:"wave_id" binding:"required"` - CarID int64 `form:"car_id"` - CarCode int64 `form:"car_code"` - RelatedOrderID int64 `form:"related_order_id" binding:"required"` - Assignee string `form:"assignee"` - AssigneeId int64 `form:"assignee_id"` - Items []WaveItemRequest `form:"items[]"` + WaveID int64 `form:"wave_id" binding:"required"` // 波次ID + CarID int64 `form:"car_id"` // 波次ID + CarCode int64 `form:"car_code"` // 波次编号 + RelatedOrderID int64 `form:"related_order_id" binding:"required"` // 关联的订单ID + Assignee string `form:"assignee"` // 分配人 + AssigneeId int64 `form:"assignee_id"` // 分配人ID + Items []WaveItemRequest `form:"items[]"` // 波次项 } type WaveItemRequest struct { diff --git a/service/process.go b/service/process.go index 74a8d11..57ea8f0 100644 --- a/service/process.go +++ b/service/process.go @@ -4453,13 +4453,23 @@ func parseImageList(liveImage datatypes.JSON) []string { // 尝试解析为字符串数组 var imgList []string if err := json.Unmarshal(liveImage, &imgList); err == nil { - return imgList + // 对每个元素做逗号拆分,兼容 ["url1,url2"] 的情况 + result := make([]string, 0, len(imgList)) + for _, item := range imgList { + parts := strings.Split(item, ",") + for _, part := range parts { + trimmed := strings.TrimSpace(part) + if trimmed != "" { + result = append(result, trimmed) + } + } + } + return result } // 如果解析失败,尝试解析为字符串,然后按逗号分割 var imgStr string if err := json.Unmarshal(liveImage, &imgStr); err == nil { - // 去除空格并按逗号分割 parts := strings.Split(imgStr, ",") result := make([]string, 0, len(parts)) for _, part := range parts {