修复了查询库存接口未计算锁定库存问题
修复了同步反射商品表未同步到的问题
This commit is contained in:
parent
31f300e0b3
commit
d0e9a0fa82
@ -4,10 +4,12 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"gorm.io/gorm"
|
||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -196,16 +198,6 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 同步给主库对应的product_book_xx中
|
// 同步给主库对应的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中
|
// 同步给主库对应的product_book_xx中
|
||||||
// 获取租户数据库连接
|
// 获取租户数据库连接
|
||||||
tenantDB, err := database.GetTenantDB(aboutID)
|
tenantDB, err := database.GetTenantDB(aboutID)
|
||||||
@ -230,52 +222,188 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询库位信息(用于获取库位名称)
|
// 查询库位信息(获取库位ID和Code)
|
||||||
locationMap := make(map[int64]string)
|
type locationInfo struct {
|
||||||
|
LocationID int64
|
||||||
|
Code string
|
||||||
|
}
|
||||||
|
locationMap := make(map[int64]locationInfo)
|
||||||
for _, product := range products {
|
for _, product := range products {
|
||||||
// 通过库存明细表查询商品所在的库位
|
|
||||||
var inventoryDetail models.InventoryDetail
|
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 {
|
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
|
var location models.Location
|
||||||
if err := tenantDB.Where("id = ? AND is_del = 0", inventoryDetail.LocationID).First(&location).Error; err == nil {
|
if err := tenantDB.Where("id = ? AND is_del = 0", inventoryDetail.LocationID).First(&location).Error; err == nil {
|
||||||
locationMap[product.ID] = location.Code
|
locationMap[product.ID] = locationInfo{
|
||||||
|
LocationID: location.ID,
|
||||||
|
Code: location.Code,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 逐个同步商品到主库
|
// 查询BookInfo(按StandardProductID关联)
|
||||||
|
bookInfoMap := make(map[int64]models.BookInfo)
|
||||||
for _, product := range products {
|
for _, product := range products {
|
||||||
locationCode := ""
|
if product.StandardProductID > 0 {
|
||||||
if code, exists := locationMap[product.ID]; exists {
|
if _, exists := bookInfoMap[product.StandardProductID]; !exists {
|
||||||
locationCode = code
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
if syncErr := database.SyncProductToMainDB(aboutID, &product, warehouse.ID, warehouse.Name, 0, locationCode); syncErr != nil {
|
tableName := models.ProductBookTableName(isbn)
|
||||||
utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{
|
|
||||||
"source": "同步商品到主库失败",
|
var locInfo locationInfo
|
||||||
"user_id": aboutID,
|
if li, exists := locationMap[product.ID]; exists {
|
||||||
"product_id": product.ID,
|
locInfo = li
|
||||||
"warehouse_id": warehouse.ID,
|
}
|
||||||
"location_code": locationCode,
|
|
||||||
"err_msg": syncErr.Error(),
|
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 {
|
} else {
|
||||||
utils.InfoLog(constant.LoggerChannelWork, logrus.Fields{
|
utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{
|
||||||
"source": "同步商品到主库成功",
|
"source": "查询product_book分表失败",
|
||||||
"user_id": aboutID,
|
"user_id": aboutID,
|
||||||
"product_id": product.ID,
|
"self_id": product.ID,
|
||||||
"product_name": product.Name,
|
"isbn": isbn,
|
||||||
"barcode": product.Barcode,
|
"table_name": tableName,
|
||||||
"warehouse_id": warehouse.ID,
|
"err_msg": err.Error(),
|
||||||
"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)
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import (
|
|||||||
|
|
||||||
// ProductBook 商品书籍分表(按ISBN后两位分表 product_book_00 ~ product_book_99)
|
// ProductBook 商品书籍分表(按ISBN后两位分表 product_book_00 ~ product_book_99)
|
||||||
type ProductBook struct {
|
type ProductBook struct {
|
||||||
ID int64 `json:"id" gorm:"primarykey;comment:商品ID"`
|
ID int64 `json:"id" gorm:"primarykey;comment:自增ID"`
|
||||||
|
SelfID int64 `json:"self_id" gorm:"not null;default:0;comment:再分库商品表中的商品ID"`
|
||||||
CategoryID int64 `json:"category_id" gorm:"not null;default:0;comment:分类ID"`
|
CategoryID int64 `json:"category_id" gorm:"not null;default:0;comment:分类ID"`
|
||||||
AboutId int64 `json:"about_id" gorm:"not null;default:0;index;comment:关联ID"`
|
AboutId int64 `json:"about_id" gorm:"not null;default:0;index;comment:关联ID"`
|
||||||
WarehouseID int64 `json:"warehouse_id" gorm:"not null;default:0;index;comment:仓库ID"`
|
WarehouseID int64 `json:"warehouse_id" gorm:"not null;default:0;index;comment:仓库ID"`
|
||||||
|
|||||||
@ -29,25 +29,25 @@ type CreateLogisticsRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UpdateLogisticsRequest struct {
|
type UpdateLogisticsRequest struct {
|
||||||
Id uint64 `form:"id" binding:"required"`
|
Id uint64 `form:"id" binding:"required"` // 物流模板ID
|
||||||
TemplateName string `form:"template_name" binding:"required,max=255"`
|
TemplateName string `form:"template_name" binding:"required,max=255"` // 物流模板名称
|
||||||
DeliveryProvince string `form:"delivery_province" binding:"required,max=255"`
|
DeliveryProvince string `form:"delivery_province" binding:"required,max=255"` // 发货省
|
||||||
DeliveryCity string `form:"delivery_city" binding:"required,max=255"`
|
DeliveryCity string `form:"delivery_city" binding:"required,max=255"` // 发货市
|
||||||
DeliveryArea string `form:"delivery_area" binding:"required,max=255"`
|
DeliveryArea string `form:"delivery_area" binding:"required,max=255"` // 发货区
|
||||||
DeliveryAddress string `form:"delivery_address" binding:"required,max=255"`
|
DeliveryAddress string `form:"delivery_address" binding:"required,max=255"` // 发货地址
|
||||||
PricingMethod string `form:"pricing_method" binding:"required,oneof=0 1 2 3"`
|
PricingMethod string `form:"pricing_method" binding:"required,oneof=0 1 2 3"` // 计费方式
|
||||||
Shipping string `form:"shipping" binding:"required,oneof=0 1 2"`
|
Shipping string `form:"shipping" binding:"required,oneof=0 1 2"` // 配送方式
|
||||||
FirWbv float64 `form:"fir_wbv"`
|
FirWbv float64 `form:"fir_wbv"` // 首件
|
||||||
FirPrice float64 `form:"fir_price"`
|
FirPrice float64 `form:"fir_price"` // 首费
|
||||||
ContinueWbv float64 `form:"continue_wbv"`
|
ContinueWbv float64 `form:"continue_wbv"` // 续件
|
||||||
ContinuePrice float64 `form:"continue_price"`
|
ContinuePrice float64 `form:"continue_price"` // 续费
|
||||||
Contact string `form:"contact" binding:"required,max=14"`
|
Contact string `form:"contact" binding:"required,max=14"` // 联系人
|
||||||
PhoneNumber uint64 `form:"phone_number" binding:"required"`
|
PhoneNumber uint64 `form:"phone_number" binding:"required"` // 联系电话
|
||||||
FullAddress string `form:"full_address" binding:"required,max=255"`
|
FullAddress string `form:"full_address" binding:"required,max=255"` // 收货地址
|
||||||
ShippingRange string `form:"shipping_range" binding:"required"`
|
ShippingRange string `form:"shipping_range" binding:"required"` // 配送范围
|
||||||
WarehouseId uint64 `form:"warehouse_id"`
|
WarehouseId uint64 `form:"warehouse_id"` // 仓库ID
|
||||||
Remark string `form:"remark" binding:"max=255"`
|
Remark string `form:"remark" binding:"max=255"` // 备注
|
||||||
Status string `form:"status" binding:"oneof=0 1"`
|
Status string `form:"status" binding:"oneof=0 1"` // 状态
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeleteLogisticsRequest struct {
|
type DeleteLogisticsRequest struct {
|
||||||
|
|||||||
@ -12,13 +12,13 @@ type GetSplitAccountDeductionLogListRequest struct {
|
|||||||
|
|
||||||
// AddSplitAccountDeductionLogRequest 添加分账扣钱日志请求
|
// AddSplitAccountDeductionLogRequest 添加分账扣钱日志请求
|
||||||
type AddSplitAccountDeductionLogRequest struct {
|
type AddSplitAccountDeductionLogRequest struct {
|
||||||
BusinessNo string `form:"business_no" binding:"required"`
|
BusinessNo string `form:"business_no" binding:"required"` // 业务单号
|
||||||
ConfigID int64 `form:"config_id" binding:"required"`
|
ConfigID int64 `form:"config_id" binding:"required"` // 分账配置ID
|
||||||
ConfigName string `form:"config_name" binding:"required"`
|
ConfigName string `form:"config_name" binding:"required"` // 分账配置名称
|
||||||
DeductionDetails string `form:"deduction_details" binding:"required"`
|
DeductionDetails string `form:"deduction_details" binding:"required"` // 扣钱详情
|
||||||
TotalAmount float64 `form:"total_amount" binding:"required"`
|
TotalAmount float64 `form:"total_amount" binding:"required"` // 总金额
|
||||||
DeductionAmount float64 `form:"deduction_amount" binding:"required"`
|
DeductionAmount float64 `form:"deduction_amount" binding:"required"` // 扣钱金额
|
||||||
RemainingAmount float64 `form:"remaining_amount" binding:"required"`
|
RemainingAmount float64 `form:"remaining_amount" binding:"required"` // 剩余金额
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateSplitAccountDeductionLogRequest 更新分账扣钱日志请求
|
// UpdateSplitAccountDeductionLogRequest 更新分账扣钱日志请求
|
||||||
@ -29,6 +29,7 @@ type UpdateSplitAccountDeductionLogRequest struct {
|
|||||||
ConfigName string `form:"config_name"`
|
ConfigName string `form:"config_name"`
|
||||||
DeductionDetails string `form:"deduction_details"`
|
DeductionDetails string `form:"deduction_details"`
|
||||||
TotalAmount float64 `form:"total_amount"`
|
TotalAmount float64 `form:"total_amount"`
|
||||||
|
Status int8 `form:"status"`
|
||||||
DeductionAmount float64 `form:"deduction_amount"`
|
DeductionAmount float64 `form:"deduction_amount"`
|
||||||
RemainingAmount float64 `form:"remaining_amount"`
|
RemainingAmount float64 `form:"remaining_amount"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ type SplitAccountDeductionLog struct {
|
|||||||
TotalAmount float64 `json:"total_amount" gorm:"type:decimal(15,2);not null;default:0.00;comment:总金额(分账前)"`
|
TotalAmount float64 `json:"total_amount" gorm:"type:decimal(15,2);not null;default:0.00;comment:总金额(分账前)"`
|
||||||
DeductionAmount float64 `json:"deduction_amount" gorm:"type:decimal(15,2);not null;default:0.00;comment:扣款总金额"`
|
DeductionAmount float64 `json:"deduction_amount" gorm:"type:decimal(15,2);not null;default:0.00;comment:扣款总金额"`
|
||||||
RemainingAmount float64 `json:"remaining_amount" gorm:"type:decimal(15,2);not null;default:0.00;comment:剩余金额(分账后)"`
|
RemainingAmount float64 `json:"remaining_amount" gorm:"type:decimal(15,2);not null;default:0.00;comment:剩余金额(分账后)"`
|
||||||
|
Status int8 `json:"status" gorm:"type:tinyint;not null;default:0;comment:状态 0:正常 1:退款"`
|
||||||
CreatedBy string `json:"created_by" gorm:"size:100;not null;default:'';comment:创建人/系统"`
|
CreatedBy string `json:"created_by" gorm:"size:100;not null;default:'';comment:创建人/系统"`
|
||||||
UpdatedBy string `json:"updated_by" gorm:"size:100;comment:更新人"`
|
UpdatedBy string `json:"updated_by" gorm:"size:100;comment:更新人"`
|
||||||
CreatedAt int64 `json:"created_at" gorm:"type:bigint;default:0;comment:创建时间戳(秒)"`
|
CreatedAt int64 `json:"created_at" gorm:"type:bigint;default:0;comment:创建时间戳(秒)"`
|
||||||
|
|||||||
@ -797,10 +797,7 @@ func (s *ProcessService) loadOrderAndWaveDetails(tx *gorm.DB, orderID, waveTaskI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// processOrderItems 处理订单明细
|
// processOrderItems 处理订单明细
|
||||||
func (s *ProcessService) processOrderItems(tx *gorm.DB, items []orderItemInfo, orderInfo *orderInfo,
|
func (s *ProcessService) processOrderItems(tx *gorm.DB, items []orderItemInfo, orderInfo *orderInfo, productMap map[int64]models.Product, locationMap map[int64]models.Location, orderItemMap map[int64]interface{}, waveTaskDetailMap map[int64]*models.WaveTaskDetail, operator string, operatorID int64, now int64, changeType int8) (map[inventoryKey]*inventoryOperation, []models.InventoryLog, error) {
|
||||||
productMap map[int64]models.Product, locationMap map[int64]models.Location,
|
|
||||||
orderItemMap map[int64]interface{}, waveTaskDetailMap map[int64]*models.WaveTaskDetail,
|
|
||||||
operator string, operatorID int64, now int64, changeType int8) (map[inventoryKey]*inventoryOperation, []models.InventoryLog, error) {
|
|
||||||
|
|
||||||
inventoryOpMap := make(map[inventoryKey]*inventoryOperation)
|
inventoryOpMap := make(map[inventoryKey]*inventoryOperation)
|
||||||
|
|
||||||
@ -999,8 +996,7 @@ func (s *ProcessService) processOrderItems(tx *gorm.DB, items []orderItemInfo, o
|
|||||||
}
|
}
|
||||||
|
|
||||||
// executeInventoryOperations 执行库存操作
|
// executeInventoryOperations 执行库存操作
|
||||||
func (s *ProcessService) executeInventoryOperations(tx *gorm.DB, inventoryOpMap map[inventoryKey]*inventoryOperation,
|
func (s *ProcessService) executeInventoryOperations(tx *gorm.DB, inventoryOpMap map[inventoryKey]*inventoryOperation, inventoryLogs []models.InventoryLog, orderNo string, operator string, operatorID int64, now int64, changeType int8) error {
|
||||||
inventoryLogs []models.InventoryLog, orderNo string, operator string, operatorID int64, now int64, changeType int8) error {
|
|
||||||
|
|
||||||
for _, op := range inventoryOpMap {
|
for _, op := range inventoryOpMap {
|
||||||
log, err := s.processInventoryOperation(tx, op.key, op.locationID, op.quantity, changeType, orderNo, operator, operatorID, now)
|
log, err := s.processInventoryOperation(tx, op.key, op.locationID, op.quantity, changeType, orderNo, operator, operatorID, now)
|
||||||
@ -2667,8 +2663,7 @@ func (s *ProcessService) ChangeLocation(req systemReq.ChangeLocationRequest, ope
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建波次
|
// 创建波次
|
||||||
func (s *ProcessService) createWaveHeader(tx *gorm.DB, waveNo string, direction int8,
|
func (s *ProcessService) createWaveHeader(tx *gorm.DB, waveNo string, direction int8, warehouseID, relatedOrderID int64, creator string, creatorID int64) (*models.WaveHeader, error) {
|
||||||
warehouseID, relatedOrderID int64, creator string, creatorID int64) (*models.WaveHeader, error) {
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
waveHeader := models.WaveHeader{
|
waveHeader := models.WaveHeader{
|
||||||
WaveNo: waveNo,
|
WaveNo: waveNo,
|
||||||
@ -2718,8 +2713,7 @@ func (s *ProcessService) createWaveTaskDetails(tx *gorm.DB, waveTaskID int64, it
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建波次任务和明细
|
// 创建波次任务和明细
|
||||||
func (s *ProcessService) createWaveTaskAndDetails(tx *gorm.DB, waveID int64, taskType int8,
|
func (s *ProcessService) createWaveTaskAndDetails(tx *gorm.DB, waveID int64, taskType int8, items []WaveItemData, assignee string, assigneeID, carId, carCode, carCapacity int64) (*models.WaveTask, error) {
|
||||||
items []WaveItemData, assignee string, assigneeID, carId, carCode, carCapacity int64) (*models.WaveTask, error) {
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
taskNo := utils.GenerateTaskNo()
|
taskNo := utils.GenerateTaskNo()
|
||||||
taskTd := utils.GenerateTaskDetailNo()
|
taskTd := utils.GenerateTaskDetailNo()
|
||||||
@ -2767,8 +2761,7 @@ func (s *ProcessService) createWaveTaskAndDetails(tx *gorm.DB, waveID int64, tas
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createWaveTaskAndDetailsForOutbound 创建出库波次任务和明细(使用入库批次号)
|
// createWaveTaskAndDetailsForOutbound 创建出库波次任务和明细(使用入库批次号)
|
||||||
func (s *ProcessService) createWaveTaskAndDetailsForOutbound(tx *gorm.DB, waveID int64, taskType int8,
|
func (s *ProcessService) createWaveTaskAndDetailsForOutbound(tx *gorm.DB, waveID int64, taskType int8, items []WaveItemData, outboundItems []models.OutboundOrderItem, assignee string, assigneeID, carId, carCode, carCapacity int64) (*models.WaveTask, error) {
|
||||||
items []WaveItemData, outboundItems []models.OutboundOrderItem, assignee string, assigneeID, carId, carCode, carCapacity int64) (*models.WaveTask, error) {
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
taskNo := utils.GenerateTaskNo()
|
taskNo := utils.GenerateTaskNo()
|
||||||
|
|
||||||
@ -2864,8 +2857,7 @@ func (s *ProcessService) updateWaveTaskToPicking(tx *gorm.DB, waveTaskID int64)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理库存操作(使用原子操作和行级锁保证并发安全)
|
// 处理库存操作(使用原子操作和行级锁保证并发安全)
|
||||||
func (s *ProcessService) processInventoryOperation(tx *gorm.DB, opKey inventoryKey, locationID int64,
|
func (s *ProcessService) processInventoryOperation(tx *gorm.DB, opKey inventoryKey, locationID int64, quantity int64, changeType int8, orderNo string, operator string, operatorID int64, now int64) (*models.InventoryLog, error) {
|
||||||
quantity int64, changeType int8, orderNo string, operator string, operatorID int64, now int64) (*models.InventoryLog, error) {
|
|
||||||
|
|
||||||
if changeType == constant.InventoryChangeInbound {
|
if changeType == constant.InventoryChangeInbound {
|
||||||
var inventory models.Inventory
|
var inventory models.Inventory
|
||||||
@ -3499,8 +3491,7 @@ func (s *ProcessService) CancelSalesOrder(orderID int64, operator string, operat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// processInventoryOperationForAdjustment 处理盘库调整的库存汇总操作
|
// processInventoryOperationForAdjustment 处理盘库调整的库存汇总操作
|
||||||
func (s *ProcessService) processInventoryOperationForAdjustment(tx *gorm.DB, opKey inventoryKey, locationID int64,
|
func (s *ProcessService) processInventoryOperationForAdjustment(tx *gorm.DB, opKey inventoryKey, locationID int64, quantity int64, orderNo string, operator string, operatorID int64, now int64, remark string) (*models.InventoryLog, error) {
|
||||||
quantity int64, orderNo string, operator string, operatorID int64, now int64, remark string) (*models.InventoryLog, error) {
|
|
||||||
|
|
||||||
var inventory models.Inventory
|
var inventory models.Inventory
|
||||||
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||||
@ -3598,8 +3589,7 @@ func (s *ProcessService) processInventoryOperationForAdjustment(tx *gorm.DB, opK
|
|||||||
}
|
}
|
||||||
|
|
||||||
// processInventoryDetailOperationForAdjustment 处理盘库调整的库存明细操作
|
// processInventoryDetailOperationForAdjustment 处理盘库调整的库存明细操作
|
||||||
func (s *ProcessService) processInventoryDetailOperationForAdjustment(tx *gorm.DB, opKey inventoryKey, locationID int64,
|
func (s *ProcessService) processInventoryDetailOperationForAdjustment(tx *gorm.DB, opKey inventoryKey, locationID int64, quantity int64, now int64) error {
|
||||||
quantity int64, now int64) error {
|
|
||||||
|
|
||||||
var inventoryDetail models.InventoryDetail
|
var inventoryDetail models.InventoryDetail
|
||||||
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||||
|
|||||||
@ -675,10 +675,10 @@ func (s *ProductService) GetProductInventory(req systemReq.GetProductInventoryRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
var groupList []GroupStock
|
var groupList []GroupStock
|
||||||
// 先根据商品的 ISBN 和品相,查询所有匹配的库存记录,再按仓库分组统计
|
// 先根据商品的 ISBN 和品相,查询所有匹配的库存记录,再按仓库分组统计(可用量 = 总量 - 锁定量)
|
||||||
databaseConn.Table("inventory").
|
databaseConn.Table("inventory").
|
||||||
Select(`
|
Select(`
|
||||||
COALESCE(SUM(inventory.quantity), 0) as total_quantity
|
COALESCE(SUM(inventory.quantity - inventory.locked_quantity), 0) as total_quantity
|
||||||
`).
|
`).
|
||||||
Joins("LEFT JOIN product p ON inventory.product_id = p.id AND p.is_del = ?", 0).
|
Joins("LEFT JOIN product p ON inventory.product_id = p.id AND p.is_del = ?", 0).
|
||||||
Where("p.barcode = ? AND p.appearance = ? AND inventory.warehouse_id IS NOT NULL AND inventory.is_del = ?",
|
Where("p.barcode = ? AND p.appearance = ? AND inventory.warehouse_id IS NOT NULL AND inventory.is_del = ?",
|
||||||
@ -686,7 +686,7 @@ func (s *ProductService) GetProductInventory(req systemReq.GetProductInventoryRe
|
|||||||
Group("inventory.warehouse_id").
|
Group("inventory.warehouse_id").
|
||||||
Scan(&groupList)
|
Scan(&groupList)
|
||||||
|
|
||||||
// 累加所有分组的数量
|
// 累加所有分组的可用数量
|
||||||
for _, group := range groupList {
|
for _, group := range groupList {
|
||||||
totalQuantity += group.TotalQuantity
|
totalQuantity += group.TotalQuantity
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user