jiangshuai
2023-12-28 47847bb0325c27039c1c32b5debe02f8552a2324
调整operation去掉FromLocationID,ToLocationID,以及所有调整。
9个文件已修改
757 ■■■■■ 已修改文件
controllers/location_product_amount.go 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/operation.go 511 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/product_controller.go 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/reorder_rule_controller.go 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/report_forms_controller.go 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/operation.go 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/operation_details.go 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
proto/product_inventory/server.go 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
request/operation.go 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/location_product_amount.go
@@ -120,7 +120,11 @@
    }
    var existCount int64
    if err := models.NewOperationSearch().Orm.Table("wms_operation").InnerJoins("inner join wms_operation_details on wms_operation_details.operation_id=wms_operation.id").Where("wms_operation.from_location_id=? and wms_operation_details.product_id=? and wms_operation.base_operation_type=? and wms_operation.status=?", reqParams.LocationId, reqParams.ProductId, constvar.BaseOperationTypeAdjust, constvar.OperationStatus_Ready).Count(&existCount).Error; err != nil {
    if err := models.NewOperationSearch().Orm.
        Table("wms_operation").
        InnerJoins("inner join wms_operation_details on wms_operation_details.operation_id=wms_operation.id").
        Where("wms_operation.location_id=? and wms_operation_details.product_id=? and wms_operation.base_operation_type=? and wms_operation.status=?", reqParams.LocationId, reqParams.ProductId, constvar.BaseOperationTypeAdjust, constvar.OperationStatus_Ready).
        Count(&existCount).Error; err != nil {
        return err
    }
    if existCount > 0 {
@@ -149,8 +153,10 @@
    }
    detail := &models.OperationDetails{
        ProductId: reqParams.ProductId,
        Amount:    reqParams.AdjustAmount,
        ProductId:      reqParams.ProductId,
        Amount:         reqParams.AdjustAmount,
        FromLocationID: location.Id,
        ToLocationID:   reqParams.LocationId,
    }
    operation := models.Operation{
        Number:            strconv.FormatInt(time.Now().Unix(), 10),
@@ -159,8 +165,6 @@
        Comment:           "库存盘点",
        BaseOperationType: constvar.BaseOperationTypeAdjust,
        Details:           []*models.OperationDetails{detail},
        FromLocationID:    location.Id,
        ToLocationID:      reqParams.LocationId,
    }
    if err := models.WithTransaction(func(tx *gorm.DB) error {
controllers/operation.go
@@ -61,6 +61,7 @@
        util.ResponseFormat(c, code.RequestParamError, err.Error())
        return
    }
    if err := slf.FormatLocation(&params); err != nil {
        util.ResponseFormat(c, code.RequestParamError, err.Error())
        return
@@ -122,32 +123,41 @@
        return err
    }
    if operationType.BaseOperationType == constvar.BaseOperationTypeIncoming {
        if location, err := models.NewLocationSearch().SetType(int(constvar.LocationTypeVendor)).First(); err != nil {
        location, err := models.NewLocationSearch().SetType(int(constvar.LocationTypeVendor)).First()
        if err != nil {
            return err
        } else {
            params.FromLocationID = location.Id
        }
        if params.ToLocationID == 0 {
            return errors.New("请选择目标位置")
        for k, v := range params.Details {
            params.Details[k].FromLocationID = location.Id
            if v.ToLocationID == 0 {
                params.Details[k].ToLocationID = params.LocationID
            }
        }
    }
    if operationType.BaseOperationType == constvar.BaseOperationTypeOutgoing {
        if location, err := models.NewLocationSearch().SetType(int(constvar.LocationTypeCustomer)).First(); err != nil {
        location, err := models.NewLocationSearch().SetType(int(constvar.LocationTypeCustomer)).First()
        if err != nil {
            return err
        } else {
            params.ToLocationID = location.Id
        }
        if params.FromLocationID == 0 {
            return errors.New("请选择源位置")
        for k, v := range params.Details {
            params.Details[k].ToLocationID = location.Id
            if v.FromLocationID == 0 {
                return errors.New("请选择出库位置")
            }
        }
    }
    if operationType.BaseOperationType == constvar.BaseOperationTypeInternal {
        if params.ToLocationID == 0 {
            return errors.New("请选择目标位置")
        for _, v := range params.Details {
            if v.ToLocationID == 0 {
                return errors.New("请选择目标位置")
            }
            if v.FromLocationID == 0 {
                return errors.New("请选择源位置")
            }
        }
        if params.FromLocationID == 0 {
            return errors.New("请选择源位置")
        }
    }
    return nil
}
@@ -167,6 +177,10 @@
    if params.OperationDate == "" {
        return errors.New("请选择安排日期")
    }
    if params.LocationID == 0 {
        return errors.New("请选择源位置")
    }
    if len(params.Details) <= 0 {
@@ -380,8 +394,26 @@
        util.ResponseFormat(c, code.RequestError, "该出入库信息无法完成")
        return
    }
    err = models.WithTransaction(func(tx *gorm.DB) error {
    listDetails, err := models.NewOperationDetailsSearch().SetOperationId(operation.Id).SetPreload(true).FindAll()
    if err != nil {
        util.ResponseFormat(c, code.RequestError, err.Error())
        return
    }
    var mapLocAmount map[string]*models.LocationProductAmount
    locAmountList, err := models.NewLocationProductAmountSearch().Find()
    if err != nil {
        util.ResponseFormat(c, code.RequestError, err.Error())
        return
    }
    if len(locAmountList) > 0 {
        for _, v := range locAmountList {
            mapLocAmount[strconv.Itoa(v.LocationId)+v.ProductId] = v
        }
    }
    err = models.WithTransaction(func(tx *gorm.DB) error {
        if err := models.NewOperationSearch().SetOrm(tx).SetID(id).Update(&models.Operation{Status: constvar.OperationStatus_Finish, AuditDate: time.Now().Format("2006-01-02 15:04:05")}); err != nil {
            return err
        }
@@ -389,154 +421,119 @@
            return err
        }
        var listProdtId []string
        var listProdt []*models.Material
        mapProdt := make(map[string]decimal.Decimal)
        listDetails, err := models.NewOperationDetailsSearch().SetOperationId(operation.Id).FindAll()
        if err != nil {
            return err
        }
        for _, v := range listDetails {
            listProdtId = append(listProdtId, v.ProductId)
            mapProdt[v.ProductId] = v.Amount
        }
        if err := models.NewMaterialSearch().Orm.Where("id IN ?", listProdtId).Find(&listProdt).Error; err != nil {
            return err
        }
        if operation.BaseOperationType == constvar.BaseOperationTypeIncoming {
            var operationInputs []*models.Operation
            for k, v := range listProdt {
                value, ok := mapProdt[v.ID]
                if !ok {
                    return errors.New("产品种类异常")
            locationRoleList, err := models.NewLocationProductSearch().Find()
            if err != nil {
                return errors.New("获取上架规则信息失败")
            }
            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
                    }
                }
            }
                listProdt[k].Amount = listProdt[k].Amount.Add(value)
                if err := tx.Save(listProdt[k]).Error; err != nil {
            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
                }
                locationRule, err := models.NewLocationProductSearch().SetProductId(v.ID).SetAreaId(operation.ToLocationID).First()
                if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
                    return err
                }
                if err == nil {
                    operationTransfer := &models.Operation{
                        Number:            operation.Number,
                        SourceNumber:      operation.SourceNumber,
                        OperationTypeId:   0,
                        OperationTypeName: operation.OperationTypeName,
                        Status:            constvar.OperationStatus_Finish,
                        FromLocationID:    locationRule.AreaId,
                        ToLocationID:      locationRule.LocationId,
                        OperationDate:     operation.OperationDate,
                        ContacterID:       operation.ContacterID,
                        ContacterName:     operation.ContacterName,
                        CompanyID:         operation.CompanyID,
                        CompanyName:       operation.CompanyName,
                        Comment:           operation.Comment,
                        BaseOperationType: constvar.BaseOperationTypeInternal,
                        Details: []*models.OperationDetails{
                            {
                                ProductId: v.ID,
                                Amount:    value,
                            },
                        },
                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,
                    }
                    operationInputs = append(operationInputs, operationTransfer)
                    details = append(details, detail)
                    //if err := tx.Create(&operationTransfer).Error; err != nil {
                    //    return err
                    //}
                    locAmount, err := models.NewLocationProductAmountSearch().
                        SetProductId(v.ID).
                        SetLocationId(locationRule.LocationId).
                        First()
                    if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
                        return err
                    }
                    locAmount.LocationId = locationRule.LocationId
                    locAmount.ProductId = v.ID
                    locAmount.CreateDate = time.Now().Format("2006-01-02 15:04:05")
                    locAmount.Amount = locAmount.Amount.Add(value)
                    locAmount.ProductCategoryID = v.CategoryId
                    if res := models.NewLocationProductAmountSearch().Orm.Where("id=?", locAmount.ID).Save(locAmount); res.Error != nil {
                        return res.Error
                    }
                } else {
                    locationRule, err = models.NewLocationProductSearch().SetProductCategoryId(v.CategoryId).SetAreaId(operation.ToLocationID).First()
                    if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
                        return err
                    }
                    if err == nil {
                        operationTransfer := &models.Operation{
                            Number:            operation.Number,
                            SourceNumber:      operation.SourceNumber,
                            OperationTypeId:   0,
                            OperationTypeName: operation.OperationTypeName,
                            Status:            constvar.OperationStatus_Finish,
                            FromLocationID:    locationRule.AreaId,
                            ToLocationID:      locationRule.LocationId,
                            OperationDate:     operation.OperationDate,
                            ContacterID:       operation.ContacterID,
                            ContacterName:     operation.ContacterName,
                            CompanyID:         operation.CompanyID,
                            CompanyName:       operation.CompanyName,
                            Comment:           operation.Comment,
                            BaseOperationType: constvar.BaseOperationTypeInternal,
                            Details: []*models.OperationDetails{
                                {
                                    ProductId: v.ID,
                                    Amount:    value,
                                },
                            },
                        }
                        operationInputs = append(operationInputs, operationTransfer)
                        //if err := tx.Create(&operationTransfer).Error; err != nil {
                        //    return err
                        //}
                        locAmount, err := models.NewLocationProductAmountSearch().
                            SetProductId(v.ID).
                            SetLocationId(locationRule.LocationId).
                            First()
                        if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
                            return err
                        }
                        locAmount.LocationId = locationRule.LocationId
                        locAmount.ProductId = v.ID
                        locAmount.CreateDate = time.Now().Format("2006-01-02 15:04:05")
                        locAmount.Amount = locAmount.Amount.Add(value)
                        locAmount.ProductCategoryID = v.CategoryId
                    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 {
                        locAmount, err := models.NewLocationProductAmountSearch().
                            SetProductId(v.ID).
                            SetLocationId(operation.ToLocationID).
                            First()
                        if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
                        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
                        }
                        locAmount.LocationId = operation.ToLocationID
                        locAmount.ProductId = v.ID
                        locAmount.CreateDate = time.Now().Format("2006-01-02 15:04:05")
                        locAmount.Amount = locAmount.Amount.Add(value)
                        locAmount.ProductCategoryID = v.CategoryId
                        if res := models.NewLocationProductAmountSearch().Orm.Where("id=?", locAmount.ID).Save(locAmount); res.Error != nil {
                            return res.Error
                    }
                } 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(operationInputs) > 0 {
                if err := tx.Create(&operationInputs).Error; err != nil {
            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,
                }).Error; err != nil {
                    return err
                }
            }
@@ -547,11 +544,7 @@
        }
        if operation.BaseOperationType == constvar.BaseOperationTypeOutgoing {
            for k, v := range listProdt {
                value, ok := mapProdt[v.ID]
                if !ok {
                    return errors.New("产品种类异常")
                }
            for k, v := range listDetails {
                //todo 演示测试数据
                data, err := os.ReadFile("conf/input.json")
                if err != nil {
@@ -563,30 +556,29 @@
                    return errors.New("格式转换失败")
                }
                if opa.OpaCheck(c, m, "operation") {
                    if v.Amount.LessThan(value) {
                        return errors.New(fmt.Sprintf("产品:%v,库存:%v,出库:%v,数量不够,无法完成出库操作", v.Name, v.Amount.String(), value.String()))
                    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()))
                    }
                }
                listProdt[k].Amount = listProdt[k].Amount.Sub(value)
                if err := tx.Save(listProdt[k]).Error; err != nil {
                //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
                }
                locAmount, res := models.NewLocationProductAmountSearch().
                    SetProductId(v.ID).
                    SetLocationId(operation.FromLocationID).
                    FirstRes()
                if res.Error != nil {
                    if res.Error == gorm.ErrRecordNotFound {
                        return errors.New("当前仓库没有该产品,请先入库")
                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()))
                    }
                    return res.Error
                }
                if locAmount.Amount.LessThan(value) {
                    return errors.New(fmt.Sprintf("产品:%v,库存:%v,出库:%v,数量不够,无法完成出库操作", v.Name, v.Amount.String(), value.String()))
                }
                locAmount.Amount = locAmount.Amount.Sub(value)
                if err := models.NewLocationProductAmountSearch().SetID(locAmount.Id).Update(locAmount); err != nil {
                    return err
                    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 operation.Source != "" {
@@ -595,150 +587,34 @@
        }
        if operation.BaseOperationType == constvar.BaseOperationTypeInternal {
            var operationInputs []*models.Operation
            for _, v := range listProdt {
                value, ok := mapProdt[v.ID]
                if !ok {
                    return errors.New("产品种类异常")
                }
                //listProdt[k].Amount = listProdt[k].Amount.Add(value)
                //if err := tx.Save(listProdt[k]).Error; err != nil {
                //    return err
                //}
                fromLocAmount, res := models.NewLocationProductAmountSearch().
                    SetProductId(v.ID).
                    SetLocationId(operation.FromLocationID).
                    FirstRes()
                if res.Error != nil {
                    return err
                }
                if fromLocAmount.Amount.LessThan(value) {
                    return errors.New(fmt.Sprintf("产品:%v,库存:%v,调拨:%v,数量不够,无法完成调拨操作", v.Name, v.Amount.String(), value.String()))
                }
                fromLocAmount.Amount = fromLocAmount.Amount.Sub(value)
                if err := models.NewLocationProductAmountSearch().SetID(fromLocAmount.Id).Update(fromLocAmount); err != nil {
                    return err
                }
                locationRule, err := models.NewLocationProductSearch().SetProductId(v.ID).SetAreaId(operation.ToLocationID).First()
                if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
                    return err
                }
                if err == nil {
                    operationTransfer := &models.Operation{
                        Number:            operation.Number,
                        SourceNumber:      operation.SourceNumber,
                        OperationTypeId:   0,
                        OperationTypeName: operation.OperationTypeName,
                        Status:            constvar.OperationStatus_Finish,
                        FromLocationID:    locationRule.AreaId,
                        ToLocationID:      locationRule.LocationId,
                        OperationDate:     operation.OperationDate,
                        ContacterID:       operation.ContacterID,
                        ContacterName:     operation.ContacterName,
                        CompanyID:         operation.CompanyID,
                        CompanyName:       operation.CompanyName,
                        Comment:           operation.Comment,
                        BaseOperationType: constvar.BaseOperationTypeInternal,
                        Details: []*models.OperationDetails{
                            {
                                ProductId: v.ID,
                                Amount:    value,
                            },
                        },
            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()))
                    }
                    operationInputs = append(operationInputs, operationTransfer)
                    //if err := tx.Create(&operationTransfer).Error; err != nil {
                    //    return err
                    //}
                    locAmount, err := models.NewLocationProductAmountSearch().
                        SetProductId(v.ID).
                        SetLocationId(locationRule.LocationId).
                        First()
                    if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
                    fromLocAmount.Amount = fromLocAmount.Amount.Sub(v.Amount)
                    if err := models.NewLocationProductAmountSearch().SetID(fromLocAmount.Id).Update(fromLocAmount); err != nil {
                        return err
                    }
                    locAmount.LocationId = locationRule.LocationId
                    locAmount.ProductId = v.ID
                    locAmount.CreateDate = time.Now().Format("2006-01-02 15:04:05")
                    locAmount.Amount = locAmount.Amount.Add(value)
                    locAmount.ProductCategoryID = v.CategoryId
                    if res := models.NewLocationProductAmountSearch().Orm.Where("id=?", locAmount.ID).Save(locAmount); res.Error != nil {
                        return res.Error
                    }
                } else {
                    locationRule, err = models.NewLocationProductSearch().SetProductCategoryId(v.CategoryId).SetAreaId(operation.ToLocationID).First()
                    if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
                    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
                    }
                    if err == nil {
                        operationTransfer := &models.Operation{
                            Number:            operation.Number,
                            SourceNumber:      operation.SourceNumber,
                            OperationTypeId:   0,
                            OperationTypeName: operation.OperationTypeName,
                            Status:            constvar.OperationStatus_Finish,
                            FromLocationID:    locationRule.AreaId,
                            ToLocationID:      locationRule.LocationId,
                            OperationDate:     operation.OperationDate,
                            ContacterID:       operation.ContacterID,
                            ContacterName:     operation.ContacterName,
                            CompanyID:         operation.CompanyID,
                            CompanyName:       operation.CompanyName,
                            Comment:           operation.Comment,
                            BaseOperationType: constvar.BaseOperationTypeInternal,
                            Details: []*models.OperationDetails{
                                {
                                    ProductId: v.ID,
                                    Amount:    value,
                                },
                            },
                        }
                        operationInputs = append(operationInputs, operationTransfer)
                        //if err := tx.Create(&operationTransfer).Error; err != nil {
                        //    return err
                        //}
                        locAmount, err := models.NewLocationProductAmountSearch().
                            SetProductId(v.ID).
                            SetLocationId(locationRule.LocationId).
                            First()
                        if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
                            return err
                        }
                        locAmount.LocationId = locationRule.LocationId
                        locAmount.ProductId = v.ID
                        locAmount.CreateDate = time.Now().Format("2006-01-02 15:04:05")
                        locAmount.Amount = locAmount.Amount.Add(value)
                        locAmount.ProductCategoryID = v.CategoryId
                        if res := models.NewLocationProductAmountSearch().Orm.Where("id=?", locAmount.ID).Save(locAmount); res.Error != nil {
                            return res.Error
                        }
                    } else {
                        locAmount, err := models.NewLocationProductAmountSearch().
                            SetProductId(v.ID).
                            SetLocationId(operation.ToLocationID).
                            First()
                        if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
                            return err
                        }
                        locAmount.LocationId = operation.ToLocationID
                        locAmount.ProductId = v.ID
                        locAmount.CreateDate = time.Now().Format("2006-01-02 15:04:05")
                        locAmount.Amount = locAmount.Amount.Add(value)
                        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 len(operationInputs) > 0 {
                if err := tx.Create(&operationInputs).Error; err != nil {
                    return err
                }
            }
        }
@@ -768,10 +644,10 @@
                Amount:            v.Amount,
                Unit:              v.Product.Unit,
                Weight:            operation.Weight,
                FromLocationId:    operation.FromLocationID,
                FromLocation:      operation.FromLocation.Name,
                ToLocationId:      operation.ToLocationID,
                ToLocation:        operation.ToLocation.Name,
                FromLocationId:    v.FromLocationID,
                FromLocation:      v.FromLocation.Name,
                ToLocationId:      v.ToLocationID,
                ToLocation:        v.ToLocation.Name,
            }
            histories = append(histories, history)
        }
