| | |
| | | "errors" |
| | | "fmt" |
| | | "github.com/gin-gonic/gin" |
| | | "github.com/mitchellh/mapstructure" |
| | | "github.com/shopspring/decimal" |
| | | "gorm.io/gorm" |
| | | "strconv" |
| | |
| | | |
| | | 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 |
| | | if err := models.NewLocationProductAmountSearch().SetOrm(tx).SetID(int(locAmount.ID)).Save(locAmount); err != nil { |
| | | return err |
| | | } |
| | | } else { |
| | | if err := models.NewLocationProductAmountSearch().Create(&models.LocationProductAmount{ |
| | | if err := models.NewLocationProductAmountSearch().SetOrm(tx).Create(&models.LocationProductAmount{ |
| | | LocationId: roleProduct.LocationId, |
| | | ProductCategoryID: v.Product.CategoryId, |
| | | ProductId: v.ProductId, |
| | |
| | | |
| | | 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 |
| | | if err := models.NewLocationProductAmountSearch().SetOrm(tx).SetID(int(locAmount.ID)).Save(locAmount); err != nil { |
| | | return err |
| | | } |
| | | } else { |
| | | if err := models.NewLocationProductAmountSearch().Create(&models.LocationProductAmount{ |
| | | if err := models.NewLocationProductAmountSearch().SetOrm(tx).Create(&models.LocationProductAmount{ |
| | | LocationId: roleCategory.LocationId, |
| | | ProductCategoryID: v.Product.CategoryId, |
| | | ProductId: v.ProductId, |
| | |
| | | } 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 |
| | | if err := models.NewLocationProductAmountSearch().SetOrm(tx).SetID(int(locAmount.ID)).Save(locAmount); err != nil { |
| | | return err |
| | | } |
| | | } else { |
| | | if err := models.NewLocationProductAmountSearch().Create(&models.LocationProductAmount{ |
| | | if err := models.NewLocationProductAmountSearch().SetOrm(tx).Create(&models.LocationProductAmount{ |
| | | LocationId: operation.LocationID, |
| | | ProductCategoryID: v.Product.CategoryId, |
| | | ProductId: v.ProductId, |
| | |
| | | } |
| | | |
| | | // FinishOperationOutput 完成出库或报废 |
| | | func FinishOperationOutput(tx *gorm.DB, listDetails []*models.OperationDetails, mapLocAmount map[string]*models.LocationProductAmount) (err error) { |
| | | func FinishOperationOutput(tx *gorm.DB, listDetails []*models.OperationDetails, mapLocAmount map[string]*models.LocationProductAmount, originOperation *models.Operation) (err error) { |
| | | var internalInputDetails []*models.OperationDetails //内部调拨产生的出库验证后,生成入库单 |
| | | for k, v := range listDetails { |
| | | 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())) |
| | |
| | | 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 { |
| | | if err := models.NewLocationProductAmountSearch().SetOrm(tx).SetID(locAmount.Id).Save(locAmount); err != nil { |
| | | return err |
| | | } |
| | | } else { |
| | | return errors.New("当前仓库没有该产品,请先入库") |
| | | } |
| | | if v.IsInternalOutput { |
| | | var inputDetail models.OperationDetails |
| | | mapstructure.Decode(v, &inputDetail) |
| | | inputDetail.Id = 0 |
| | | inputDetail.OperationID = 0 |
| | | internalInputDetails = append(internalInputDetails, &inputDetail) |
| | | } |
| | | } |
| | | if len(internalInputDetails) > 0 { |
| | | opTypeId, err := GetTargetOperationTypeIdByOperation(originOperation, constvar.BaseOperationTypeIncoming) |
| | | if err != nil { |
| | | return err |
| | | } |
| | | operation := &models.Operation{ |
| | | OperationTypeId: opTypeId, |
| | | Number: strconv.FormatInt(time.Now().Unix(), 10), |
| | | Status: constvar.OperationStatus_Ready, |
| | | OperationDate: time.Now().Format("2006-01-02 15:04:05"), |
| | | Comment: "库存调拨入库", |
| | | BaseOperationType: constvar.BaseOperationTypeIncoming, |
| | | Details: internalInputDetails, |
| | | LocationID: internalInputDetails[0].ToLocationID, |
| | | OperationTypeName: "库存调拨入库", |
| | | } |
| | | if err := models.NewOperationSearch().SetOrm(tx).Create(operation); err != nil { |
| | | return err |
| | | } |
| | | } |
| | | return nil |
| | | |
| | | } |
| | | |
| | | // FinishOperationInternal 完成内部调拨 |
| | | func FinishOperationInternal(tx *gorm.DB, listDetails []*models.OperationDetails, mapLocAmount map[string]*models.LocationProductAmount) (err error) { |
| | | // FinishOperationInternal 验证内部调拨生成出库单 |
| | | func FinishOperationInternal(tx *gorm.DB, listDetails []*models.OperationDetails, originOperation *models.Operation) (err error) { |
| | | var outputDetails []*models.OperationDetails |
| | | 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().SetOrm(tx).SetID(fromLocAmount.Id).Update(fromLocAmount); err != nil { |
| | | return err |
| | | } |
| | | } else { |
| | | return errors.New("当前仓库没有该产品,请先入库") |
| | | outputDetails = append(outputDetails, &models.OperationDetails{ |
| | | ProductId: v.ProductId, |
| | | Amount: v.Amount, |
| | | FromLocationID: v.FromLocationID, |
| | | ToLocationID: v.ToLocationID, |
| | | TotalGrossWeight: v.TotalGrossWeight, |
| | | TotalNetWeight: v.TotalNetWeight, |
| | | AuxiliaryAmount: v.AuxiliaryAmount, |
| | | AuxiliaryUnit: v.AuxiliaryUnit, |
| | | Remark: v.Remark, |
| | | IsInternalOutput: true, |
| | | Cost: v.Cost, |
| | | SalePrice: v.SalePrice, |
| | | }) |
| | | } |
| | | if len(outputDetails) > 0 { |
| | | opTypeId, err := GetTargetOperationTypeIdByOperation(originOperation, constvar.BaseOperationTypeOutgoing) |
| | | if err != nil { |
| | | return err |
| | | } |
| | | |
| | | if toLocAmount, aok := mapLocAmount[strconv.Itoa(v.ToLocationID)+v.ProductId]; aok { |
| | | toLocAmount.Amount = toLocAmount.Amount.Add(v.Amount) |
| | | if err := models.NewLocationProductAmountSearch().SetOrm(tx).SetID(toLocAmount.Id).Update(toLocAmount); err != nil { |
| | | return err |
| | | } |
| | | } else { |
| | | if err := models.NewLocationProductAmountSearch().SetOrm(tx).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 |
| | | } |
| | | operation := &models.Operation{ |
| | | OperationTypeId: opTypeId, |
| | | Number: strconv.FormatInt(time.Now().Unix(), 10), |
| | | Status: constvar.OperationStatus_Ready, |
| | | OperationDate: time.Now().Format("2006-01-02 15:04:05"), |
| | | Comment: "库存调拨出库", |
| | | BaseOperationType: constvar.BaseOperationTypeOutgoing, |
| | | Details: outputDetails, |
| | | LocationID: outputDetails[0].FromLocationID, |
| | | OperationTypeName: "库存调拨出库", |
| | | IsInternalOutput: true, |
| | | } |
| | | if err := models.NewOperationSearch().SetOrm(tx).Create(operation); err != nil { |
| | | return err |
| | | } |
| | | } |
| | | return nil |
| | |
| | | |
| | | // FinishOperationAdjust 完成库存调整 |
| | | // 验证后生成入库单或出库单(库存减少生成出库单,库存增加生成入库单) |
| | | func FinishOperationAdjust(tx *gorm.DB, listDetails []*models.OperationDetails, mapLocAmount map[string]*models.LocationProductAmount) (err error) { |
| | | func FinishOperationAdjust(tx *gorm.DB, listDetails []*models.OperationDetails, mapLocAmount map[string]*models.LocationProductAmount, originOperation *models.Operation) (err error) { |
| | | var inputDetails []*models.OperationDetails |
| | | var outputDetails []*models.OperationDetails |
| | | for _, v := range listDetails { |
| | |
| | | } |
| | | if v.Amount.GreaterThan(locAmount.Amount) { |
| | | inputDetails = append(inputDetails, &models.OperationDetails{ |
| | | ProductId: v.ProductId, |
| | | Amount: v.Amount.Sub(locAmount.Amount), |
| | | FromLocationID: v.FromLocationID, |
| | | ToLocationID: v.ToLocationID, |
| | | ProductId: v.ProductId, |
| | | Amount: v.Amount.Sub(locAmount.Amount), |
| | | FromLocationID: v.FromLocationID, |
| | | ToLocationID: v.ToLocationID, |
| | | TotalGrossWeight: v.TotalGrossWeight, |
| | | TotalNetWeight: v.TotalNetWeight, |
| | | AuxiliaryAmount: v.AuxiliaryAmount, |
| | | AuxiliaryUnit: v.AuxiliaryUnit, |
| | | Remark: v.Remark, |
| | | Cost: v.Cost, |
| | | SalePrice: v.SalePrice, |
| | | }) |
| | | } else { |
| | | outputDetails = append(outputDetails, &models.OperationDetails{ |
| | | ProductId: v.ProductId, |
| | | Amount: locAmount.Amount.Sub(v.Amount), |
| | | FromLocationID: v.ToLocationID, |
| | | ToLocationID: v.FromLocationID, |
| | | ProductId: v.ProductId, |
| | | Amount: locAmount.Amount.Sub(v.Amount), |
| | | FromLocationID: v.ToLocationID, |
| | | ToLocationID: v.FromLocationID, |
| | | TotalGrossWeight: v.TotalGrossWeight, |
| | | TotalNetWeight: v.TotalNetWeight, |
| | | AuxiliaryAmount: v.AuxiliaryAmount, |
| | | AuxiliaryUnit: v.AuxiliaryUnit, |
| | | Remark: v.Remark, |
| | | Cost: v.Cost, |
| | | SalePrice: v.SalePrice, |
| | | }) |
| | | } |
| | | } else { |
| | |
| | | Amount: v.Amount, |
| | | FromLocationID: v.FromLocationID, |
| | | ToLocationID: v.ToLocationID, |
| | | Remark: v.Remark, |
| | | }) |
| | | } |
| | | //if locAmount, aok := mapLocAmount[strconv.Itoa(v.ToLocationID)+v.ProductId]; aok { |
| | | // locAmount.Amount = v.Amount |
| | | // if err := models.NewLocationProductAmountSearch().SetOrm(tx).SetID(locAmount.Id).Save(locAmount); err != nil { |
| | | // return err |
| | | // } |
| | | //} else { |
| | | // if err := models.NewLocationProductAmountSearch().SetOrm(tx).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 len(inputDetails) > 0 { |
| | | operation := &models.Operation{ |
| | | Number: strconv.FormatInt(time.Now().Unix(), 10), |
| | | Status: constvar.OperationStatus_Ready, |
| | | OperationDate: time.Now().Format("2006-01-02 15:04:05"), |
| | | Comment: "库存盘点", |
| | | BaseOperationType: constvar.BaseOperationTypeIncoming, |
| | | Details: inputDetails, |
| | | LocationID: inputDetails[0].FromLocationID, |
| | | OperationTypeName: "库存调整", |
| | | } |
| | | if err := models.NewOperationSearch().SetOrm(tx).Create(operation); err != nil { |
| | | return err |
| | | } |
| | | } |
| | | if len(inputDetails) > 0 { |
| | | opTypeId, err := GetTargetOperationTypeIdByOperation(originOperation, constvar.BaseOperationTypeIncoming) |
| | | if err != nil { |
| | | return err |
| | | } |
| | | if len(outputDetails) > 0 { |
| | | operation := &models.Operation{ |
| | | Number: strconv.FormatInt(time.Now().Unix(), 10), |
| | | Status: constvar.OperationStatus_Ready, |
| | | OperationDate: time.Now().Format("2006-01-02 15:04:05"), |
| | | Comment: "库存盘点", |
| | | BaseOperationType: constvar.BaseOperationTypeOutgoing, |
| | | Details: outputDetails, |
| | | LocationID: outputDetails[0].FromLocationID, |
| | | OperationTypeName: "库存调整", |
| | | } |
| | | if err := models.NewOperationSearch().SetOrm(tx).Create(operation); err != nil { |
| | | return err |
| | | } |
| | | operation := &models.Operation{ |
| | | OperationTypeId: opTypeId, |
| | | Number: strconv.FormatInt(time.Now().Unix(), 10), |
| | | Status: constvar.OperationStatus_Ready, |
| | | OperationDate: time.Now().Format("2006-01-02 15:04:05"), |
| | | Comment: "库存调整入库", |
| | | BaseOperationType: constvar.BaseOperationTypeIncoming, |
| | | Details: inputDetails, |
| | | LocationID: inputDetails[0].FromLocationID, |
| | | OperationTypeName: "库存调整入库", |
| | | } |
| | | if err := models.NewOperationSearch().SetOrm(tx).Create(operation); err != nil { |
| | | return err |
| | | } |
| | | } |
| | | if len(outputDetails) > 0 { |
| | | opTypeId, err := GetTargetOperationTypeIdByOperation(originOperation, constvar.BaseOperationTypeOutgoing) |
| | | if err != nil { |
| | | return err |
| | | } |
| | | operation := &models.Operation{ |
| | | OperationTypeId: opTypeId, |
| | | Number: strconv.FormatInt(time.Now().Unix(), 10), |
| | | Status: constvar.OperationStatus_Ready, |
| | | OperationDate: time.Now().Format("2006-01-02 15:04:05"), |
| | | Comment: "库存调整出库", |
| | | BaseOperationType: constvar.BaseOperationTypeOutgoing, |
| | | Details: outputDetails, |
| | | LocationID: outputDetails[0].FromLocationID, |
| | | OperationTypeName: "库存调整出库", |
| | | } |
| | | if err := models.NewOperationSearch().SetOrm(tx).Create(operation); err != nil { |
| | | return err |
| | | } |
| | | } |
| | | return nil |
| | | |
| | | } |
| | | |
| | | func GetTargetOperationTypeIdByOperation(operation *models.Operation, baseOT constvar.BaseOperationType) (operationTypeId int, err error) { |
| | | oT, err := models.NewOperationTypeSearch().SetID(uint(operation.OperationTypeId)).First() |
| | | if err != nil { |
| | | return 0, err |
| | | } |
| | | targetOT, err := models.NewOperationTypeSearch().SetBaseOperationType(baseOT).SetWarehouseId(oT.WarehouseId).First() |
| | | if err != nil { |
| | | return 0, err |
| | | } |
| | | return targetOT.Id, nil |
| | | } |