jiangshuai
2023-11-13 f16252d8b4736a0212b14a2bfb0eeee411d0cc76
Merge branch 'master' of http://192.168.5.5:10010/r/aps/WMS
13个文件已修改
408 ■■■■■ 已修改文件
conf/config.go 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
conf/config.yaml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/operation.go 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/reorder_rule_controller.go 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/report_forms_controller.go 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/docs.go 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/swagger.json 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/swagger.yaml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main.go 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
proto/product_inventory.proto 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
proto/product_inventory/product_inventory.pb.go 197 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
proto/product_inventory/product_inventory_grpc.pb.go 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
proto/product_inventory/server.go 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
conf/config.go
@@ -39,6 +39,7 @@
    grpcServerConf struct {
        ApsAddr string //aps服务grpc地址
        CrmAddr string //crm服务grpc地址
    }
)
@@ -67,6 +68,7 @@
    host := os.Getenv("HOST")         // 本机IP地址
    GrpcPort := os.Getenv("WMS_GRPC") // 只对外提供grpc服务,本服务不用
    apsAddr := os.Getenv("APS_GRPC")
    crmAddr := os.Getenv("CRM_GRPC")
    if len(GrpcPort) > 0 {
        WebConf.GrpcPort = GrpcPort
    }
@@ -79,6 +81,9 @@
    if len(apsAddr) > 0 {
        GrpcServerConf.ApsAddr = apsAddr
    }
    if len(crmAddr) > 0 {
        GrpcServerConf.CrmAddr = crmAddr
    }
    DBHost := os.Getenv("DB_HOST")
    DBName := os.Getenv("DB_NAME")
conf/config.yaml
@@ -25,3 +25,4 @@
  storePath: uploads/file
grpcServer:
  apsAddr: 192.168.20.119:9091
  crmAddr: 192.168.20.118:9092
controllers/operation.go
@@ -1,16 +1,20 @@
package controllers
import (
    "context"
    "encoding/json"
    "errors"
    "fmt"
    "github.com/gin-gonic/gin"
    "github.com/shopspring/decimal"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    "gorm.io/gorm"
    "os"
    "sort"
    "strconv"
    "time"
    "wms/conf"
    "wms/constvar"
    "wms/extend/code"
    "wms/extend/util"
@@ -18,6 +22,7 @@
    "wms/opa"
    "wms/pkg/logx"
    "wms/pkg/structx"
    "wms/proto/product_inventory"
    "wms/request"
)
@@ -679,9 +684,40 @@
        util.ResponseFormat(c, code.RequestError, err.Error())
        return
    }
    if operation.SourceNumber != "" {
        go UpdateSalesDetailStatus(operation.SourceNumber)
    }
    util.ResponseFormat(c, code.Success, "操作成功")
}
var ProductInventoryServiceConn *grpc.ClientConn
func InitProductInventoryServiceConn() {
    var err error
    ProductInventoryServiceConn, err = grpc.Dial(conf.GrpcServerConf.CrmAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        logx.Errorf("grpc dial product service error: %v", err.Error())
        return
    }
}
func CloseProductInventoryServiceConn() {
    if ProductInventoryServiceConn != nil {
        ProductInventoryServiceConn.Close()
    }
}
func UpdateSalesDetailStatus(number string) {
    client := product_inventory.NewProductInventoryServiceClient(ProductInventoryServiceConn)
    _, err := client.UpdateSalesDetailStatus(context.Background(), &product_inventory.UpdateSalesDetailStatusRequest{
        Number:            number,
        SalesDetailStatus: "已出库",
    })
    if err != nil {
        logx.Errorf("grpc dial UpdateSalesDetailStatus service error: %v", err)
    }
}
// ListTransfer
// @Tags      入库/出库
// @Summary   库存调拨列表
controllers/reorder_rule_controller.go
@@ -119,7 +119,7 @@
        rule.Prediction = rule.Amount.Add(rule.Prediction)
    }
    //出库就绪
    operationType = []constvar.BaseOperationType{constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeInternal}
    operationType = []constvar.BaseOperationType{constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeInternal, constvar.BaseOperationTypeDisuse}
    amount, err = GetProductAmount(productIds, nil, locationIds, status, operationType)
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "查询重订货规则列表失败")
@@ -221,7 +221,7 @@
    }
    prediction = amount.Add(prediction)
    //出库就绪
    operationType = []constvar.BaseOperationType{constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeInternal}
    operationType = []constvar.BaseOperationType{constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeInternal, constvar.BaseOperationTypeDisuse}
    list, err = GetProductAmount(productIds, nil, locationIds, status, operationType)
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "查询重订货规则列表失败")
controllers/report_forms_controller.go
@@ -3,6 +3,7 @@
import (
    "fmt"
    "github.com/gin-gonic/gin"
    "github.com/shopspring/decimal"
    "wms/constvar"
    "wms/extend/code"
    "wms/extend/util"
@@ -12,6 +13,13 @@
)
type ReportFormsController struct {
}
type Detail struct {
    ProductId string                   `json:"productId"`
    Amount    decimal.Decimal          `json:"amount"`
    Status    constvar.OperationStatus `json:"status"`
    //ProductName string                   `json:"productName"`
}
// GetInventoryForms
@@ -54,7 +62,6 @@
        return
    }
    //查询出入库数量
    locations, err := models.NewLocationSearch().SetJointName(params.WarehouseCode).FindNotTotal()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "查询仓库位置失败")
