@ -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调用完成" ,