controllers/operation.go
@@ -3,7 +3,6 @@
import (
   "context"
   "errors"
   "fmt"
   "github.com/gin-gonic/gin"
   uuid "github.com/satori/go.uuid"
   "github.com/shopspring/decimal"
@@ -48,6 +47,7 @@
func (slf OperationController) Add(c *gin.Context) {
   var reqParams request.AddOperation
   var params models.Operation
   if err := c.BindJSON(&reqParams); err != nil {
      util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误")
      return
@@ -91,27 +91,26 @@
      util.ResponseFormat(c, code.RequestParamError, "单号已存在")
      return
   }
   var productIds []string
   for _, v := range params.Details {
      productIds = append(productIds, v.ProductId)
   }
   products, err := models.NewMaterialSearch().SetIDs(productIds).FindNotTotal()
   if err != nil {
      logx.Errorf("MonthStats get products err:%v", err)
      return
   }
   productMap := models.MaterialMap(products)
   for key, value := range productMap {
      for i := 0; i < len(params.Details); i++ {
         if key == params.Details[i].ProductId {
            params.Details[i].Note = value.Note
            break
   err = models.WithTransaction(func(db *gorm.DB) error {
      if err := models.NewOperationSearch().Create(&params); err != nil {
         return err
      }
      od := params.Details
      for _, v := range od {
         //material, err := models.NewMaterialSearch().SetID(v.ProductId).First()
         //if err != nil {return err}
         material := new(models.Material)
         material.ID = v.ProductId
         material.Cost = v.Cost
         material.SalePrice = v.SalePrice
         if err := models.NewMaterialSearch().SetOrm(db).Update(material); err != nil {
            return err
         }
      }
   }
      return nil
   })
   if err := models.NewOperationSearch().Create(&params); err != nil {
   if err != nil {
      logx.Errorf("Operation create err: %v", err)
      util.ResponseFormat(c, code.SaveFail, "添加失败:"+err.Error())
      return
@@ -176,15 +175,14 @@
            return errors.New("请选择源位置")
         }
      }
   }
   return nil
}
func (slf OperationController) CheckParams(params models.Operation) error {
   if params.SourceNumber == "" {
   /*if params.SourceNumber == "" {
      return errors.New("请填入源单号")
   }
   }*/
   if params.Number == "" {
      return errors.New("请填入单号")
@@ -271,10 +269,29 @@
   if int(params.Status) != 0 {
      search.SetStatus(params.Status)
   }
   materials, err := models.NewMaterialSearch().FindNotTotal()
   if err != nil {
      util.ResponseFormat(c, code.RequestError, "查找失败:"+err.Error())
      return
   }
   costMap := make(map[string]decimal.Decimal)
   salePriceMap := make(map[string]decimal.Decimal)
   for _, material := range materials {
      costMap[material.ID] = material.Cost
      salePriceMap[material.ID] = material.SalePrice
   }
   list, total, err := search.SetOperationTypeId(params.OperationTypeId).SetPreload(true).SetOrder("created_at desc").Find()
   if err != nil {
      util.ResponseFormat(c, code.RequestError, "查找失败:"+err.Error())
      return
   }
   for _, v := range list {
      for _, v1 := range v.Details {
         //v1.SalePrice = decimal.NewFromFloat(1.2345)
         //v1.Cost = decimal.NewFromFloat(9.678)
         v1.SalePrice = v1.Cost
         v1.Cost = v1.SalePrice
      }
   }
   util.ResponseFormatListWithPage(c, code.Success, list, int(total), params.Page, params.PageSize)
@@ -334,6 +351,18 @@
      }
      if err := models.NewOperationSearch().SetOrm(tx).SetID(params.Id).Save(&params); err != nil {
         return err
      }
      od := params.Details
      for _, v := range od {
         //material, err := models.NewMaterialSearch().SetID(v.ProductId).First()
         //if err != nil {return err}
         material := new(models.Material)
         material.ID = v.ProductId
         material.Cost = v.Cost
         material.SalePrice = v.SalePrice
         if err := models.NewMaterialSearch().SetOrm(tx).Update(material); err != nil {
            return err
         }
      }
      return nil
   }); err != nil {
@@ -438,231 +467,38 @@
      }
   }
   userInfo := middleware.GetUserInfo(c)
   err = models.WithTransaction(func(tx *gorm.DB) error {
      if err := models.NewOperationSearch().SetOrm(tx).SetID(id).Update(&models.Operation{
         Status:    constvar.OperationStatus_Finish,
         CheckedBy: userInfo.Username,
         CheckedAt: time.Now(),
         AuditDate: time.Now().Format("2006-01-02 15:04:05")}); err != nil {
         return err
      }
      if err := AddMoveHistory([]*models.Operation{operation}, tx); err != nil {
      if err := service.AddMoveHistory([]*models.Operation{operation}, tx); err != nil {
         return err
      }
      if operation.BaseOperationType == constvar.BaseOperationTypeIncoming {
         locationRoleList, err := models.NewLocationProductSearch().Find()
         if err != nil {
            return errors.New("获取上架规则信息失败")
         if err := service.FinishOperationInput(c, tx, operation, listDetails, mapLocAmount); err != nil {
            return err
         }
         var mapLocationRoleProduct, mapLocationRoleCategory map[string]*models.LocationProduct
         if len(locationRoleList) > 0 {
            mapLocationRoleProduct = make(map[string]*models.LocationProduct)
            mapLocationRoleCategory = make(map[string]*models.LocationProduct)
            for _, v := range locationRoleList {
               if v.RuleType == constvar.RuleType_Product {
                  mapLocationRoleProduct[strconv.Itoa(v.AreaId)+v.ProductId] = v
               }
               if v.RuleType == constvar.RuleType_ProductCategory {
                  mapLocationRoleCategory[strconv.Itoa(v.AreaId)+strconv.Itoa(v.ProductCategoryID)] = v
               }
            }
         }
         var details []*models.OperationDetails
         for k, v := range listDetails {
            listDetails[k].Product.Amount = listDetails[k].Product.Amount.Add(v.Amount)
            if err := tx.Save(&listDetails[k].Product).Error; err != nil {
               return err
            }
            if roleProduct, ok := mapLocationRoleProduct[strconv.Itoa(operation.LocationID)+v.ProductId]; ok {
               detail := &models.OperationDetails{
                  ProductId:      v.ProductId,
                  Amount:         v.Amount,
                  FromLocationID: roleProduct.AreaId,
                  ToLocationID:   roleProduct.LocationId,
               }
               details = append(details, detail)
               if locAmount, aok := mapLocAmount[strconv.Itoa(roleProduct.LocationId)+v.ProductId]; aok {
                  locAmount.Amount = locAmount.Amount.Add(v.Amount)
                  if res := models.NewLocationProductAmountSearch().Orm.Where("id=?", locAmount.ID).Save(locAmount); res.Error != nil {
                     return res.Error
                  }
               } else {
                  if err := models.NewLocationProductAmountSearch().Create(&models.LocationProductAmount{
                     LocationId:        roleProduct.LocationId,
                     ProductCategoryID: v.Product.CategoryId,
                     ProductId:         v.ProductId,
                     Amount:            v.Amount,
                     CreateDate:        time.Now().Format("2006-01-02 15:04:05"),
                  }); err != nil {
                     return err
                  }
               }
            } else {
               if roleCategory, cok := mapLocationRoleCategory[strconv.Itoa(operation.LocationID)+strconv.Itoa(v.Product.CategoryId)]; cok {
                  detail := &models.OperationDetails{
                     ProductId:      v.ProductId,
                     Amount:         v.Amount,
                     FromLocationID: roleCategory.AreaId,
                     ToLocationID:   roleCategory.LocationId,
                  }
                  details = append(details, detail)
                  if locAmount, aok := mapLocAmount[strconv.Itoa(roleCategory.LocationId)+v.ProductId]; aok {
                     locAmount.Amount = locAmount.Amount.Add(v.Amount)
                     if res := models.NewLocationProductAmountSearch().Orm.Where("id=?", locAmount.ID).Save(locAmount); res.Error != nil {
                        return res.Error
                     }
                  } else {
                     if err := models.NewLocationProductAmountSearch().Create(&models.LocationProductAmount{
                        LocationId:        roleCategory.LocationId,
                        ProductCategoryID: v.Product.CategoryId,
                        ProductId:         v.ProductId,
                        Amount:            v.Amount,
                        CreateDate:        time.Now().Format("2006-01-02 15:04:05"),
                     }); err != nil {
                        return err
                     }
                  }
               } else {
                  if locAmount, aok := mapLocAmount[strconv.Itoa(operation.LocationID)+v.ProductId]; aok {
                     locAmount.Amount = locAmount.Amount.Add(v.Amount)
                     if res := models.NewLocationProductAmountSearch().Orm.Where("id=?", locAmount.ID).Save(locAmount); res.Error != nil {
                        return res.Error
                     }
                  } else {
                     if err := models.NewLocationProductAmountSearch().Create(&models.LocationProductAmount{
                        LocationId:        operation.LocationID,
                        ProductCategoryID: v.Product.CategoryId,
                        ProductId:         v.ProductId,
                        Amount:            v.Amount,
                        CreateDate:        time.Now().Format("2006-01-02 15:04:05"),
                     }); err != nil {
                        return err
                     }
                  }
               }
            }
         }
         if len(details) > 0 {
            if err := tx.Create(&models.Operation{
               Number:            operation.Number,
               SourceNumber:      operation.SourceNumber,
               OperationTypeId:   0,
               OperationTypeName: operation.OperationTypeName,
               Status:            constvar.OperationStatus_Finish,
               OperationDate:     operation.OperationDate,
               ContacterID:       operation.ContacterID,
               ContacterName:     operation.ContacterName,
               CompanyID:         operation.CompanyID,
               CompanyName:       operation.CompanyName,
               Comment:           operation.Comment,
               BaseOperationType: constvar.BaseOperationTypeInternal,
               Details:           details,
               CheckedAt:         time.Now(),
               CheckedBy:         userInfo.Username,
            }).Error; err != nil {
               return err
            }
         }
      }
      if operation.BaseOperationType == constvar.BaseOperationTypeOutgoing || operation.BaseOperationType == constvar.BaseOperationTypeDisuse {
         for k, v := range listDetails {
            //todo 演示测试数据
            //data, err := os.ReadFile("conf/input.json")
            //if err != nil {
            //   return errors.New("文件读取失败")
            //}
            //m := make(map[string]interface{})
            //err = json.Unmarshal(data, &m)
            //if err != nil {
            //   return errors.New("格式转换失败")
            //}
            //if opa.OpaCheck(c, m, "operation") {
            //   if v.Product.Amount.LessThan(v.Amount) {
            //      return errors.New(fmt.Sprintf("产品:%v,库存:%v,出库:%v,数量不够,无法完成出库操作", v.Product.Name, v.Product.Amount.String(), v.Amount.String()))
            //   }
            //}
            //todo ================end===============================
            if v.Product.Amount.LessThan(v.Amount) {
               return errors.New(fmt.Sprintf("产品:%v,库存:%v,出库:%v,数量不够,无法完成出库操作", v.Product.Name, v.Product.Amount.String(), v.Amount.String()))
            }
            listDetails[k].Product.Amount = listDetails[k].Product.Amount.Sub(v.Amount)
            if err := tx.Save(&listDetails[k].Product).Error; err != nil {
               return err
            }
            if locAmount, aok := mapLocAmount[strconv.Itoa(v.FromLocationID)+v.ProductId]; aok {
               if locAmount.Amount.LessThan(v.Amount) {
                  return errors.New(fmt.Sprintf("产品:%v,库存:%v,出库:%v,数量不够,无法完成出库操作", v.Product.Name, locAmount.Amount.String(), v.Amount.String()))
               }
               locAmount.Amount = locAmount.Amount.Sub(v.Amount)
               if err := models.NewLocationProductAmountSearch().SetID(locAmount.Id).Update(locAmount); err != nil {
                  return err
               }
            } else {
               return errors.New("当前仓库没有该产品,请先入库")
            }
         if err := service.FinishOperationOutput(tx, listDetails, mapLocAmount); err != nil {
            return err
         }
      }
      if operation.BaseOperationType == constvar.BaseOperationTypeInternal {
         for _, v := range listDetails {
            if fromLocAmount, aok := mapLocAmount[strconv.Itoa(v.FromLocationID)+v.ProductId]; aok {
               if fromLocAmount.Amount.LessThan(v.Amount) {
                  return errors.New(fmt.Sprintf("产品:%v,库存:%v,出库:%v,数量不够,无法完成出库操作", v.Product.Name, fromLocAmount.Amount.String(), v.Amount.String()))
               }
               fromLocAmount.Amount = fromLocAmount.Amount.Sub(v.Amount)
               if err := models.NewLocationProductAmountSearch().SetID(fromLocAmount.Id).Update(fromLocAmount); err != nil {
                  return err
               }
            } else {
               return errors.New("当前仓库没有该产品,请先入库")
            }
            if toLocAmount, aok := mapLocAmount[strconv.Itoa(v.ToLocationID)+v.ProductId]; aok {
               toLocAmount.Amount = toLocAmount.Amount.Add(v.Amount)
               if err := models.NewLocationProductAmountSearch().SetID(toLocAmount.Id).Update(toLocAmount); err != nil {
                  return err
               }
            } else {
               if err := models.NewLocationProductAmountSearch().Create(&models.LocationProductAmount{
                  LocationId:        v.ToLocationID,
                  ProductCategoryID: v.Product.CategoryId,
                  ProductId:         v.ProductId,
                  Amount:            v.Amount,
                  CreateDate:        time.Now().Format("2006-01-02 15:04:05"),
               }); err != nil {
                  return err
               }
            }
         if err := service.FinishOperationInternal(tx, listDetails); err != nil {
            return err
         }
      }
      if operation.BaseOperationType == constvar.BaseOperationTypeAdjust {
         for _, v := range listDetails {
            if locAmount, aok := mapLocAmount[strconv.Itoa(v.ToLocationID)+v.ProductId]; aok {
               locAmount.Amount = v.Amount
               if res := models.NewLocationProductAmountSearch().Orm.Where("id=?", locAmount.ID).Save(locAmount); res.Error != nil {
                  return res.Error
               }
            } else {
               if err := models.NewLocationProductAmountSearch().Create(&models.LocationProductAmount{
                  LocationId:        v.ToLocationID,
                  ProductCategoryID: v.Product.CategoryId,
                  ProductId:         v.ProductId,
                  Amount:            v.Amount,
                  CreateDate:        time.Now().Format("2006-01-02 15:04:05"),
               }); err != nil {
                  return err
               }
            }
         if err := service.FinishOperationAdjust(tx, listDetails, mapLocAmount); err != nil {
            return err
         }
      }
      return nil
@@ -685,40 +521,6 @@
   }
   util.ResponseFormat(c, code.Success, "操作成功")
}
func AddMoveHistory(operationList []*models.Operation, db *gorm.DB) error {
   var histories []*models.MoveHistory
   operationMap := make(map[int]*models.Operation, len(operationList))
   for _, operation := range operationList {
      for _, v := range operation.Details {
         history := &models.MoveHistory{
            Number:            operation.Number,
            BaseOperationType: operation.BaseOperationType,
            OperationTypeId:   operation.OperationTypeId,
            OperationTypeName: operation.OperationTypeName,
            OperationId:       operation.Id,
            ProductId:         v.ProductId,
            ProductName:       v.Product.Name,
            Amount:            v.Amount,
            Unit:              v.Product.Unit,
            Weight:            operation.Weight,
            FromLocationId:    v.FromLocationID,
            FromLocation:      v.FromLocation.Name,
            ToLocationId:      v.ToLocationID,
            ToLocation:        v.ToLocation.Name,
         }
         histories = append(histories, history)
      }
      operationMap[operation.Id] = operation
   }
   if err := db.Model(&models.MoveHistory{}).Create(&histories).Error; err != nil {
      return err
   }
   for _, history := range histories {
      service.AddNewHistoryReportRecord(history, operationMap[history.OperationId])
   }
   return nil
}
//var (
@@ -1292,6 +1094,12 @@
   if params.Condition != "" {
      db = db.Where("wms_operation.number like ? or wms_operation.source_number like ? or from_location.`name` like ? or to_location.`name` like ? or material.`name` like ? ", "%"+params.Condition+"%", "%"+params.Condition+"%", "%"+params.Condition+"%", "%"+params.Condition+"%", "%"+params.Condition+"%")
   }
   if params.WarehouseId != 0 {
      db = db.Where("warehouse_id = ?", params.WarehouseId)
   }
   if params.LocationId != 0 {
      db = db.Where("location_id = ?", params.LocationId)
   }
   var (
      records = make([]*response.InventoryHistory, 0)
      total   int64