@@ -1030,7 +906,7 @@
        f.SetCellValue("Sheet1", "C"+strconv.Itoa(rowIndex), v.Product.Specs)
        f.SetCellValue("Sheet1", "D"+strconv.Itoa(rowIndex), v.Product.Unit)
        f.SetCellValue("Sheet1", "E"+strconv.Itoa(rowIndex), v.Amount.String())
        f.SetCellValue("Sheet1", "H"+strconv.Itoa(rowIndex), operation.ToLocation.Name)
        f.SetCellValue("Sheet1", "H"+strconv.Itoa(rowIndex), v.ToLocation.Name)
        f.SetCellValue("Sheet1", "I"+strconv.Itoa(rowIndex), operation.Comment)
        rowIndex++
        totalAmount = totalAmount.Add(v.Amount)
@@ -1063,7 +939,7 @@
}
func ExportOutputOperation(category constvar.FileTemplateCategory, operation *models.Operation) (string, error) {
    repositoryLevels := strings.Split(operation.FromLocation.JointName, "/")
    repositoryLevels := strings.Split(operation.Location.JointName, "/")
    template, err := models.NewFileTemplateAttachmentSearch().SetPreload(true).SetCategory(category).First()
    if err != nil {
        return "", errors.New("获取模版记录失败:" + err.Error())
@@ -1194,9 +1070,14 @@
        return
    }
    db := mysqlx.GetDB().Table("wms_operation").Select("wms_operation.id as operation_id,wms_operation.number,wms_operation.base_operation_type,material.id AS product_id,material.`name` AS product_name,wms_operation_details.amount,material.unit,wms_operation.from_location_id,from_location.`name` AS from_location,wms_operation.to_location_id,to_location.`name` AS to_location,wms_operation.operation_date as date,wms_operation.`status`").InnerJoins("inner join wms_operation_details ON wms_operation_details.operation_id = wms_operation.id").InnerJoins("INNER JOIN material ON material.id = wms_operation_details.product_id").InnerJoins("INNER JOIN wms_location AS from_location ON from_location.id = wms_operation.from_location_id").InnerJoins("INNER JOIN wms_location AS to_location ON to_location.id = wms_operation.to_location_id")
    db := mysqlx.GetDB().Table("wms_operation").
        Select("wms_operation.id as operation_id,wms_operation.number,wms_operation.base_operation_type,material.id AS product_id,material.`name` AS product_name,wms_operation_details.amount,material.unit,wms_operation_details.from_location_id,from_location.`name` AS from_location,wms_operation_details.to_location_id,to_location.`name` AS to_location,wms_operation.operation_date as date,wms_operation.`status`").
        InnerJoins("inner join wms_operation_details ON wms_operation_details.operation_id = wms_operation.id").
        InnerJoins("INNER JOIN material ON material.id = wms_operation_details.product_id").
        InnerJoins("INNER JOIN wms_location AS from_location ON from_location.id = wms_operation_details.from_location_id").
        InnerJoins("INNER JOIN wms_location AS to_location ON to_location.id = wms_operation_details.to_location_id")
    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 ?", "%"+params.Condition+"%", "%"+params.Condition+"%", "%"+params.Condition+"%", "%"+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+"%")
    }
    var (
        records = make([]*response.InventoryHistory, 0)
controllers/product_controller.go
@@ -464,8 +464,10 @@
    }
    detail := &models.OperationDetails{
        ProductId: params.ProductId,
        Amount:    params.Amount,
        ProductId:      params.ProductId,
        Amount:         params.Amount,
        FromLocationID: params.FromLocationId,
        ToLocationID:   params.ToLocationId,
    }
    operation := models.Operation{
        //Number:            strconv.FormatInt(time.Now().Unix(), 10),
@@ -473,8 +475,6 @@
        SourceNumber:      params.SourceNumber,
        OperationTypeId:   0,
        Status:            constvar.OperationStatus_Ready,
        FromLocationID:    params.FromLocationId,
        ToLocationID:      params.ToLocationId,
        OperationDate:     time.Now().Format("2006-01-02 15:04:05"),
        Details:           []*models.OperationDetails{detail},
        BaseOperationType: constvar.BaseOperationTypeDisuse,
@@ -505,7 +505,12 @@
        return
    }
    db := models.NewOperationSearch().Orm.Table("wms_operation").Select("wms_operation.id,wms_operation.number,wms_operation.source_number,wms_operation.status,wms_operation.from_location_id,wms_operation.to_location_id,wms_operation.operation_date,wms_operation.contacter_id,wms_operation.contacter_name,wms_operation.company_id,wms_operation.company_name,wms_operation.comment,wms_operation_details.product_id,material.name as product_name,material.unit,wms_operation_details.amount,wms_operation.base_operation_type").InnerJoins("inner join wms_operation_details on wms_operation_details.operation_id=wms_operation.id").InnerJoins("inner join material on material.id=wms_operation_details.product_id").Where("wms_operation.base_operation_type=?", constvar.BaseOperationTypeDisuse)
    db := models.NewOperationSearch().Orm.
        Table("wms_operation").
        Select("wms_operation.id,wms_operation.number,wms_operation.source_number,wms_operation.status,wms_operation_details.from_location_id,wms_operation_details.to_location_id,wms_operation.operation_date,wms_operation.contacter_id,wms_operation.contacter_name,wms_operation.company_id,wms_operation.company_name,wms_operation.comment,wms_operation_details.product_id,material.name as product_name,material.unit,wms_operation_details.amount,wms_operation.base_operation_type").
        InnerJoins("inner join wms_operation_details on wms_operation_details.operation_id=wms_operation.id").
        InnerJoins("inner join material on material.id=wms_operation_details.product_id").
        Where("wms_operation.base_operation_type=?", constvar.BaseOperationTypeDisuse)
    if params.Number != "" {
        db = db.Where("wms_operation.number like ? or wms_operation.source_number like ? or material.name like ?", fmt.Sprintf("%%%v%%", params.Number), fmt.Sprintf("%%%v%%", params.Number), fmt.Sprintf("%%%v%%", params.Number))
@@ -564,62 +569,34 @@
        if err := models.NewOperationSearch().SetOrm(tx).SetID(id).Update(&models.Operation{Status: constvar.OperationStatus_Finish, AuditDate: time.Now().Format("2006-01-02 15:04:05")}); err != nil {
            return err
        }
        var listProdtId []string
        var listProdt []*models.Material
        mapProdt := make(map[string]decimal.Decimal)
        listDetails, err := models.NewOperationDetailsSearch().SetOperationId(operation.Id).FindAll()
        listDetails, err := models.NewOperationDetailsSearch().SetOperationId(operation.Id).SetPreload(true).FindAll()
        if err != nil {
            return err
        }
        for _, v := range listDetails {
            listProdtId = append(listProdtId, v.ProductId)
            mapProdt[v.ProductId] = v.Amount
        }
        if err := models.NewMaterialSearch().Orm.Where("id IN ?", listProdtId).Find(&listProdt).Error; err != nil {
            return err
        }
        for k, v := range listProdt {
            if value, ok := mapProdt[v.ID]; !ok {
                return errors.New("产品种类异常")
            } else {
                if v.Amount.LessThan(value) {
                    return errors.New(fmt.Sprintf("产品:%v,库存:%v,报废:%v,数量不够,无法完成报废操作", v.Name, v.Amount.String(), value.String()))
                }
                listProdt[k].Amount = listProdt[k].Amount.Sub(value)
                if err := tx.Save(listProdt[k]).Error; err != nil {
                    return err
                }
                //var locAmount models.LocationProductAmount
                //if err := models.NewLocationProductAmountSearch().Orm.
                //    Table("wms_location_product_amount").
                //    Joins("inner join wms_location_product on wms_location_product.id=wms_location_product_amount.location_product_id").
                //    Where("wms_location_product.product_id=? and wms_location_product.location_id=?", v.ID, operation.FromLocationID).
                //    First(&locAmount).Error; err != nil {
                //    return err
                //}
                //if locAmount.Amount.LessThan(value) {
                //    return errors.New(fmt.Sprintf("产品:%v,库存:%v,出库:%v,数量不够,无法完成出库操作", v.Name, v.Amount.String(), value.String()))
                //}
                //locAmount.Amount = locAmount.Amount.Sub(value)
                //if err := models.NewLocationProductAmountSearch().SetID(locAmount.Id).Update(&locAmount); err != nil {
                //    return err
                //}
        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()))
            }
            listDetails[k].Product.Amount = listDetails[k].Product.Amount.Sub(v.Amount)
            if err := tx.Save(&listDetails[k].Product).Error; err != nil {
                return err
            }
                locAmount, res := models.NewLocationProductAmountSearch().
                    SetProductId(v.ID).
                    SetLocationId(operation.FromLocationID).
                    FirstRes()
                if res.Error != nil {
                    return err
                }
                if locAmount.Amount.LessThan(value) {
                    return errors.New(fmt.Sprintf("产品:%v,库存:%v,报废:%v,数量不够,无法完成报废操作", v.Name, v.Amount.String(), value.String()))
                }
                locAmount.Amount = locAmount.Amount.Sub(value)
                if err := models.NewLocationProductAmountSearch().SetID(locAmount.Id).Update(locAmount); err != nil {
                    return err
                }
            locAmount, res := models.NewLocationProductAmountSearch().
                SetProductId(v.ProductId).
                SetLocationId(v.FromLocationID).
                FirstRes()
            if res.Error != nil {
                return err
            }
            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
            }
        }
        return nil
