1058 lines
37 KiB
Go
1058 lines
37 KiB
Go
package models
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"github.com/gin-gonic/gin"
|
||
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)
|
||
}
|
||
} else { // 库存增加
|
||
// 如果该商品是串码商品,判断其串码是否会重复
|
||
if item.IMEI != "" {
|
||
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock_commodity WHERE FIND_IN_SET('%s', imei) > 0", item.IMEI))
|
||
if err != nil {
|
||
logger.Error("exist sn err")
|
||
}
|
||
if exist {
|
||
return fmt.Errorf("串码有重复项请修改[%s]", item.IMEI)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
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).
|
||
Omit("created_at").Save(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(c *gin.Context) (*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 !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
|
||
sysUser, err := GetSysUserByCtx(c)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 返回sysUser未过期的门店id列表
|
||
storeList := GetValidStoreIDs(sysUser.StoreData)
|
||
if m.StoreId != 0 {
|
||
if !Contains(storeList, m.StoreId) {
|
||
return nil, errors.New("您没有该门店权限")
|
||
}
|
||
} else {
|
||
if len(storeList) > 0 {
|
||
if len(storeList) == 1 {
|
||
qs = qs.Where("store_id = ?", storeList[0])
|
||
} else {
|
||
qs = qs.Where("store_id IN (?)", storeList)
|
||
}
|
||
} else {
|
||
return nil, errors.New("用户未绑定门店")
|
||
}
|
||
}
|
||
}
|
||
|
||
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, c *gin.Context) 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
|
||
}
|
||
|
||
sysUser, err := GetSysUserByCtx(c)
|
||
if err != nil {
|
||
logger.Error("sys user err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
// 校验是否有入参门店权限
|
||
err = AuthUserStore(c, inventoryChangeOrder.StoreId)
|
||
if err != nil {
|
||
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 || trimCommodities[i].IMEIType == 3 { // 串码商品
|
||
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).
|
||
Updates(map[string]interface{}{
|
||
"state": CheckOut,
|
||
"updated_at": time.Now(),
|
||
}).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).
|
||
Updates(map[string]interface{}{
|
||
"state": CheckOut,
|
||
"updated_at": time.Now(),
|
||
}).Error // 状态更新为:盘点出库
|
||
if err != nil {
|
||
logger.Error("handleInventoryReduce update erp_stock_commodity err:",
|
||
logger.Field("err", err))
|
||
return err
|
||
}
|
||
usedStockCommodityIdList[trimCommodities[i].CommodityId] = append(usedStockCommodityIdList[trimCommodities[i].CommodityId], 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 || trimCommodities[i].IMEIType == 3 { // 串码商品
|
||
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 || trimCommodities[i].IMEIType == 3 { // 串码商品
|
||
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).
|
||
Updates(map[string]interface{}{"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).
|
||
Updates(map[string]interface{}{"state": InStock}).Error // 状态更新为:在库
|
||
if err != nil {
|
||
logger.Error("handleCancelInventoryReduce update erp_stock_commodity err:",
|
||
logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
usedStockCommodityIdList[trimCommodities[i].CommodityId] = append(usedStockCommodityIdList[trimCommodities[i].CommodityId], 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
|
||
}
|