@@ -64,19 +71,37 @@
    for _, location := range locations {
        locationIds = append(locationIds, location.Id)
    }
    var inHouse []models.OperationDetails
    var outHouse []models.OperationDetails
    //查询在库数量
    productIds := make([]string, 0)
    for _, material := range materials {
        productIds = append(productIds, material.ID)
    }
    productAmounts, err := models.NewLocationProductAmountSearch().SetProductIds(productIds).SetLocationIds(locationIds).Find()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "查询在库数量失败")
        return
    }
    //查询出入库就绪数量
    var inHouse []Detail
    var outHouse []Detail
    dbIn := models.NewOperationDetailsSearch().Orm.Model(&models.OperationDetails{}).
        Select("wms_operation_details.product_id,wms_operation_details.amount,wms_operation.status as status").
        Joins("left join wms_operation ON wms_operation_details.operation_id=wms_operation.id").
        Where("wms_operation.base_operation_type=?", constvar.BaseOperationTypeIncoming).
        Where("wms_operation.status = ?", constvar.OperationStatus_Finish)
        Where("wms_operation.base_operation_type in (?)", []constvar.BaseOperationType{constvar.BaseOperationTypeIncoming, constvar.BaseOperationTypeInternal}).
        Where("wms_operation.status in (?)", []constvar.OperationStatus{constvar.OperationStatus_Finish})
    dbOut := models.NewOperationDetailsSearch().Orm.Model(&models.OperationDetails{}).
        Select("wms_operation_details.product_id,wms_operation_details.amount,wms_operation.status as status").
        Joins("left join wms_operation ON wms_operation_details.operation_id=wms_operation.id").
        Where("wms_operation.base_operation_type in (?)", []int{2, 4}).
        Where("wms_operation.status = ?", constvar.OperationStatus_Finish)
        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)
    }
    if len(productIds) > 0 {
        dbIn.Where("wms_operation_details.product_id in (?)", productIds)
        dbOut.Where("wms_operation_details.product_id in (?)", productIds)
    }
    err = dbIn.Find(&inHouse).Error
    if err != nil {
@@ -97,18 +122,27 @@
        resp.Unit = material.Unit
        resp.Value = material.Amount.Mul(material.Cost)
        resp.ProductType = material.CategoryName
        for _, amount := range productAmounts {
            if material.ID == amount.ProductId {
                resp.Amount = resp.Amount.Add(amount.Amount)
            }
        }
        for _, details := range inHouse {
            if material.ID == details.ProductId {
                resp.In = resp.In.Add(details.Amount)
            }
        }
        available := decimal.NewFromInt(0)
        for _, details := range outHouse {
            if material.ID == details.ProductId {
                resp.Out = resp.Out.Add(details.Amount)
                if details.Status == constvar.OperationStatus_Ready {
                    available = available.Add(details.Amount)
                } else {
                    resp.Out = resp.Out.Add(details.Amount)
                }
            }
        }
        resp.Amount = resp.In.Sub(resp.Out)
        resp.AvailableNumber = resp.Amount
        resp.AvailableNumber = resp.Amount.Sub(available)
        result = append(result, resp)
    }
    util.ResponseFormatList(c, code.Success, result, int(total))
