修复了查询库存接口未计算锁定库存问题
修复了同步反射商品表未同步到的问题
This commit is contained in:
parent
31f300e0b3
commit
d0e9a0fa82
@ -4,10 +4,12 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -196,16 +198,6 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 同步给主库对应的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)
|
||||
@ -230,52 +222,188 @@ func (r *ProcessApi) SubmitReceiving(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 查询库位信息(用于获取库位名称)
|
||||
locationMap := make(map[int64]string)
|
||||
// 查询库位信息(获取库位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] = location.Code
|
||||
locationMap[product.ID] = locationInfo{
|
||||
LocationID: location.ID,
|
||||
Code: location.Code,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 逐个同步商品到主库
|
||||
// 查询BookInfo(按StandardProductID关联)
|
||||
bookInfoMap := make(map[int64]models.BookInfo)
|
||||
for _, product := range products {
|
||||
locationCode := ""
|
||||
if code, exists := locationMap[product.ID]; exists {
|
||||
locationCode = code
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if syncErr := database.SyncProductToMainDB(aboutID, &product, warehouse.ID, warehouse.Name, 0, locationCode); syncErr != nil {
|
||||
// 逐个写入主库 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": "同步商品到主库失败",
|
||||
"source": "写入product_book分表失败",
|
||||
"user_id": aboutID,
|
||||
"product_id": product.ID,
|
||||
"self_id": product.ID,
|
||||
"isbn": isbn,
|
||||
"table_name": tableName,
|
||||
"warehouse_id": warehouse.ID,
|
||||
"location_code": locationCode,
|
||||
"err_msg": syncErr.Error(),
|
||||
"err_msg": createErr.Error(),
|
||||
})
|
||||
} else {
|
||||
utils.InfoLog(constant.LoggerChannelWork, logrus.Fields{
|
||||
"source": "同步商品到主库成功",
|
||||
"source": "写入product_book分表成功",
|
||||
"user_id": aboutID,
|
||||
"product_id": product.ID,
|
||||
"product_name": product.Name,
|
||||
"barcode": product.Barcode,
|
||||
"self_id": product.ID,
|
||||
"isbn": isbn,
|
||||
"table_name": tableName,
|
||||
"warehouse_id": warehouse.ID,
|
||||
"location_code": locationCode,
|
||||
"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
|
||||
|
||||
//warehouseId := warehouse.ID
|
||||
|
||||
productIds := make([]string, len(itemProductIDs))
|
||||
for i, pid := range itemProductIDs {
|
||||
productIds[i] = fmt.Sprintf("%d", pid)
|
||||
|
||||
@ -7,7 +7,8 @@ import (
|
||||
|
||||
// ProductBook 商品书籍分表(按ISBN后两位分表 product_book_00 ~ product_book_99)
|
||||
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"`
|
||||
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"`
|
||||
|
||||
@ -29,25 +29,25 @@ type CreateLogisticsRequest struct {
|
||||
}
|
||||
|
||||
type UpdateLogisticsRequest struct {
|
||||
Id uint64 `form:"id" binding:"required"`
|
||||
TemplateName string `form:"template_name" binding:"required,max=255"`
|
||||
DeliveryProvince string `form:"delivery_province" binding:"required,max=255"`
|
||||
DeliveryCity string `form:"delivery_city" binding:"required,max=255"`
|
||||
DeliveryArea string `form:"delivery_area" 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"`
|
||||
Shipping string `form:"shipping" binding:"required,oneof=0 1 2"`
|
||||
FirWbv float64 `form:"fir_wbv"`
|
||||
FirPrice float64 `form:"fir_price"`
|
||||
ContinueWbv float64 `form:"continue_wbv"`
|
||||
ContinuePrice float64 `form:"continue_price"`
|
||||
Contact string `form:"contact" binding:"required,max=14"`
|
||||
PhoneNumber uint64 `form:"phone_number" binding:"required"`
|
||||
FullAddress string `form:"full_address" binding:"required,max=255"`
|
||||
ShippingRange string `form:"shipping_range" binding:"required"`
|
||||
WarehouseId uint64 `form:"warehouse_id"`
|
||||
Remark string `form:"remark" binding:"max=255"`
|
||||
Status string `form:"status" binding:"oneof=0 1"`
|
||||
Id uint64 `form:"id" binding:"required"` // 物流模板ID
|
||||
TemplateName string `form:"template_name" binding:"required,max=255"` // 物流模板名称
|
||||
DeliveryProvince string `form:"delivery_province" binding:"required,max=255"` // 发货省
|
||||
DeliveryCity string `form:"delivery_city" binding:"required,max=255"` // 发货市
|
||||
DeliveryArea string `form:"delivery_area" 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"` // 计费方式
|
||||
Shipping string `form:"shipping" binding:"required,oneof=0 1 2"` // 配送方式
|
||||
FirWbv float64 `form:"fir_wbv"` // 首件
|
||||
FirPrice float64 `form:"fir_price"` // 首费
|
||||
ContinueWbv float64 `form:"continue_wbv"` // 续件
|
||||
ContinuePrice float64 `form:"continue_price"` // 续费
|
||||
Contact string `form:"contact" binding:"required,max=14"` // 联系人
|
||||
PhoneNumber uint64 `form:"phone_number" binding:"required"` // 联系电话
|
||||
FullAddress string `form:"full_address" binding:"required,max=255"` // 收货地址
|
||||
ShippingRange string `form:"shipping_range" binding:"required"` // 配送范围
|
||||
WarehouseId uint64 `form:"warehouse_id"` // 仓库ID
|
||||
Remark string `form:"remark" binding:"max=255"` // 备注
|
||||
Status string `form:"status" binding:"oneof=0 1"` // 状态
|
||||
}
|
||||
|
||||
type DeleteLogisticsRequest struct {
|
||||
|
||||
@ -12,13 +12,13 @@ type GetSplitAccountDeductionLogListRequest struct {
|
||||
|
||||
// AddSplitAccountDeductionLogRequest 添加分账扣钱日志请求
|
||||
type AddSplitAccountDeductionLogRequest struct {
|
||||
BusinessNo string `form:"business_no" binding:"required"`
|
||||
ConfigID int64 `form:"config_id" binding:"required"`
|
||||
ConfigName string `form:"config_name" binding:"required"`
|
||||
DeductionDetails string `form:"deduction_details" binding:"required"`
|
||||
TotalAmount float64 `form:"total_amount" binding:"required"`
|
||||
DeductionAmount float64 `form:"deduction_amount" binding:"required"`
|
||||
RemainingAmount float64 `form:"remaining_amount" binding:"required"`
|
||||
BusinessNo string `form:"business_no" binding:"required"` // 业务单号
|
||||
ConfigID int64 `form:"config_id" binding:"required"` // 分账配置ID
|
||||
ConfigName string `form:"config_name" binding:"required"` // 分账配置名称
|
||||
DeductionDetails string `form:"deduction_details" binding:"required"` // 扣钱详情
|
||||
TotalAmount float64 `form:"total_amount" binding:"required"` // 总金额
|
||||
DeductionAmount float64 `form:"deduction_amount" binding:"required"` // 扣钱金额
|
||||
RemainingAmount float64 `form:"remaining_amount" binding:"required"` // 剩余金额
|
||||
}
|
||||
|
||||
// UpdateSplitAccountDeductionLogRequest 更新分账扣钱日志请求
|
||||
@ -29,6 +29,7 @@ type UpdateSplitAccountDeductionLogRequest struct {
|
||||
ConfigName string `form:"config_name"`
|
||||
DeductionDetails string `form:"deduction_details"`
|
||||
TotalAmount float64 `form:"total_amount"`
|
||||
Status int8 `form:"status"`
|
||||
DeductionAmount float64 `form:"deduction_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:总金额(分账前)"`
|
||||
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:剩余金额(分账后)"`
|
||||
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:创建人/系统"`
|
||||
UpdatedBy string `json:"updated_by" gorm:"size:100;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 处理订单明细
|
||||
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) {
|
||||
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) {
|
||||
|
||||
inventoryOpMap := make(map[inventoryKey]*inventoryOperation)
|
||||
|
||||
@ -999,8 +996,7 @@ func (s *ProcessService) processOrderItems(tx *gorm.DB, items []orderItemInfo, o
|
||||
}
|
||||
|
||||
// executeInventoryOperations 执行库存操作
|
||||
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 {
|
||||
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 {
|
||||
|
||||
for _, op := range inventoryOpMap {
|
||||
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,
|
||||
warehouseID, relatedOrderID int64, creator string, creatorID int64) (*models.WaveHeader, error) {
|
||||
func (s *ProcessService) createWaveHeader(tx *gorm.DB, waveNo string, direction int8, warehouseID, relatedOrderID int64, creator string, creatorID int64) (*models.WaveHeader, error) {
|
||||
now := time.Now().Unix()
|
||||
waveHeader := models.WaveHeader{
|
||||
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,
|
||||
items []WaveItemData, assignee string, assigneeID, carId, carCode, carCapacity int64) (*models.WaveTask, error) {
|
||||
func (s *ProcessService) createWaveTaskAndDetails(tx *gorm.DB, waveID int64, taskType int8, items []WaveItemData, assignee string, assigneeID, carId, carCode, carCapacity int64) (*models.WaveTask, error) {
|
||||
now := time.Now().Unix()
|
||||
taskNo := utils.GenerateTaskNo()
|
||||
taskTd := utils.GenerateTaskDetailNo()
|
||||
@ -2767,8 +2761,7 @@ func (s *ProcessService) createWaveTaskAndDetails(tx *gorm.DB, waveID int64, tas
|
||||
}
|
||||
|
||||
// createWaveTaskAndDetailsForOutbound 创建出库波次任务和明细(使用入库批次号)
|
||||
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) {
|
||||
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) {
|
||||
now := time.Now().Unix()
|
||||
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,
|
||||
quantity int64, changeType int8, orderNo string, operator string, operatorID int64, now int64) (*models.InventoryLog, error) {
|
||||
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) {
|
||||
|
||||
if changeType == constant.InventoryChangeInbound {
|
||||
var inventory models.Inventory
|
||||
@ -3499,8 +3491,7 @@ func (s *ProcessService) CancelSalesOrder(orderID int64, operator string, operat
|
||||
}
|
||||
|
||||
// processInventoryOperationForAdjustment 处理盘库调整的库存汇总操作
|
||||
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) {
|
||||
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) {
|
||||
|
||||
var inventory models.Inventory
|
||||
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||
@ -3598,8 +3589,7 @@ func (s *ProcessService) processInventoryOperationForAdjustment(tx *gorm.DB, opK
|
||||
}
|
||||
|
||||
// processInventoryDetailOperationForAdjustment 处理盘库调整的库存明细操作
|
||||
func (s *ProcessService) processInventoryDetailOperationForAdjustment(tx *gorm.DB, opKey inventoryKey, locationID int64,
|
||||
quantity int64, now int64) error {
|
||||
func (s *ProcessService) processInventoryDetailOperationForAdjustment(tx *gorm.DB, opKey inventoryKey, locationID int64, quantity int64, now int64) error {
|
||||
|
||||
var inventoryDetail models.InventoryDetail
|
||||
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||
|
||||
@ -675,10 +675,10 @@ func (s *ProductService) GetProductInventory(req systemReq.GetProductInventoryRe
|
||||
}
|
||||
|
||||
var groupList []GroupStock
|
||||
// 先根据商品的 ISBN 和品相,查询所有匹配的库存记录,再按仓库分组统计
|
||||
// 先根据商品的 ISBN 和品相,查询所有匹配的库存记录,再按仓库分组统计(可用量 = 总量 - 锁定量)
|
||||
databaseConn.Table("inventory").
|
||||
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).
|
||||
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").
|
||||
Scan(&groupList)
|
||||
|
||||
// 累加所有分组的数量
|
||||
// 累加所有分组的可用数量
|
||||
for _, group := range groupList {
|
||||
totalQuantity += group.TotalQuantity
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user