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 // 如果是非串码,且数量大于1,则进行拆分 if req.Commodities[i].IMEIType == 1 && req.Commodities[i].Count > 1 { nCount := req.Commodities[i].Count for j := 0; j < int(nCount); j++ { req.Commodities[i].ID = 0 req.Commodities[i].Count = 1 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 } } } else { // 普通串码商品则只有1条数据 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 } // 删除所有的商品信息 if len(commodities) != 0 { err = gdb.Delete(&commodities).Error if err != nil { logger.Error("更新商品订单信息-删除 error") return errors.New("操作失败:" + err.Error()) } } // 新建所有的商品信息 for i, _ := range req.Commodities { req.Commodities[i].ChangeOrderId = orderId // 如果是非串码,且数量大于1,则进行拆分 if req.Commodities[i].IMEIType == 1 && req.Commodities[i].Count > 1 { nCount := req.Commodities[i].Count for j := 0; j < int(nCount); j++ { req.Commodities[i].ID = 0 req.Commodities[i].Count = 1 err = gdb.Create(&req.Commodities[i]).Error if err != nil { logger.Error("create allot commodity err:", logger.Field("err", err)) return err } } } else { // 普通串码商品则只有1条数据 err = gdb.Create(&req.Commodities[i]).Error if err != nil { logger.Error("create allot commodity err:", logger.Field("err", err)) return err } } } 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 审核库存变动入库 state:1-审核,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() // 判断入参state:1-审核,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 } if len(commodities) == 0 { return errors.New("未查询到商品信息") } // 遍历库存变动商品信息,将商品id相同的非串码商品进行合并,数量累加即可 trimCommodities := MergeChangeCommodities(commodities) // 遍历采购入库商品信息 var stockList []ErpStockCommodity for _, v := range trimCommodities { 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("未查询到商品信息") } // 遍历库存变动商品信息,将商品id相同的非串码商品进行合并,数量累加即可 trimCommodities := MergeChangeCommodities(commodities) usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id // 更新库存数量 for i, _ := range trimCommodities { if trimCommodities[i].IMEIType == 2 { // 串码商品 if trimCommodities[i].IMEI == "" { return errors.New("串码为空") } // 判断该串码商品是否已经销售 var stockCommodityInfo ErpStockCommodity err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", trimCommodities[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) 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 = ?", trimCommodities[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, trimCommodities[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", trimCommodities[i].CommodityId, changeOrder.StoreId).Count(&nCount).Error if err != nil { return err } // 如果库存数量不够则报错 if uint32(nCount) < trimCommodities[i].Count { return fmt.Errorf("商品[%s]库存不足", trimCommodities[i].CommodityName) } var stockCommodity []ErpStockCommodity // 非串码商品可能不止1个,更新库存商品状态 for j := 0; j < int(trimCommodities[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 = ?", trimCommodities[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, trimCommodities[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[trimCommodities[i].ID] = append(usedStockCommodityIdList[trimCommodities[i].ID], rightId) } // 更新库存数量:库存数量-count err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", changeOrder.StoreId, trimCommodities[i].CommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count - ?", trimCommodities[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("未查询到商品信息") } // 遍历库存变动商品信息,将商品id相同的非串码商品进行合并,数量累加即可 trimCommodities := MergeChangeCommodities(commodities) // 更新库存数量 for i, _ := range trimCommodities { if trimCommodities[i].IMEIType == 2 { // 串码商品 if trimCommodities[i].IMEI == "" { return errors.New("串码为空") } // 判断该串码商品是否已经销售 var stockCommodityInfo ErpStockCommodity err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", trimCommodities[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) 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, trimCommodities[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, trimCommodities[i].CommodityId) if err != nil { logger.Error("handleCancelInventoryAdd GetCommodityStockByPurchaseId err:", logger.Field("err", err)) return err } // 如果库存数量不够则报错 if nCount < trimCommodities[i].Count { return fmt.Errorf("商品[%s]库存数量不足", trimCommodities[i].CommodityName) } // 更新库存数量:库存数量-count err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", changeOrder.StoreId, trimCommodities[i].CommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count - ?", trimCommodities[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("未查询到商品信息") } // 遍历库存变动商品信息,将商品id相同的非串码商品进行合并,数量累加即可 trimCommodities := MergeChangeCommodities(commodities) usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id // 更新库存数量 for i, _ := range trimCommodities { if trimCommodities[i].IMEIType == 2 { // 串码商品 if trimCommodities[i].IMEI == "" { return errors.New("串码为空") } // 判断该串码商品是否已经销售 var stockCommodityInfo ErpStockCommodity err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", trimCommodities[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) 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 = ?", trimCommodities[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, trimCommodities[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(trimCommodities[i].Count); j++ { // 通过门店id,商品id,查找状态为盘点出库的非串码商品 err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and "+ "store_id = ? and state = ? and imei_type = ?", trimCommodities[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, trimCommodities[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[trimCommodities[i].ID] = append(usedStockCommodityIdList[trimCommodities[i].ID], rightId) } // 更新库存数量:库存数量+count err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", changeOrder.StoreId, trimCommodities[i].CommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count + ?", trimCommodities[i].Count)}).Error if err != nil { logger.Error("handleCancelInventoryReduce update erp_stock err:", logger.Field("err", err)) return err } } } return nil }