docs/docs.go
@@ -3996,6 +3996,13 @@
                "id": {
                    "type": "integer"
                },
                "logisticCompanyId": {
                    "type": "string"
                },
                "logisticWeight": {
                    "description": "物流重量",
                    "type": "number"
                },
                "number": {
                    "description": "单号",
                    "type": "string"
@@ -4027,6 +4034,14 @@
                "toLocationId": {
                    "description": "目标位置id",
                    "type": "integer"
                },
                "waybillNumber": {
                    "description": "运单号",
                    "type": "string"
                },
                "weight": {
                    "description": "重量",
                    "type": "number"
                }
            }
        },
docs/swagger.json
@@ -3984,6 +3984,13 @@
                "id": {
                    "type": "integer"
                },
                "logisticCompanyId": {
                    "type": "string"
                },
                "logisticWeight": {
                    "description": "物流重量",
                    "type": "number"
                },
                "number": {
                    "description": "单号",
                    "type": "string"
@@ -4015,6 +4022,14 @@
                "toLocationId": {
                    "description": "目标位置id",
                    "type": "integer"
                },
                "waybillNumber": {
                    "description": "运单号",
                    "type": "string"
                },
                "weight": {
                    "description": "重量",
                    "type": "number"
                }
            }
        },
docs/swagger.yaml
@@ -1267,6 +1267,11 @@
        type: integer
      id:
        type: integer
      logisticCompanyId:
        type: string
      logisticWeight:
        description: 物流重量
        type: number
      number:
        description: 单号
        type: string
@@ -1289,6 +1294,12 @@
      toLocationId:
        description: 目标位置id
        type: integer
      waybillNumber:
        description: 运单号
        type: string
      weight:
        description: 重量
        type: number
    type: object
  request.UpdateOperationType:
    properties:
