package models

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	orm "go-admin/common/global"
	"go-admin/logger"
	"go-admin/tools"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"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("订单是未审核状态，无需取消审核")
		}
		if IsMonthEndClosed(*inventoryChangeOrder.AuditTime) {
			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.Clauses(clause.OnConflict{
				Columns:   []clause.Column{{Name: "store_id"}, {Name: "erp_commodity_id"}},                      // 唯一约束字段
				DoUpdates: clause.Assignments(map[string]interface{}{"count": gorm.Expr("count + ?", v.Count)}), // 冲突时累加 count
			}).Create(stock).Error

			if err != nil {
				logger.Errorf("create or update 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
}