@@ -672,6 +649,8 @@
        //ProductName: params.ProductName,
        Amount: params.Amount,
        //Unit:        params.Unit,
        FromLocationID: params.FromLocationId,
        ToLocationID:   params.ToLocationId,
    }
    operation := models.Operation{
        Id:                params.Id,
@@ -679,8 +658,6 @@
        SourceNumber:      params.SourceNumber,
        OperationTypeId:   0,
        Status:            params.Status,
        FromLocationID:    params.FromLocationId,
        ToLocationID:      params.ToLocationId,
        OperationDate:     params.OperationDate,
        Details:           []*models.OperationDetails{detail},
        BaseOperationType: params.BaseOperationType,
@@ -723,7 +700,7 @@
    }
    search := models.NewOperationSearch().SetPage(params.Page, params.PageSize).SetPreload(true).SetOrder("created_at desc")
    search.SetOrm(search.Orm.InnerJoins("inner join wms_operation_details on wms_operation_details.operation_id=wms_operation.id").Where("wms_operation_details.product_id=? and (wms_operation.from_location_id=? or wms_operation.to_location_id=?)", params.ProductId, params.LocationId, params.LocationId))
    search.SetOrm(search.Orm.InnerJoins("inner join wms_operation_details on wms_operation_details.operation_id=wms_operation.id").Where("wms_operation_details.product_id=? and (wms_operation_details.from_location_id=? or wms_operation_details.to_location_id=?)", params.ProductId, params.LocationId, params.LocationId))
    list, total, err := search.SetBaseOperationType(constvar.BaseOperationTypeAdjust).Find()
    if err != nil {
controllers/reorder_rule_controller.go
@@ -150,17 +150,17 @@
    var pa []request.ProductAmount
    search := models.NewOperationDetailsSearch()
    search.Orm = search.Orm.Model(&models.OperationDetails{}).
        Select("wms_operation_details.product_id, wms_operation_details.amount, wms_operation.to_location_id as to_location_id, " +
            "wms_operation.from_location_id as from_location_id, wms_operation.base_operation_type").
        Select("wms_operation_details.product_id, wms_operation_details.amount, wms_operation_details.to_location_id as to_location_id, " +
            "wms_operation_details.from_location_id as from_location_id, wms_operation.base_operation_type").
        Joins("left join wms_operation on wms_operation_details.operation_id = wms_operation.id")
    if len(productIds) > 0 {
        search.Orm.Where("wms_operation_details.product_id in (?)", productIds)
    }
    if len(toLocationIds) > 0 {
        search.Orm.Where("wms_operation.to_location_id in (?)", toLocationIds)
        search.Orm.Where("wms_operation_details.to_location_id in (?)", toLocationIds)
    }
    if len(fromLocationIds) > 0 {
        search.Orm.Where("wms_operation.from_location_id in (?)", fromLocationIds)
        search.Orm.Where("wms_operation_details.from_location_id in (?)", fromLocationIds)
    }
    if len(status) > 0 {
        search.Orm.Where("wms_operation.status in (?)", status)
@@ -332,16 +332,17 @@
    var details models.OperationDetails
    details.ProductId = params.ProductId
    details.Amount = params.OrderNumber
    details.FromLocationID = 1
    details.ToLocationID = params.LocationId
    operation.Details = append(operation.Details, &details)
    operation.BaseOperationType = constvar.BaseOperationTypeIncoming
    operation.Status = constvar.OperationStatus_Ready
    operation.OperationTypeId = operationType.Id
    operation.OperationTypeName = operationType.Name
    operation.OperationDate = timex.TimeToString2(time.Now())
    //todo 供应商位置
    operation.FromLocationID = 1
    operation.LocationID = params.LocationId
    operation.Number = strconv.FormatInt(time.Now().Unix(), 10)
    operation.ToLocationID = params.LocationId
    operation.SourceNumber = SourceNumber
    err = models.WithTransaction(func(db *gorm.DB) error {
controllers/report_forms_controller.go
@@ -97,8 +97,8 @@
        Where("wms_operation.base_operation_type in (?)", []constvar.BaseOperationType{constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeInternal, constvar.BaseOperationTypeDisuse}).
        Where("wms_operation.status in (?)", []constvar.OperationStatus{constvar.OperationStatus_Ready, constvar.OperationStatus_Finish})
    if len(locationIds) > 0 {
        dbIn.Where("wms_operation.to_location_id in (?)", locationIds)
        dbOut.Where("wms_operation.from_location_id in (?)", locationIds)
        dbIn.Where("wms_operation_details.to_location_id in (?)", locationIds)
        dbOut.Where("wms_operation_details.from_location_id in (?)", locationIds)
    }
    if len(productIds) > 0 {
        dbIn.Where("wms_operation_details.product_id in (?)", productIds)
models/operation.go
@@ -13,27 +13,27 @@
    Operation struct {
        WmsModel
        Id                int                      `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"`
        Number            string                   `json:"number" gorm:"type:varchar(255)"`                                 //单号
        SourceNumber      string                   `json:"sourceNumber" gorm:"type:varchar(255)"`                           //源单号
        OperationTypeId   int                      `json:"operationTypeId" gorm:"type:int;not null;comment:作业类型id"`         //作业类型id
        OperationTypeName string                   `json:"operationTypeName" gorm:"type:varchar(127);comment:作业类型名称"`       //作业类型名称
        Status            constvar.OperationStatus `json:"status" gorm:"type:int(11);not null;comment:状态"`                  //状态
        FromLocationID    int                      `json:"fromLocationId"   gorm:"type:int;not null;comment:源位置id"`         //源位置id
        FromLocation      Location                 `json:"fromLocation"     gorm:"foreignKey:FromLocationID;references:Id"` //源位置
        ToLocationID      int                      `json:"toLocationId"    gorm:"type:int;not null;comment:目标位置id"`         //目标位置id
        ToLocation        Location                 `json:"toLocation"      gorm:"foreignKey:ToLocationID;references:Id"`    //目标位置
        OperationDate     string                   `json:"operationDate" gorm:"type:varchar(31);comment:安排日期"`
        ContacterID       int                      `json:"contacterID" gorm:"type:int;comment:联系人ID"`
        ContacterName     string                   `json:"contacterName" gorm:"type:varchar(63);comment:联系人姓名"`
        CompanyID         int                      `json:"companyID" gorm:"type:int;comment:公司ID-客户"`
        CompanyName       string                   `json:"companyName" gorm:"type:varchar(127);comment:公司名称-客户"`
        Comment           string                   `json:"comment" gorm:"type:text;comment:备注"`
        LogisticCompanyId string                   `json:"logisticCompanyId"   gorm:"type:varchar(191);comment:物流公司id"`
        LogisticCompany   LogisticCompany          `json:"logisticCompany"      gorm:"foreignKey:LogisticCompanyId"`
        WaybillNumber     string                   `json:"waybillNumber" gorm:"type:varchar(255);comment:运单号"`    //运单号
        Weight            decimal.Decimal          `gorm:"type:decimal(20,2);comment:重量" json:"weight"`           //重量
        LogisticWeight    decimal.Decimal          `gorm:"type:decimal(20,2);comment:物流重量" json:"logisticWeight"` //物流重量
        Source            string                   `json:"source" gorm:"type:varchar(255);comment:来源系统,用于返回修改状态"`
        Number            string                   `json:"number" gorm:"type:varchar(255)"`                           //单号
        SourceNumber      string                   `json:"sourceNumber" gorm:"type:varchar(255)"`                     //源单号
        OperationTypeId   int                      `json:"operationTypeId" gorm:"type:int;not null;comment:作业类型id"`   //作业类型id
        OperationTypeName string                   `json:"operationTypeName" gorm:"type:varchar(127);comment:作业类型名称"` //作业类型名称
        Status            constvar.OperationStatus `json:"status" gorm:"type:int(11);not null;comment:状态"`            //状态
        //FromLocationID    int                      `json:"fromLocationId"   gorm:"type:int;not null;comment:源位置id"`         //源位置id
        //FromLocation      Location                 `json:"fromLocation"     gorm:"foreignKey:FromLocationID;references:Id"` //源位置
        //ToLocationID      int                      `json:"toLocationId"    gorm:"type:int;not null;comment:目标位置id"`         //目标位置id
        //ToLocation        Location                 `json:"toLocation"      gorm:"foreignKey:ToLocationID;references:Id"`    //目标位置
        OperationDate     string          `json:"operationDate" gorm:"type:varchar(31);comment:安排日期"`
        ContacterID       int             `json:"contacterID" gorm:"type:int;comment:联系人ID"`
        ContacterName     string          `json:"contacterName" gorm:"type:varchar(63);comment:联系人姓名"`
        CompanyID         int             `json:"companyID" gorm:"type:int;comment:公司ID-客户"`
        CompanyName       string          `json:"companyName" gorm:"type:varchar(127);comment:公司名称-客户"`
        Comment           string          `json:"comment" gorm:"type:text;comment:备注"`
        LogisticCompanyId string          `json:"logisticCompanyId"   gorm:"type:varchar(191);comment:物流公司id"`
        LogisticCompany   LogisticCompany `json:"logisticCompany"      gorm:"foreignKey:LogisticCompanyId"`
        WaybillNumber     string          `json:"waybillNumber" gorm:"type:varchar(255);comment:运单号"`    //运单号
        Weight            decimal.Decimal `gorm:"type:decimal(20,2);comment:重量" json:"weight"`           //重量
        LogisticWeight    decimal.Decimal `gorm:"type:decimal(20,2);comment:物流重量" json:"logisticWeight"` //物流重量
        Source            string          `json:"source" gorm:"type:varchar(255);comment:来源系统,用于返回修改状态"`
        Details           []*OperationDetails        `json:"details" gorm:"foreignKey:OperationID;references:Id"`
        BaseOperationType constvar.BaseOperationType `json:"baseOperationType" gorm:"type:tinyint;not null;comment:基础作业类型"` //基础作业类型
@@ -42,6 +42,9 @@
        ReceiverName  string `json:"receiverName" gorm:"type:varchar(31);comment:收货人姓名"`
        ReceiverPhone string `json:"receiverPhone" gorm:"type:varchar(31);comment:联系电话"`
        ReceiverAddr  string `json:"receiverAddr" gorm:"type:varchar(255);comment:收货地址"`
        LocationID int      `json:"locationID"   gorm:"type:int;not null;comment:源位置id"` //源位置id
        Location   Location `json:"location" gorm:"foreignkey:locationID;references:Id"` //源位置
    }
    OperationSearch struct {
@@ -158,7 +161,7 @@
    }
    if slf.Preload {
        db = db.Model(&Operation{}).Preload("Details").Preload("Details.Product").Preload("LogisticCompany").Preload("FromLocation").Preload("ToLocation")
        db = db.Model(&Operation{}).Preload("Details").Preload("Details.Product").Preload("LogisticCompany").Preload("Location").Preload("Details.FromLocation").Preload("Details.ToLocation")
    }
    if slf.Disuse {
models/operation_details.go
@@ -18,6 +18,11 @@
        Amount decimal.Decimal `json:"amount" gorm:"type:decimal(20,2);not null;comment:数量"` //数量
        //Unit        string          `json:"unit" gorm:"type:varchar(31);comment:单位"`                    //单位
        Product Material `json:"product" gorm:"foreignKey:ProductId;references:ID"`
        FromLocationID int      `json:"fromLocationId"   gorm:"type:int;not null;comment:源位置id"`         //源位置id
        FromLocation   Location `json:"fromLocation"     gorm:"foreignKey:FromLocationID;references:Id"` //源位置
        ToLocationID   int      `json:"toLocationId"    gorm:"type:int;not null;comment:目标位置id"`         //目标位置id
        ToLocation     Location `json:"toLocation"      gorm:"foreignKey:ToLocationID;references:Id"`    //目标位置
    }
    OperationDetailsSearch struct {
proto/product_inventory/server.go
@@ -34,7 +34,7 @@
    var productIds []string
    resp := new(GetInventoryProductInfoResponse)
    err := models.NewOperationDetailsSearch().Orm.Model(&models.OperationDetails{}).
        Select("wms_operation_details.product_id,wms_operation_details.amount,wms_operation.from_location_id as location_id,"+
        Select("wms_operation_details.product_id,wms_operation_details.amount,wms_operation_details.from_location_id as location_id,"+
            "wms_operation.number,wms_operation.waybill_number, logistic_company.name").
        Joins("left join wms_operation on wms_operation.id = wms_operation_details.operation_id").
        Joins("left join logistic_company on logistic_company.id = wms_operation.logistic_company_id").
@@ -92,7 +92,7 @@
        Select("wms_operation_details.product_id, wms_operation_details.amount").
        Joins("left join wms_operation on wms_operation_details.operation_id = wms_operation.id").
        Where("wms_operation_details.product_id in (?)", productIds).
        Where("wms_operation.from_location_id in (?)", locationIds).Where("wms_operation.status = ?", constvar.OperationStatus_Ready).
        Where("wms_operation_details.from_location_id in (?)", locationIds).Where("wms_operation.status = ?", constvar.OperationStatus_Ready).
        Where("wms_operation.base_operation_type in (?)", []constvar.BaseOperationType{constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeInternal, constvar.BaseOperationTypeDisuse}).
        Find(&canUse).Error
    if err != nil {
@@ -160,12 +160,12 @@
    if err != nil {
        return nil, err
    }
    operation.FromLocationID = location.Id
    first, err := models.NewLocationSearch().SetType(int(constvar.LocationTypeCustomer)).First()
    if err != nil {
        return nil, err
    }
    operation.ToLocationID = first.Id
    operation.LocationID = location.Id
    operation.BaseOperationType = constvar.BaseOperationTypeOutgoing
    operation.ReceiverName = req.Addressee
    operation.ReceiverPhone = req.Phone
@@ -179,6 +179,8 @@
            detail.ProductId = product.Id
            amount, _ := decimal.NewFromString(product.Amount)
            detail.Amount = amount
            detail.FromLocationID = location.Id
            detail.ToLocationID = first.Id
            details = append(details, &detail)
        }
        operation.Details = details
@@ -190,6 +192,8 @@
            detail.ProductId = product.Id
            amount, _ := decimal.NewFromString(product.Amount)
            detail.Amount = amount
            detail.FromLocationID = location.Id
            detail.ToLocationID = first.Id
            newOperation.Details = append(newOperation.Details, &detail)
            operations = append(operations, &newOperation)
        }
request/operation.go
@@ -12,22 +12,23 @@
    OperationTypeId   int                      `json:"operationTypeId" gorm:"type:int;not null;comment:作业类型id"`   //作业类型id
    OperationTypeName string                   `json:"operationTypeName" gorm:"type:varchar(127);comment:作业类型名称"` //作业类型名称
    Status            constvar.OperationStatus `json:"status" gorm:"type:int(11);not null;comment:状态"`            //状态
    FromLocationId    int                      `json:"fromLocationId"   gorm:"type:int;not null;comment:源位置id"`   //源位置id
    ToLocationId      int                      `json:"toLocationId"    gorm:"type:int;not null;comment:目标位置id"`   //目标位置id
    OperationDate     string                   `json:"operationDate" gorm:"type:varchar(31);comment:安排日期"`        //安排日期
    Details           []*OperationDetails      `json:"details"`
    ContacterID       int                      `json:"contacterID" gorm:"type:int;comment:联系人ID"`           //联系人ID-非必填
    ContacterName     string                   `json:"contacterName" gorm:"type:varchar(63);comment:联系人姓名"` //联系人姓名-非必填
    CompanyID         int                      `json:"companyID" gorm:"type:int;comment:公司ID"`              //公司ID-客户
    CompanyName       string                   `json:"companyName" gorm:"type:varchar(127);comment:公司名称"`   //公司名称-客户名称
    Comment           string                   `json:"comment" gorm:"type:text;comment:备注"`                 //备注
    LogisticCompanyId string                   `json:"logisticCompanyId"   gorm:"type:varchar(191);comment:物流公司id"`
    WaybillNumber     string                   `json:"waybillNumber" gorm:"type:varchar(255);comment:运单号"`    //运单号
    Weight            decimal.Decimal          `gorm:"type:decimal(20,2);comment:重量" json:"weight"`           //重量
    LogisticWeight    decimal.Decimal          `gorm:"type:decimal(20,2);comment:物流重量" json:"logisticWeight"` //物流重量
    ReceiverName      string                   `json:"receiverName" gorm:"type:varchar(31);comment:收货人姓名"`
    ReceiverPhone     string                   `json:"receiverPhone" gorm:"type:varchar(31);comment:联系电话"`
    ReceiverAddr      string                   `json:"receiverAddr" gorm:"type:varchar(255);comment:收货地址"`
    //FromLocationId    int                      `json:"fromLocationId"   gorm:"type:int;not null;comment:源位置id"`   //源位置id
    //ToLocationId      int                      `json:"toLocationId"    gorm:"type:int;not null;comment:目标位置id"`   //目标位置id
    OperationDate     string              `json:"operationDate" gorm:"type:varchar(31);comment:安排日期"` //安排日期
    Details           []*OperationDetails `json:"details"`
    ContacterID       int                 `json:"contacterID" gorm:"type:int;comment:联系人ID"`           //联系人ID-非必填
    ContacterName     string              `json:"contacterName" gorm:"type:varchar(63);comment:联系人姓名"` //联系人姓名-非必填
    CompanyID         int                 `json:"companyID" gorm:"type:int;comment:公司ID"`              //公司ID-客户
    CompanyName       string              `json:"companyName" gorm:"type:varchar(127);comment:公司名称"`   //公司名称-客户名称
    Comment           string              `json:"comment" gorm:"type:text;comment:备注"`                 //备注
    LogisticCompanyId string              `json:"logisticCompanyId"   gorm:"type:varchar(191);comment:物流公司id"`
    WaybillNumber     string              `json:"waybillNumber" gorm:"type:varchar(255);comment:运单号"`    //运单号
    Weight            decimal.Decimal     `gorm:"type:decimal(20,2);comment:重量" json:"weight"`           //重量
    LogisticWeight    decimal.Decimal     `gorm:"type:decimal(20,2);comment:物流重量" json:"logisticWeight"` //物流重量
    ReceiverName      string              `json:"receiverName" gorm:"type:varchar(31);comment:收货人姓名"`
    ReceiverPhone     string              `json:"receiverPhone" gorm:"type:varchar(31);comment:联系电话"`
    ReceiverAddr      string              `json:"receiverAddr" gorm:"type:varchar(255);comment:收货地址"`
    LocationId        int                 `json:"locationId"   gorm:"type:int;not null;comment:源位置id"` //源位置id
}
type OperationDetails struct {
@@ -37,6 +38,8 @@
    Amount decimal.Decimal `json:"amount" gorm:"type:decimal(20,2);not null;comment:数量"` //数量
    //Unit        string          `json:"unit" gorm:"type:varchar(31);comment:单位"`                    //单位
    //Product models.Material `json:"product" gorm:"foreignKey:ProductId;references:ID"`
    FromLocationId int `json:"fromLocationId"   gorm:"type:int;not null;comment:源位置id"` //源位置id
    ToLocationId   int `json:"toLocationId"    gorm:"type:int;not null;comment:目标位置id"` //目标位置id
}
type OperationList struct {
@@ -47,15 +50,15 @@
}
type UpdateOperation struct {
    ID                int                        `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"`
    Number            string                     `json:"number" gorm:"column:number;type:varchar(255)"`             //单号
    SourceNumber      string                     `json:"sourceNumber" gorm:"type:varchar(255)"`                     //源单号
    OperationTypeId   int                        `json:"operationTypeId" gorm:"type:int;not null;comment:作业类型id"`   //作业类型id
    OperationTypeName string                     `json:"operationTypeName" gorm:"type:varchar(127);comment:作业类型名称"` //作业类型名称
    Status            constvar.OperationStatus   `json:"status" gorm:"type:int(11);not null;comment:状态"`            //状态
    FromLocationId    int                        `json:"fromLocationId"   gorm:"type:int;not null;comment:源位置id"`   //源位置id
    ToLocationId      int                        `json:"toLocationId"    gorm:"type:int;not null;comment:目标位置id"`   //目标位置id
    OperationDate     string                     `json:"operationDate" gorm:"type:varchar(31);comment:安排日期"`        //安排日期
    ID                int                      `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"`
    Number            string                   `json:"number" gorm:"column:number;type:varchar(255)"`             //单号
    SourceNumber      string                   `json:"sourceNumber" gorm:"type:varchar(255)"`                     //源单号
    OperationTypeId   int                      `json:"operationTypeId" gorm:"type:int;not null;comment:作业类型id"`   //作业类型id
    OperationTypeName string                   `json:"operationTypeName" gorm:"type:varchar(127);comment:作业类型名称"` //作业类型名称
    Status            constvar.OperationStatus `json:"status" gorm:"type:int(11);not null;comment:状态"`            //状态
    //FromLocationId    int                        `json:"fromLocationId"   gorm:"type:int;not null;comment:源位置id"`   //源位置id
    //ToLocationId      int                        `json:"toLocationId"    gorm:"type:int;not null;comment:目标位置id"`   //目标位置id
    OperationDate     string                     `json:"operationDate" gorm:"type:varchar(31);comment:安排日期"` //安排日期
    Details           []*OperationDetails        `json:"details"`
    ContacterID       int                        `json:"contacterID" gorm:"type:int;comment:联系人ID"`           //联系人ID-非必填
    ContacterName     string                     `json:"contacterName" gorm:"type:varchar(63);comment:联系人姓名"` //联系人姓名-非必填
@@ -70,6 +73,7 @@
    ReceiverName      string                     `json:"receiverName" gorm:"type:varchar(31);comment:收货人姓名"`
    ReceiverPhone     string                     `json:"receiverPhone" gorm:"type:varchar(31);comment:联系电话"`
    ReceiverAddr      string                     `json:"receiverAddr" gorm:"type:varchar(255);comment:收货地址"`
    LocationId        int                        `json:"locationId"   gorm:"type:int;not null;comment:源位置id"` //源位置id
}
type OperationAllList struct {