main.go
@@ -45,6 +45,7 @@
    go shutdown(server)
    //启动grpc客户端
    go controllers.InitInventoryOrderServiceConn()
    go controllers.InitProductInventoryServiceConn()
    //启动grpc服务
    go func() {
        ln, err := net.Listen("tcp", ":"+conf.WebConf.GrpcPort)
@@ -76,6 +77,7 @@
    defer cancel()
    controllers.CloseInventoryOrderServiceConn()
    controllers.CloseProductInventoryServiceConn()
    // 关闭HTTP服务器
    if err := server.Shutdown(ctx); err != nil {
        logx.Infof("服务优雅退出失败: %v", err)
proto/product_inventory.proto
@@ -5,6 +5,7 @@
service productInventoryService {
  rpc CreateOperation(CreateOperationRequest) returns(CreateOperationResponse) {}
  rpc GetInventoryProductInfo(GetInventoryProductInfoRequest) returns (GetInventoryProductInfoResponse) {}
  rpc UpdateSalesDetailStatus(UpdateSalesDetailStatusRequest) returns (UpdateSalesDetailStatusResponse) {}
}
message CreateOperationRequest{
@@ -51,4 +52,16 @@
  int32   Code = 1;
  string  Msg = 2;
  repeated ProductInfo ProductList = 3;
}
//------------------------------------------------------------
message UpdateSalesDetailStatusRequest {
  string Number = 1;//明细单编码
  string SalesDetailStatus = 2;
}
message UpdateSalesDetailStatusResponse{
  int32   Code = 1;
  string  Msg = 2;
}
proto/product_inventory/product_inventory.pb.go
@@ -462,6 +462,116 @@
    return nil
}
type UpdateSalesDetailStatusRequest struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields
    Number            string `protobuf:"bytes,1,opt,name=Number,proto3" json:"Number,omitempty"` //明细单编码
    SalesDetailStatus string `protobuf:"bytes,2,opt,name=SalesDetailStatus,proto3" json:"SalesDetailStatus,omitempty"`
}
func (x *UpdateSalesDetailStatusRequest) Reset() {
    *x = UpdateSalesDetailStatusRequest{}
    if protoimpl.UnsafeEnabled {
        mi := &file_product_inventory_proto_msgTypes[6]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}
func (x *UpdateSalesDetailStatusRequest) String() string {
    return protoimpl.X.MessageStringOf(x)
}
func (*UpdateSalesDetailStatusRequest) ProtoMessage() {}
func (x *UpdateSalesDetailStatusRequest) ProtoReflect() protoreflect.Message {
    mi := &file_product_inventory_proto_msgTypes[6]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}
// Deprecated: Use UpdateSalesDetailStatusRequest.ProtoReflect.Descriptor instead.
func (*UpdateSalesDetailStatusRequest) Descriptor() ([]byte, []int) {
    return file_product_inventory_proto_rawDescGZIP(), []int{6}
}
func (x *UpdateSalesDetailStatusRequest) GetNumber() string {
    if x != nil {
        return x.Number
    }
    return ""
}
func (x *UpdateSalesDetailStatusRequest) GetSalesDetailStatus() string {
    if x != nil {
        return x.SalesDetailStatus
    }
    return ""
}
type UpdateSalesDetailStatusResponse struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields
    Code int32  `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"`
    Msg  string `protobuf:"bytes,2,opt,name=Msg,proto3" json:"Msg,omitempty"`
}
func (x *UpdateSalesDetailStatusResponse) Reset() {
    *x = UpdateSalesDetailStatusResponse{}
    if protoimpl.UnsafeEnabled {
        mi := &file_product_inventory_proto_msgTypes[7]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}
func (x *UpdateSalesDetailStatusResponse) String() string {
    return protoimpl.X.MessageStringOf(x)
}
func (*UpdateSalesDetailStatusResponse) ProtoMessage() {}
func (x *UpdateSalesDetailStatusResponse) ProtoReflect() protoreflect.Message {
    mi := &file_product_inventory_proto_msgTypes[7]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}
// Deprecated: Use UpdateSalesDetailStatusResponse.ProtoReflect.Descriptor instead.
func (*UpdateSalesDetailStatusResponse) Descriptor() ([]byte, []int) {
    return file_product_inventory_proto_rawDescGZIP(), []int{7}
}
func (x *UpdateSalesDetailStatusResponse) GetCode() int32 {
    if x != nil {
        return x.Code
    }
    return 0
}
func (x *UpdateSalesDetailStatusResponse) GetMsg() string {
    if x != nil {
        return x.Msg
    }
    return ""
}
var File_product_inventory_proto protoreflect.FileDescriptor
var file_product_inventory_proto_rawDesc = []byte{
@@ -520,21 +630,38 @@
    0x67, 0x12, 0x2e, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74,
    0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74,
    0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73,
    0x74, 0x32, 0xc1, 0x01, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x76,
    0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x46, 0x0a,
    0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
    0x12, 0x17, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
    0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x43, 0x72, 0x65, 0x61,
    0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
    0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65,
    0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f,
    0x12, 0x1f, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50,
    0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
    0x74, 0x1a, 0x20, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79,
    0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f,
    0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x15, 0x5a, 0x13, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75,
    0x63, 0x74, 0x5f, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72,
    0x6f, 0x74, 0x6f, 0x33,
    0x74, 0x22, 0x66, 0x0a, 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73,
    0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75,
    0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20,
    0x01, 0x28, 0x09, 0x52, 0x06, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x11, 0x53,
    0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
    0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74,
    0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x47, 0x0a, 0x1f, 0x55, 0x70, 0x64,
    0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74,
    0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04,
    0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65,
    0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d,
    0x73, 0x67, 0x32, 0xa1, 0x02, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e,
    0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x46,
    0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
    0x6e, 0x12, 0x17, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
    0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x43, 0x72, 0x65,
    0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
    0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76,
    0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66,
    0x6f, 0x12, 0x1f, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79,
    0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65,
    0x73, 0x74, 0x1a, 0x20, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72,
    0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70,
    0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
    0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75,
    0x73, 0x12, 0x1f, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44,
    0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
    0x73, 0x74, 0x1a, 0x20, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73,
    0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70,
    0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x15, 0x5a, 0x13, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x64,
    0x75, 0x63, 0x74, 0x5f, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70,
    0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -549,7 +676,7 @@
    return file_product_inventory_proto_rawDescData
}
var file_product_inventory_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_product_inventory_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_product_inventory_proto_goTypes = []interface{}{
    (*CreateOperationRequest)(nil),          // 0: CreateOperationRequest
    (*InventoryProduct)(nil),                // 1: InventoryProduct
@@ -557,16 +684,20 @@
    (*GetInventoryProductInfoRequest)(nil),  // 3: GetInventoryProductInfoRequest
    (*ProductInfo)(nil),                     // 4: ProductInfo
    (*GetInventoryProductInfoResponse)(nil), // 5: GetInventoryProductInfoResponse
    (*UpdateSalesDetailStatusRequest)(nil),  // 6: UpdateSalesDetailStatusRequest
    (*UpdateSalesDetailStatusResponse)(nil), // 7: UpdateSalesDetailStatusResponse
}
var file_product_inventory_proto_depIdxs = []int32{
    1, // 0: CreateOperationRequest.ProductList:type_name -> InventoryProduct
    4, // 1: GetInventoryProductInfoResponse.ProductList:type_name -> ProductInfo
    0, // 2: productInventoryService.CreateOperation:input_type -> CreateOperationRequest
    3, // 3: productInventoryService.GetInventoryProductInfo:input_type -> GetInventoryProductInfoRequest
    2, // 4: productInventoryService.CreateOperation:output_type -> CreateOperationResponse
    5, // 5: productInventoryService.GetInventoryProductInfo:output_type -> GetInventoryProductInfoResponse
    4, // [4:6] is the sub-list for method output_type
    2, // [2:4] is the sub-list for method input_type
    6, // 4: productInventoryService.UpdateSalesDetailStatus:input_type -> UpdateSalesDetailStatusRequest
    2, // 5: productInventoryService.CreateOperation:output_type -> CreateOperationResponse
    5, // 6: productInventoryService.GetInventoryProductInfo:output_type -> GetInventoryProductInfoResponse
    7, // 7: productInventoryService.UpdateSalesDetailStatus:output_type -> UpdateSalesDetailStatusResponse
    5, // [5:8] is the sub-list for method output_type
    2, // [2:5] is the sub-list for method input_type
    2, // [2:2] is the sub-list for extension type_name
    2, // [2:2] is the sub-list for extension extendee
    0, // [0:2] is the sub-list for field type_name
@@ -650,6 +781,30 @@
                return nil
            }
        }
        file_product_inventory_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*UpdateSalesDetailStatusRequest); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
        file_product_inventory_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*UpdateSalesDetailStatusResponse); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
    }
    type x struct{}
    out := protoimpl.TypeBuilder{
@@ -657,7 +812,7 @@
            GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
            RawDescriptor: file_product_inventory_proto_rawDesc,
            NumEnums:      0,
            NumMessages:   6,
            NumMessages:   8,
            NumExtensions: 0,
            NumServices:   1,
        },
