mh_goadmin_server/app/admin/models/inventory_change.go
chenlin c17e078290 1.修复缺陷:
(1)零售取消销售锁定状态,审核通过库存即改为已售;
(2)门店过期时间对应是过期当天的23:59:59;
(3)库存调拨后更新最新入库时间;
(4)库存导入、商品导入校验规则优化;
2024-04-29 18:10:48 +08:00

994 lines
34 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package models
import (
"errors"
"fmt"
orm "go-admin/common/global"
"go-admin/logger"
"go-admin/tools"
"gorm.io/gorm"
"math/rand"
"time"
)
const (
ErpInventoryChangeOrderUnAudit = 1 // 库存变动-待审核
ErpInventoryChangeOrderFinished = 2 // 库存变动-已完成
AddChangeOrder = "add" // 库存增加
ReduceChangeOrder = "reduce" // 库存减少
)
// ErpInventoryChangeOrder 库存变动订单表
type ErpInventoryChangeOrder struct {
Model
SerialNumber string `json:"serial_number" gorm:"index"` // 单据编号
ChangeType string `json:"change_type"` // 类型:add-增加reduce-减少
StoreId uint32 `json:"store_id" gorm:"index"` // 门店id
StoreName string `json:"store_name"` // 门店名称
HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
MakerTime *time.Time `json:"maker_time"` // 制单时间
MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id
MakerName string `json:"maker_name"` // 制单人名称
AuditTime *time.Time `json:"audit_time"` // 审核时间
AuditorId uint32 `json:"auditor_id" gorm:"index"` // 审核人id
AuditorName string `json:"auditor_name"` // 审核人名称
State uint32 `json:"state"` // 1-待审核 2-已完成
TotalCount uint32 `json:"total_count"` // 总数量
TotalAmount float64 `json:"total_amount"` // 总金额
Commodities []ErpInventoryChangeCommodity `json:"commodities" gorm:"-"` // 库存变动商品信息
}
// ErpInventoryChangeCommodity 库存变动商品信息表
type ErpInventoryChangeCommodity struct {
Model
ChangeOrderId uint32 `json:"change_order_id" gorm:"index"` // 库存变动订单表id
CommodityId uint32 `json:"commodity_id" gorm:"index"` // 商品id
CommodityName string `json:"commodity_name"` // 商品名称
SupplierId uint32 `json:"supplier_id" gorm:"index"` // 供应商id
SupplierName string `json:"supplier_name"` // 供应商名称
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei"` // 商品串码
Count uint32 `json:"count"` // 计划数量
Price float64 `json:"price"` // 采购单价
EmployeePrice float64 `json:"employee_price"` // 员工成本价
Amount float64 `json:"amount"` // 金额
Remark string `json:"remark"` // 备注
}
// InventoryChangeAddReq 新增库存变动入参
type InventoryChangeAddReq struct {
StoreId uint32 `json:"store_id" binding:"required"` // 门店id
StoreName string `json:"store_name" binding:"required"` // 门店名称
HandlerId uint32 `json:"handler_id" binding:"required"` // 经手人id
HandlerName string `json:"handler_name" binding:"required"` // 经手人名称
ChangeType string `json:"change_type" binding:"required"` // 库存变动类型add-库存增加 reduce-库存减少
Commodities []ErpInventoryChangeCommodity `json:"commodities" binding:"required"` // 库存变动商品信息
}
// InventoryChangeEditReq 编辑库存变动入参
type InventoryChangeEditReq struct {
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
InventoryChangeAddReq
}
// InventoryChangeAuditReq 审核入参
type InventoryChangeAuditReq struct {
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
State int `json:"state" binding:"required"` // 审核操作: 1-审核 2-取消审核
}
// InventoryChangeDeleteReq 删除入参
type InventoryChangeDeleteReq struct {
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
}
// InventoryChangeListReq 查询库存变动列表入参
type InventoryChangeListReq struct {
SerialNumber string `json:"serial_number"` // 单据编号
ChangeType string `json:"change_type"` // 类型:add-增加reduce-减少
StoreId uint32 `json:"store_id"` // 门店id
HandlerId uint32 `json:"handler_id"` // 经手人id
State int `json:"state"` // 1-待审核 2-已完成
AuditTimeStart string `json:"audit_time_start"` // 审核开始时间
AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
// InventoryChangeListResp 查询库存变动列表出参
type InventoryChangeListResp struct {
List []ErpInventoryChangeOrder `json:"list"`
Total int `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
// InventoryChangeDetailReq 查询库存变动详情入参
type InventoryChangeDetailReq struct {
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
}
// newChangeInventorySn 生成库存变动订单号
func newChangeInventorySn(changeType string) string {
var prefix string
switch changeType {
case "add": // 库存增加
prefix = "kcz"
case "reduce": // 库存减少
prefix = "kcj"
}
nowTime := time.Now()
rand.Seed(nowTime.UnixNano())
max := 1
for {
if max > 5 {
logger.Error("create NewChangeInventorySn err")
return ""
}
random := rand.Intn(9000) + 1000
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_inventory_change_order "+
"WHERE serial_number='%s'", prefix+sn))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return prefix + sn
}
max++
}
}
// 检查新增库存变动入参信息
func checkChangeInventoryParam(req *InventoryChangeAddReq, editFlag bool) error {
if len(req.Commodities) == 0 {
return errors.New("商品信息为空")
}
if req.ChangeType != AddChangeOrder && req.ChangeType != ReduceChangeOrder {
return errors.New("库存变动类型错误")
}
noIMEICommodityMap := make(map[uint32]bool, 0)
for _, item := range req.Commodities {
// 校验数量
if item.Count <= 0 {
return fmt.Errorf("商品[%s]数量[%d]错误需大于0", item.CommodityName, item.Count)
} else {
if item.Count != 1 && item.IMEIType != NoIMEICommodity { // 串码商品数量不为1则报错
return fmt.Errorf("串码商品[%s]数量[%d]错误需为1", item.CommodityName, item.Count)
}
}
// 校验编辑订单时是否有传商品ID
if editFlag {
if item.ID == 0 {
return fmt.Errorf("商品[%s]ID为空", item.CommodityName)
}
}
// 校验串码类型
switch item.IMEIType {
case 1, 2, 3:
// 串码商品校验串码是否为空
if item.IMEIType != NoIMEICommodity && item.IMEI == "" {
return fmt.Errorf("[%s]是串码商品,其串码不能为空", item.CommodityName)
}
default:
return fmt.Errorf("商品[%s]串码类型[%d]错误", item.CommodityName, item.IMEIType)
}
// 校验非串码商品是否重复
if item.IMEIType == NoIMEICommodity {
_, ok := noIMEICommodityMap[item.CommodityId]
if !ok {
noIMEICommodityMap[item.CommodityId] = true
} else {
return fmt.Errorf("商品[%s]重复相同的非串码商品只能有1条数据", item.CommodityName)
}
}
if req.ChangeType == ReduceChangeOrder { // 库存减少
// 检查调出门店是否有对应商品,库存变动数量是否 > 商品库存数量
var stockCount int64
var err error
if item.IMEIType == NoIMEICommodity { // 非串码商品
err = orm.Eloquent.Table("erp_stock_commodity").
Where("erp_commodity_id = ? AND store_id = ? AND state = 1", item.CommodityId, req.StoreId).
Count(&stockCount).Error
} else { // 串码商品
err = orm.Eloquent.Table("erp_stock_commodity").
Where("erp_commodity_id = ? AND store_id = ? AND state = 1 AND imei = ?", item.CommodityId,
req.StoreId, item.IMEI).Count(&stockCount).Error
}
if err != nil {
return errors.New("查询商品库存失败," + err.Error())
}
if stockCount == 0 {
return fmt.Errorf("商品[%s]库存数量为0", item.CommodityName)
}
if stockCount < int64(item.Count) {
return fmt.Errorf("商品[%s]库存数量[%d]少于库存减少数量[%d]", item.CommodityName, stockCount, item.Count)
}
}
}
return nil
}
// AddInventoryChange 新增库存变动订单
func AddInventoryChange(req *InventoryChangeAddReq, sysUser *SysUser) (*ErpInventoryChangeOrder, error) {
// 检查库存变动信息
if err := checkChangeInventoryParam(req, false); err != nil {
return nil, err
}
var err error
nowTime := time.Now()
// 计算库存变动的总数量,总金额
var nTotalCount uint32
var nTotalAmount float64
for i, _ := range req.Commodities {
nTotalCount += req.Commodities[i].Count // 数量
nTotalAmount += req.Commodities[i].Amount // 金额
}
// 组合库存变动订单数据
inventoryChangeOrder := &ErpInventoryChangeOrder{
SerialNumber: newChangeInventorySn(req.ChangeType),
ChangeType: req.ChangeType,
StoreId: req.StoreId,
StoreName: req.StoreName,
HandlerId: req.HandlerId,
HandlerName: req.HandlerName,
MakerTime: &nowTime,
MakerId: uint32(sysUser.UserId),
MakerName: sysUser.NickName,
State: ErpInventoryChangeOrderUnAudit,
TotalCount: nTotalCount,
TotalAmount: nTotalAmount,
}
// 创建库存变动订单
begin := orm.Eloquent.Begin()
err = begin.Create(inventoryChangeOrder).Error
if err != nil {
begin.Rollback()
logger.Error("create change order err:", logger.Field("err", err))
return nil, err
}
// 创建库存变动商品信息添加库存变动订单id
for i, _ := range req.Commodities {
req.Commodities[i].ChangeOrderId = inventoryChangeOrder.ID
err = begin.Create(&req.Commodities[i]).Error
if err != nil {
begin.Rollback()
logger.Error("create change commodity err:", logger.Field("err", err))
return nil, err
}
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit change commodity err:", logger.Field("err", err))
return nil, err
}
return inventoryChangeOrder, nil
}
// EditChangeInventory 编辑库存变动
func EditChangeInventory(req *InventoryChangeEditReq) (*ErpInventoryChangeOrder, error) {
// 查询订单信息
var inventoryChangeOrder ErpInventoryChangeOrder
err := orm.Eloquent.Table("erp_inventory_change_order").Where("serial_number = ?", req.SerialNumber).
Find(&inventoryChangeOrder).Error
if err != nil {
logger.Error("allot order err:", logger.Field("err", err))
return nil, err
}
// 未找到订单
if inventoryChangeOrder.ID == 0 {
return nil, fmt.Errorf("未找到该订单,请检查单据编号[%s]", req.SerialNumber)
}
if inventoryChangeOrder.State != ErpInventoryChangeOrderUnAudit { // 只有待审核的订单才能编辑
return nil, errors.New("订单不是待审核状态")
}
// 检查库存调拨信息
if err = checkChangeInventoryParam(&req.InventoryChangeAddReq, true); err != nil {
return nil, err
}
// 计算库存调拨的总数量
var nTotalCount uint32
var nTotalAmount float64
for i, _ := range req.Commodities {
nTotalCount += req.Commodities[i].Count // 数量
nTotalAmount += req.Commodities[i].Amount // 金额
}
begin := orm.Eloquent.Begin()
// 1-更新库存调拨信息
inventoryChangeOrder.ChangeType = req.ChangeType
inventoryChangeOrder.StoreId = req.StoreId
inventoryChangeOrder.StoreName = req.StoreName
inventoryChangeOrder.HandlerId = req.HandlerId
inventoryChangeOrder.HandlerName = req.HandlerName
inventoryChangeOrder.TotalCount = nTotalCount
inventoryChangeOrder.TotalAmount = nTotalAmount
err = begin.Model(&ErpInventoryChangeOrder{}).Where("id = ?", inventoryChangeOrder.ID).
Updates(inventoryChangeOrder).Error
if err != nil {
begin.Rollback()
logger.Error("update change order err:", logger.Field("err", err))
return nil, err
}
// 2-更新库存调拨商品表
err = updateChangeCommodityData(begin, inventoryChangeOrder.ID, req)
if err != nil {
begin.Rollback()
logger.Error("update erp_inventory_change_commodity err:", logger.Field("err", err))
return nil, err
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit err:", logger.Field("err", err))
return nil, err
}
return &inventoryChangeOrder, nil
}
// updateChangeCommodityData 更新库存变动商品信息
func updateChangeCommodityData(gdb *gorm.DB, orderId uint32, req *InventoryChangeEditReq) error {
// 查询现有的零售订单信息
var commodities []ErpInventoryChangeCommodity
err := orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?", orderId).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
return err
}
var newCommodities []ErpInventoryChangeCommodity
var deletedCommodities []ErpInventoryChangeCommodity
var matchingCommodities []ErpInventoryChangeCommodity
// 找到新增的商品
for i, reqCommodity := range req.Commodities {
// 订单商品表信息添加零售订单id
req.Commodities[i].ChangeOrderId = orderId
var found bool
for _, dbCommodity := range commodities {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.ID == dbCommodity.ID {
found = true
break
}
}
if !found {
newCommodities = append(newCommodities, reqCommodity)
}
}
// 找到删除的商品
for _, dbCommodity := range commodities {
var found bool
for _, reqCommodity := range req.Commodities {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.ID == dbCommodity.ID {
found = true
// 找到匹配的商品,加入匹配列表
matchingCommodities = append(matchingCommodities, reqCommodity)
break
}
}
if !found {
deletedCommodities = append(deletedCommodities, dbCommodity)
}
}
// 2-更新商品订单信息-更新
for _, commodity := range matchingCommodities {
if err := gdb.Model(&ErpInventoryChangeCommodity{}).Where("id = ?", commodity.ID).Updates(commodity).Error; err != nil {
logger.Error("更新商品订单信息-更新 error")
return errors.New("操作失败:" + err.Error())
}
}
// 2-更新商品订单信息-新增
if len(newCommodities) != 0 {
err = gdb.Create(&newCommodities).Error
if err != nil {
logger.Error("更新商品订单信息-新增 error")
return errors.New("操作失败:" + err.Error())
}
}
//2-更新商品订单信息-删除
if len(deletedCommodities) != 0 {
err = gdb.Delete(&deletedCommodities).Error
if err != nil {
logger.Error("更新商品订单信息-删除 error")
return errors.New("操作失败:" + err.Error())
}
}
return nil
}
// List 查询采购订单列表
func (m *InventoryChangeListReq) List() (*InventoryChangeListResp, error) {
resp := &InventoryChangeListResp{
PageIndex: m.PageIndex,
PageSize: m.PageSize,
}
page := m.PageIndex - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
qs := orm.Eloquent.Table("erp_inventory_change_order")
if m.SerialNumber != "" {
qs = qs.Where("serial_number=?", m.SerialNumber)
} else {
if m.ChangeType != "" {
qs = qs.Where("change_type=?", m.ChangeType)
}
if m.StoreId != 0 {
qs = qs.Where("store_id=?", m.StoreId)
}
if m.HandlerId != 0 {
qs = qs.Where("handler_id=?", m.HandlerId)
}
if m.State != 0 {
qs = qs.Where("state=?", m.State)
}
if m.AuditTimeStart != "" {
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
if err != nil {
logger.Errorf("ChangeInventoryList err:", err)
return nil, err
}
qs = qs.Where("audit_time > ?", parse)
}
if m.AuditTimeEnd != "" {
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
if err != nil {
logger.Errorf("ChangeInventoryList err:", err)
return nil, err
}
qs = qs.Where("audit_time < ?", parse)
}
}
var count int64
err := qs.Count(&count).Error
if err != nil {
logger.Error("count err:", logger.Field("err", err))
return resp, err
}
resp.Total = int(count)
var orders []ErpInventoryChangeOrder
err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error
if err != nil && err != RecordNotFound {
logger.Error("change list err:", logger.Field("err", err))
return resp, err
}
// 校验时间如果为01-01-01 08:05则赋值为空
for i, v := range orders {
if v.MakerTime != nil && v.MakerTime.IsZero() {
orders[i].MakerTime = nil
}
if v.AuditTime != nil && v.AuditTime.IsZero() {
orders[i].AuditTime = nil
}
}
resp.List = orders
return resp, nil
}
// AuditChangeInventory 审核库存变动入库 state1-审核2-取消审核
func AuditChangeInventory(req *InventoryChangeAuditReq, sysUser *SysUser) error {
// 查询订单信息
var inventoryChangeOrder ErpInventoryChangeOrder
err := orm.Eloquent.Table("erp_inventory_change_order").Where("serial_number = ?", req.SerialNumber).
Find(&inventoryChangeOrder).Error
if err != nil {
logger.Error("order err:", logger.Field("err", err))
return err
}
if inventoryChangeOrder.ID == 0 {
return errors.New("未查询到订单信息")
}
begin := orm.Eloquent.Begin()
// 判断入参state1-审核2-取消审核
orderState := 0
switch req.State {
case 1: // 1-审核:待审核状态可以审核
if inventoryChangeOrder.State == ErpInventoryChangeOrderFinished { // 订单已完成
return errors.New("订单已审核,无需再次审核")
}
orderState = ErpInventoryChangeOrderFinished
case 2: // 2-取消审核
if inventoryChangeOrder.State == ErpInventoryChangeOrderUnAudit { // 订单未审核
return errors.New("订单是未审核状态,无需取消审核")
}
orderState = ErpInventoryChangeOrderUnAudit
default:
logger.Error("order err, req.State is:", logger.Field("req.State", req.State))
return errors.New("参数有误")
}
// 更新商品的库存状态
err = changeInventoryUpdateStock(begin, inventoryChangeOrder, req.State)
if err != nil {
begin.Rollback()
logger.Error("changeInventoryUpdateStock err:", logger.Field("err", err))
return err
}
// 更新库存调拨订单表
err = begin.Table("erp_inventory_change_order").Where("id = ?", inventoryChangeOrder.ID).
Updates(map[string]interface{}{
"state": orderState,
"auditor_id": sysUser.UserId,
"audit_time": time.Now(),
"auditor_name": sysUser.NickName,
}).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_inventory_change_order err:", logger.Field("err", err))
return err
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Errorf("commit err:", err)
return err
}
return nil
}
// changeInventoryUpdateStock 库存变动更新库存信息
func changeInventoryUpdateStock(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder, nState int) error {
if nState != 1 && nState != 2 {
return errors.New("无效的状态")
}
if changeOrder.ChangeType != AddChangeOrder && changeOrder.ChangeType != ReduceChangeOrder {
return errors.New("无效的库存变动类型")
}
// 根据状态和库存变动类型执行不同的逻辑
switch {
case nState == 1 && changeOrder.ChangeType == AddChangeOrder:
return handleInventoryAdd(gdb, changeOrder)
case nState == 1 && changeOrder.ChangeType == ReduceChangeOrder:
return handleInventoryReduce(gdb, changeOrder)
case nState == 2 && changeOrder.ChangeType == AddChangeOrder:
return handleCancelInventoryAdd(gdb, changeOrder)
case nState == 2 && changeOrder.ChangeType == ReduceChangeOrder:
return handleCancelInventoryReduce(gdb, changeOrder)
default:
return nil
}
}
// 库存增加逻辑
func handleInventoryAdd(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) error {
// 查询库存变动商品信息
var commodities []ErpInventoryChangeCommodity
err := orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?",
changeOrder.ID).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
return err
}
// 遍历采购入库商品信息
var stockList []ErpStockCommodity
for _, v := range commodities {
commodityInfo, err := GetCommodity(v.CommodityId)
if err != nil {
logger.Errorf("GetCommodity err:", err)
return err
}
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND "+
"erp_commodity_id=%d", changeOrder.StoreId, v.CommodityId))
if err != nil {
logger.Errorf("exist err:", err)
return err
}
if exist {
err = gdb.Exec(fmt.Sprintf(
"UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d",
v.Count, changeOrder.StoreId, v.CommodityId)).Error
if err != nil {
logger.Errorf("update stock err:", err)
return err
}
} else {
stock := &ErpStock{
StoreId: changeOrder.StoreId,
StoreName: changeOrder.StoreName,
ErpCommodityId: v.CommodityId,
ErpCommodityName: v.CommodityName,
ErpCategoryId: commodityInfo.ErpCategoryId,
ErpCategoryName: commodityInfo.ErpCategoryName,
CommoditySerialNumber: commodityInfo.SerialNumber,
IMEIType: v.IMEIType,
RetailPrice: commodityInfo.RetailPrice,
MinRetailPrice: commodityInfo.MinRetailPrice,
Count: v.Count,
DispatchCount: 0,
}
err = gdb.Create(stock).Error
if err != nil {
logger.Errorf("create stock err:", err)
return err
}
}
for i := 0; i < int(v.Count); i++ {
nowTime := time.Now()
stockCommodity := ErpStockCommodity{
StoreId: changeOrder.StoreId,
StoreName: changeOrder.StoreName,
ErpCommodityId: v.CommodityId,
ErpCommodityName: v.CommodityName,
CommoditySerialNumber: commodityInfo.SerialNumber,
ErpCategoryId: commodityInfo.ErpCategoryId,
ErpCategoryName: commodityInfo.ErpCategoryName,
ErpSupplierId: v.SupplierId,
ErpSupplierName: v.SupplierName,
StaffCostPrice: tools.RoundToTwoDecimalPlaces(v.EmployeePrice - v.Price),
WholesalePrice: tools.RoundToTwoDecimalPlaces(v.Price),
State: InStock,
StorageType: CheckInventory, // 盘点入库
FirstStockTime: nowTime,
StockTime: nowTime,
Count: 1,
ErpBarcode: commodityInfo.ErpBarcode, // 240106新增商品条码
IMEIType: v.IMEIType,
IMEI: v.IMEI,
Remark: "",
MemberDiscount: commodityInfo.MemberDiscount,
MinRetailPrice: commodityInfo.MinRetailPrice,
RetailPrice: commodityInfo.RetailPrice,
OriginalSn: changeOrder.SerialNumber,
//StockSn: v.SerialNumber,
}
stockList = append(stockList, stockCommodity)
}
}
err = gdb.Debug().Create(&stockList).Error
if err != nil {
logger.Errorf("create stock commodity err:", err)
return err
}
return nil
}
// 库存减少逻辑
func handleInventoryReduce(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) error {
// 查询库存变动商品信息
var commodities []ErpInventoryChangeCommodity
err := orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?",
changeOrder.ID).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
return err
}
if len(commodities) == 0 {
return errors.New("未查询到商品信息")
}
usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id
// 更新库存数量
for i, _ := range commodities {
if commodities[i].IMEIType == 2 { // 串码商品
if commodities[i].IMEI == "" {
return errors.New("串码为空")
}
// 判断该串码商品是否已经销售
var stockCommodityInfo ErpStockCommodity
err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?",
commodities[i].IMEI).Find(&stockCommodityInfo).Error
if err != nil {
logger.Error("handleInventoryReduce query commodities err:", logger.Field("err", err))
return err
}
if stockCommodityInfo.State == SoldOut {
return fmt.Errorf("商品[%s]已经销售", stockCommodityInfo.ErpCommodityName)
}
//else if stockCommodityInfo.State == OnSale {
// return fmt.Errorf("商品[%s]在销售锁定中", stockCommodityInfo.ErpCommodityName)
//}
// 更新库存商品状态为:盘点出库
err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI).
Update("state", CheckOut).Error
if err != nil {
logger.Error("handleInventoryReduce update erp_stock_commodity err:",
logger.Field("err", err))
return err
}
// 更新库存数量:库存数量-1
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error
if err != nil {
logger.Error("handleInventoryReduce update erp_stock err:", logger.Field("err", err))
return err
}
} else {
// 查询商品实际库存详情处剩余有效数,不包含已出库的数量
var nCount int64
err = orm.Eloquent.Table("erp_stock_commodity").
Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodities[i].CommodityId,
changeOrder.StoreId).Count(&nCount).Error
if err != nil {
return err
}
// 如果库存数量不够则报错
if uint32(nCount) < commodities[i].Count {
return fmt.Errorf("商品[%s]库存不足", commodities[i].CommodityName)
}
var stockCommodity []ErpStockCommodity
// 非串码商品可能不止1个更新库存商品状态
for j := 0; j < int(commodities[i].Count); j++ {
// 通过门店id商品id查找状态为1-在库的非串码商品
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and "+
"store_id = ? and state = ? and imei_type = ?", commodities[i].CommodityId, changeOrder.StoreId,
InStock, NoIMEICommodity).Order("first_stock_time DESC").Find(&stockCommodity).Error
if err != nil {
logger.Error("get commodities err:", logger.Field("err", err))
return err
}
if stockCommodity == nil {
return errors.New("find no stock commodity")
}
// 找一个可用的库存商品表主键ID
rightId, err := findRightErpStockCommodityId(usedStockCommodityIdList,
commodities[i].CommodityId, stockCommodity)
if err != nil {
return err
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId).
Update("state", CheckOut).Error // 状态更新为:盘点出库
if err != nil {
logger.Error("handleInventoryReduce update erp_stock_commodity err:",
logger.Field("err", err))
return err
}
usedStockCommodityIdList[commodities[i].ID] = append(usedStockCommodityIdList[commodities[i].ID], rightId)
}
// 更新库存数量:库存数量-count
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", commodities[i].Count)}).Error
if err != nil {
logger.Error("handleInventoryReduce update erp_stock err:", logger.Field("err", err))
return err
}
}
}
return nil
}
// 取消审核时库存增加逻辑
func handleCancelInventoryAdd(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) error {
// 查询库存变动商品信息
var commodities []ErpInventoryChangeCommodity
err := orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?",
changeOrder.ID).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
return err
}
if len(commodities) == 0 {
return errors.New("未查询到商品信息")
}
// 更新库存数量
for i, _ := range commodities {
if commodities[i].IMEIType == 2 { // 串码商品
if commodities[i].IMEI == "" {
return errors.New("串码为空")
}
// 判断该串码商品是否已经销售
var stockCommodityInfo ErpStockCommodity
err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?",
commodities[i].IMEI).Find(&stockCommodityInfo).Error
if err != nil {
logger.Error("handleCancelInventoryAdd query commodities err:", logger.Field("err", err))
return err
}
if stockCommodityInfo.State == SoldOut {
return fmt.Errorf("商品[%s]已经销售", stockCommodityInfo.ErpCommodityName)
}
//else if stockCommodityInfo.State == OnSale {
// return fmt.Errorf("商品[%s]在销售锁定中", stockCommodityInfo.ErpCommodityName)
//}
// 更新库存数量:库存数量-1
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error
if err != nil {
logger.Error("handleCancelInventoryAdd commodities err:", logger.Field("err", err))
return err
}
} else {
// 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量
nCount, err := GetCommodityStockByPurchaseId(changeOrder.SerialNumber,
commodities[i].CommodityId)
if err != nil {
logger.Error("handleCancelInventoryAdd GetCommodityStockByPurchaseId err:",
logger.Field("err", err))
return err
}
// 如果库存数量不够则报错
if nCount < commodities[i].Count {
return fmt.Errorf("商品[%s]库存数量不足", commodities[i].CommodityName)
}
// 更新库存数量:库存数量-count
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", commodities[i].Count)}).Error
if err != nil {
logger.Error("handleCancelInventoryAdd commodities err:", logger.Field("err", err))
return err
}
}
}
// 删除库存商品表对应的记录
err = gdb.Where("original_sn = ? and state = ?", changeOrder.SerialNumber, InStock).Delete(&ErpStockCommodity{}).Error
if err != nil {
logger.Error("delete erp_stock_commodity err:", logger.Field("err", err))
return err
}
return nil
}
// 取消审核时库存减少逻辑
func handleCancelInventoryReduce(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) error {
// 查询库存变动商品信息
var commodities []ErpInventoryChangeCommodity
err := orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?",
changeOrder.ID).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
return err
}
if len(commodities) == 0 {
return errors.New("未查询到商品信息")
}
usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id
// 更新库存数量
for i, _ := range commodities {
if commodities[i].IMEIType == 2 { // 串码商品
if commodities[i].IMEI == "" {
return errors.New("串码为空")
}
// 判断该串码商品是否已经销售
var stockCommodityInfo ErpStockCommodity
err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?",
commodities[i].IMEI).Find(&stockCommodityInfo).Error
if err != nil {
logger.Error("handleCancelInventoryReduce query commodities err:", logger.Field("err", err))
return err
}
if stockCommodityInfo.State == SoldOut {
return fmt.Errorf("商品[%s]已经销售", stockCommodityInfo.ErpCommodityName)
}
//else if stockCommodityInfo.State == OnSale {
// return fmt.Errorf("商品[%s]在销售锁定中", stockCommodityInfo.ErpCommodityName)
//}
// 更新库存商品状态:在库
err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI).
Update("state", InStock).Error
if err != nil {
logger.Error("handleCancelInventoryReduce update erp_stock_commodity err:",
logger.Field("err", err))
return err
}
// 更新库存数量:库存数量+1
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count + ?", 1)}).Error
if err != nil {
logger.Error("handleCancelInventoryReduce update erp_stock err:", logger.Field("err", err))
return err
}
} else {
var stockCommodity []ErpStockCommodity
// 非串码商品可能不止1个更新库存商品状态
for j := 0; j < int(commodities[i].Count); j++ {
// 通过门店id商品id查找状态为盘点出库的非串码商品
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and "+
"store_id = ? and state = ? and imei_type = ?", commodities[i].CommodityId, changeOrder.StoreId,
CheckOut, NoIMEICommodity).Order("first_stock_time DESC").Find(&stockCommodity).Error
if err != nil {
logger.Error("get commodities err:", logger.Field("err", err))
return err
}
if stockCommodity == nil {
return errors.New("find no stock commodity")
}
// 找一个可用的库存商品表主键ID
rightId, err := findRightErpStockCommodityId(usedStockCommodityIdList,
commodities[i].CommodityId, stockCommodity)
if err != nil {
return err
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId).
Update("state", InStock).Error // 状态更新为:在库
if err != nil {
logger.Error("handleCancelInventoryReduce update erp_stock_commodity err:",
logger.Field("err", err))
return err
}
usedStockCommodityIdList[commodities[i].ID] = append(usedStockCommodityIdList[commodities[i].ID], rightId)
}
// 更新库存数量:库存数量+count
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count + ?", commodities[i].Count)}).Error
if err != nil {
logger.Error("handleCancelInventoryReduce update erp_stock err:", logger.Field("err", err))
return err
}
}
}
return nil
}