This commit is contained in:
Administrator 2026-06-17 15:29:47 +08:00
parent 3b2048b449
commit 31f300e0b3
4 changed files with 302 additions and 1 deletions

View File

@ -195,8 +195,87 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) {
return return
} }
// 同步给主库对应的product_book_xx中
/*var warehouse models.Warehouse
if err := databaseConn.Where("id = ? AND is_del = 0", receivingOrder.WarehouseID).First(&warehouse).Error; err != nil {
utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{
"source": "查询仓库失败",
"warehouse_id": receivingOrder.WarehouseID,
"err_msg": err.Error(),
})
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
}
// 查询库位信息(用于获取库位名称)
locationMap := make(map[int64]string)
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] = location.Code
}
}
}
// 逐个同步商品到主库
for _, product := range products {
locationCode := ""
if code, exists := locationMap[product.ID]; exists {
locationCode = code
}
if syncErr := database.SyncProductToMainDB(aboutID, &product, warehouse.ID, warehouse.Name, 0, locationCode); syncErr != nil {
utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{
"source": "同步商品到主库失败",
"user_id": aboutID,
"product_id": product.ID,
"warehouse_id": warehouse.ID,
"location_code": locationCode,
"err_msg": syncErr.Error(),
})
} else {
utils.InfoLog(constant.LoggerChannelWork, logrus.Fields{
"source": "同步商品到主库成功",
"user_id": aboutID,
"product_id": product.ID,
"product_name": product.Name,
"barcode": product.Barcode,
"warehouse_id": warehouse.ID,
"location_code": locationCode,
})
}
}
warehouseId := warehouse.ID warehouseId := warehouse.ID
//warehouseId := warehouse.ID
productIds := make([]string, len(itemProductIDs)) productIds := make([]string, len(itemProductIDs))
for i, pid := range itemProductIDs { for i, pid := range itemProductIDs {
productIds[i] = fmt.Sprintf("%d", pid) productIds[i] = fmt.Sprintf("%d", pid)
@ -211,6 +290,60 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) {
_ = writer.WriteField("userId", fmt.Sprintf("%d", aboutID)) _ = writer.WriteField("userId", fmt.Sprintf("%d", aboutID))
_ = writer.WriteField("warehouseId", fmt.Sprintf("%d", warehouseId)) _ = writer.WriteField("warehouseId", fmt.Sprintf("%d", warehouseId))
_ = writer.WriteField("productId", productIdsStr) _ = 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() err := writer.Close()
if err != nil { if err != nil {
utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{ utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{
@ -258,7 +391,7 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) {
"err_msg": err.Error(), "err_msg": err.Error(),
}) })
return return
} }*/
utils.InfoLog(constant.LoggerChannelWork, logrus.Fields{ utils.InfoLog(constant.LoggerChannelWork, logrus.Fields{
"source": "外部API调用完成", "source": "外部API调用完成",

View File

@ -0,0 +1,3 @@
package controllers
type ProductBookApi struct{}

157
database/product_sync.go Normal file
View File

@ -0,0 +1,157 @@
package database
import (
"fmt"
"psi/models"
"gorm.io/gorm"
)
// SyncProductToMainDB 将租户库的商品信息同步到主库的 product 表和 product_book 表
// aboutID: 租户ID
// product: 商品对象
// warehouseID: 仓库ID
// warehouseName: 仓库名称
// locationID: 库位ID
// locationName: 库位名称
func SyncProductToMainDB(aboutID int64, product *models.Product, warehouseID int64, warehouseName string, locationID int64, locationName string) error {
if aboutID == 0 {
return nil
}
// 1. 同步到 product 表
if err := syncToProductTable(aboutID, product, warehouseID, warehouseName, locationID, locationName); err != nil {
return fmt.Errorf("同步到product表失败: %v", err)
}
// 2. 同步到 product_book 表(如果有条码/ISBN
if product.Barcode != "" {
if err := syncToProductBookTable(aboutID, product, warehouseID, warehouseName, locationID, locationName); err != nil {
return fmt.Errorf("同步到product_book表失败: %v", err)
}
}
return nil
}
// syncToProductTable 同步到主库 product 表
func syncToProductTable(aboutID int64, product *models.Product, warehouseID int64, warehouseName string, locationID int64, locationName string) error {
var existingProduct models.Product
err := DB.Where("barcode = ? AND about_id = ? AND is_del = ?", product.Barcode, aboutID, 0).First(&existingProduct).Error
if err != nil && err == gorm.ErrRecordNotFound {
mainProduct := models.Product{
AboutId: aboutID,
WarehouseID: warehouseID,
WarehouseName: warehouseName,
LocationID: locationID,
LocationName: locationName,
CategoryID: product.CategoryID,
Name: product.Name,
Appearance: product.Appearance,
Barcode: product.Barcode,
Price: product.Price,
SalePrice: product.SalePrice,
Cost: product.Cost,
LiveImage: product.LiveImage,
Status: product.Status,
CreatedAt: product.CreatedAt,
UpdatedAt: product.UpdatedAt,
IsDel: 0,
}
if createErr := DB.Create(&mainProduct).Error; createErr != nil {
return fmt.Errorf("创建主库商品失败: %v", createErr)
}
} else if err == nil {
updateData := map[string]interface{}{
"warehouse_id": warehouseID,
"warehouse_name": warehouseName,
"location_id": locationID,
"location_name": locationName,
"name": product.Name,
"appearance": product.Appearance,
"price": product.Price,
"sale_price": product.SalePrice,
"cost": product.Cost,
"live_image": product.LiveImage,
"status": product.Status,
"updated_at": product.UpdatedAt,
}
if updateErr := DB.Model(&existingProduct).Updates(updateData).Error; updateErr != nil {
return fmt.Errorf("更新主库商品失败: %v", updateErr)
}
} else {
return fmt.Errorf("查询主库商品失败: %v", err)
}
return nil
}
// syncToProductBookTable 同步到主库 product_book 分表
func syncToProductBookTable(aboutID int64, product *models.Product, warehouseID int64, warehouseName string, locationID int64, locationName string) error {
isbn := product.Barcode
tableName := models.ProductBookTableName(isbn)
var existingBook models.ProductBook
err := DB.Table(tableName).Where("isbn = ? AND about_id = ? AND is_del = ?", isbn, aboutID, 0).First(&existingBook).Error
if err != nil && err == gorm.ErrRecordNotFound {
bookRecord := models.ProductBook{
ID: product.ID,
AboutId: aboutID,
WarehouseID: warehouseID,
WarehouseName: warehouseName,
LocationID: locationID,
LocationName: locationName,
CategoryID: product.CategoryID,
StandardProductID: product.StandardProductID,
ISBN: isbn,
Barcode: product.Barcode,
Name: product.Name,
BookName: product.Name,
Appearance: product.Appearance,
Price: product.Price,
SalePrice: product.SalePrice,
Cost: product.Cost,
LiveImage: product.LiveImage,
Status: product.Status,
CreatedAt: product.CreatedAt,
UpdatedAt: product.UpdatedAt,
IsDel: 0,
}
if createErr := DB.Table(tableName).Create(&bookRecord).Error; createErr != nil {
return fmt.Errorf("创建product_book记录失败: %v", createErr)
}
} else if err == nil {
updateData := map[string]interface{}{
"id": product.ID,
"warehouse_id": warehouseID,
"warehouse_name": warehouseName,
"location_id": locationID,
"location_name": locationName,
"category_id": product.CategoryID,
"standard_product_id": product.StandardProductID,
"name": product.Name,
"book_name": product.Name,
"appearance": product.Appearance,
"barcode": product.Barcode,
"price": product.Price,
"sale_price": product.SalePrice,
"cost": product.Cost,
"live_image": product.LiveImage,
"status": product.Status,
"updated_at": product.UpdatedAt,
}
if updateErr := DB.Table(tableName).Model(&existingBook).Updates(updateData).Error; updateErr != nil {
return fmt.Errorf("更新product_book记录失败: %v", updateErr)
}
} else {
return fmt.Errorf("查询product_book记录失败: %v", err)
}
return nil
}

View File

@ -16,6 +16,7 @@ var warehouseApi = &controllers.WarehouseApi{}
var ocrApi = &controllers.OcrApi{} var ocrApi = &controllers.OcrApi{}
var supplierApi = &controllers.SupplierApi{} var supplierApi = &controllers.SupplierApi{}
var productApi = &controllers.ProductApi{} var productApi = &controllers.ProductApi{}
var productBookApi = &controllers.ProductBookApi{}
var processApi = &controllers.ProcessApi{} var processApi = &controllers.ProcessApi{}
var barcodeApi = &controllers.BarcodeApi{} var barcodeApi = &controllers.BarcodeApi{}
var purchaseApi = &controllers.PurchaseApi{} var purchaseApi = &controllers.PurchaseApi{}
@ -79,6 +80,13 @@ func initRouter() (r *gin.Engine) {
public.GET("/product/distribution_list", productApi.GetDistributionProductList) // 获取分销商品列表 public.GET("/product/distribution_list", productApi.GetDistributionProductList) // 获取分销商品列表
public.POST("/product/batchPush", productApi.BatchPushProducts) // 批量推送商品 public.POST("/product/batchPush", productApi.BatchPushProducts) // 批量推送商品
public.POST("/product/pushToShop", productApi.PushProductToShop) // 推送商品到店铺 public.POST("/product/pushToShop", productApi.PushProductToShop) // 推送商品到店铺
// 商品反射
public.GET("/product_book/list", productBookApi.List) // 获取商品反射列表
public.GET("/product_book/list", productBookApi.Detail) // 获取商品反射详情
public.POST("/product_book/create", productBookApi.Create) // 创建商品反射
public.POST("/product_book/update", productBookApi.Update) // 更新商品反射
public.GET("/product_book/del", productBookApi.Del) // 删除商品反射
} }
sign := api.Group("") sign := api.Group("")