proto/product_inventory/product_inventory_grpc.pb.go
@@ -20,6 +20,7 @@
type ProductInventoryServiceClient interface {
    CreateOperation(ctx context.Context, in *CreateOperationRequest, opts ...grpc.CallOption) (*CreateOperationResponse, error)
    GetInventoryProductInfo(ctx context.Context, in *GetInventoryProductInfoRequest, opts ...grpc.CallOption) (*GetInventoryProductInfoResponse, error)
    UpdateSalesDetailStatus(ctx context.Context, in *UpdateSalesDetailStatusRequest, opts ...grpc.CallOption) (*UpdateSalesDetailStatusResponse, error)
}
type productInventoryServiceClient struct {
@@ -48,12 +49,22 @@
    return out, nil
}
func (c *productInventoryServiceClient) UpdateSalesDetailStatus(ctx context.Context, in *UpdateSalesDetailStatusRequest, opts ...grpc.CallOption) (*UpdateSalesDetailStatusResponse, error) {
    out := new(UpdateSalesDetailStatusResponse)
    err := c.cc.Invoke(ctx, "/productInventoryService/UpdateSalesDetailStatus", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}
// ProductInventoryServiceServer is the server API for ProductInventoryService service.
// All implementations must embed UnimplementedProductInventoryServiceServer
// for forward compatibility
type ProductInventoryServiceServer interface {
    CreateOperation(context.Context, *CreateOperationRequest) (*CreateOperationResponse, error)
    GetInventoryProductInfo(context.Context, *GetInventoryProductInfoRequest) (*GetInventoryProductInfoResponse, error)
    UpdateSalesDetailStatus(context.Context, *UpdateSalesDetailStatusRequest) (*UpdateSalesDetailStatusResponse, error)
    mustEmbedUnimplementedProductInventoryServiceServer()
}
@@ -66,6 +77,9 @@
}
func (UnimplementedProductInventoryServiceServer) GetInventoryProductInfo(context.Context, *GetInventoryProductInfoRequest) (*GetInventoryProductInfoResponse, error) {
    return nil, status.Errorf(codes.Unimplemented, "method GetInventoryProductInfo not implemented")
}
func (UnimplementedProductInventoryServiceServer) UpdateSalesDetailStatus(context.Context, *UpdateSalesDetailStatusRequest) (*UpdateSalesDetailStatusResponse, error) {
    return nil, status.Errorf(codes.Unimplemented, "method UpdateSalesDetailStatus not implemented")
}
func (UnimplementedProductInventoryServiceServer) mustEmbedUnimplementedProductInventoryServiceServer() {
}
@@ -117,6 +131,24 @@
    return interceptor(ctx, in, info, handler)
}
func _ProductInventoryService_UpdateSalesDetailStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(UpdateSalesDetailStatusRequest)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(ProductInventoryServiceServer).UpdateSalesDetailStatus(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/productInventoryService/UpdateSalesDetailStatus",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(ProductInventoryServiceServer).UpdateSalesDetailStatus(ctx, req.(*UpdateSalesDetailStatusRequest))
    }
    return interceptor(ctx, in, info, handler)
}
// ProductInventoryService_ServiceDesc is the grpc.ServiceDesc for ProductInventoryService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -132,6 +164,10 @@
            MethodName: "GetInventoryProductInfo",
            Handler:    _ProductInventoryService_GetInventoryProductInfo_Handler,
        },
        {
            MethodName: "UpdateSalesDetailStatus",
            Handler:    _ProductInventoryService_UpdateSalesDetailStatus_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "product_inventory.proto",
proto/product_inventory/server.go
@@ -17,9 +17,12 @@
}
type ProductAndLocationInfo struct {
    ProductId  string          `json:"productId"`
    Amount     decimal.Decimal `json:"amount"`
    LocationId int             `json:"locationId"`
    ProductId     string          `json:"productId"`
    Amount        decimal.Decimal `json:"amount"`
    LocationId    int             `json:"locationId"`
    Number        string          `json:"number"`
    WaybillNumber string          `json:"waybillNumber"`
    Name          string          `json:"name"`
}
func (s *Server) GetInventoryProductInfo(ctx context.Context, req *GetInventoryProductInfoRequest) (*GetInventoryProductInfoResponse, error) {
@@ -31,8 +34,10 @@
    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.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").
        Where("wms_operation.source_number = ?", req.Number).Find(&details).Error
    if err != nil {
        return nil, err
@@ -88,7 +93,7 @@
        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.base_operation_type in (?)", []constvar.BaseOperationType{constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeInternal}).
        Where("wms_operation.base_operation_type in (?)", []constvar.BaseOperationType{constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeInternal, constvar.BaseOperationTypeDisuse}).
        Find(&canUse).Error
    if err != nil {
        return nil, err
@@ -102,6 +107,9 @@
            if material.ID == detail.ProductId {
                p.OrderAmount = detail.Amount.String()
                p.Valorem = detail.Amount.Mul(material.SalePrice).String()
                p.Invoice = detail.Number
                p.Carrier = detail.Name
                p.Waybill = detail.WaybillNumber
                break
            }
        }
@@ -121,6 +129,7 @@
                cu = cu.Add(info.Amount)
            }
        }
        cu = at.Sub(cu)
        p.AvailableNumber = cu.String()
        products = append(products, &p)