package product_inventory import ( "context" "errors" "github.com/shopspring/decimal" "strconv" "time" "wms/constvar" "wms/models" "wms/pkg/timex" "wms/service" ) type Server struct { UnimplementedProductInventoryServiceServer } type ProductAndLocationInfo struct { ProductId string `json:"productId"` Amount decimal.Decimal `json:"amount"` LocationId int `json:"locationId"` FromLocationId int `json:"fromLocationId"` ToLocationId int `json:"toLocationId"` Number string `json:"number"` WaybillNumber string `json:"waybillNumber"` Name string `json:"name"` } func (s *Server) GetInventoryProductInfo(ctx context.Context, req *GetInventoryProductInfoRequest) (*GetInventoryProductInfoResponse, error) { if req.Number == "" { return nil, errors.New("参数不能为空") } //查询产品id var details []ProductAndLocationInfo var productIds []string resp := new(GetInventoryProductInfoResponse) search := models.NewOperationDetailsSearch().Orm.Model(&models.OperationDetails{}). Select("wms_operation_details.product_id,wms_operation_details.amount,wms_operation_details.from_location_id,wms_operation_details.to_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) if req.IsInput { search.Where("wms_operation.base_operation_type = ?", constvar.BaseOperationTypeIncoming) } if req.IsOutput { search.Where("wms_operation.base_operation_type = ?", constvar.BaseOperationTypeOutgoing) } err := search.Find(&details).Error if err != nil { return nil, err } if len(details) == 0 { return resp, nil } var locationIds []int var locationId int for _, detail := range details { productIds = append(productIds, detail.ProductId) if req.IsInput { //只查入库 locationIds = append(locationIds, detail.ToLocationId) } else if req.IsOutput { //只查出库 locationIds = append(locationIds, detail.FromLocationId) } locationId = detail.FromLocationId } //查询产品信息 materials, err := models.NewMaterialSearch().SetIDs(productIds).FindNotTotal() if err != nil { return nil, err } locationHouseMap, houseLocations, houseMap, err := service.GetWarehouseByLocationIds(locationIds) if err != nil { return nil, err } warehouse := locationHouseMap[locationId] amounts, err := models.NewLocationProductAmountSearch().SetProductIds(productIds).SetLocationIds(locationIds).SetPreload(true).Find() if err != nil { return nil, err } var inventory []ProductAndLocationInfo for _, productAmount := range amounts { var in ProductAndLocationInfo in.ProductId = productAmount.ProductId in.Amount = productAmount.Amount inventory = append(inventory, in) } //统计可用数量 var canUse []ProductAndLocationInfo err = models.NewOperationDetailsSearch().Orm.Model(&models.OperationDetails{}). 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_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 { return nil, err } products := make([]*ProductInfo, 0) for _, material := range materials { var p ProductInfo p.Number = material.ID p.Name = material.Name for _, detail := range details { 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 } } p.Unit = material.Unit p.SalePrice = material.SalePrice.String() p.Warehouse = warehouse.Name at := decimal.NewFromInt(0) for _, info := range inventory { if material.ID == info.ProductId { at = at.Add(info.Amount) } } p.Amount = at.String() cu := decimal.NewFromInt(0) for _, info := range canUse { if material.ID == info.ProductId { cu = cu.Add(info.Amount) } } cu = at.Sub(cu) p.AvailableNumber = cu.String() products = append(products, &p) } resp.ProductList = products if req.GroupByWarehouse { canUseMap := make(map[int]map[string]decimal.Decimal) //map[locationID]map[productID]decimal for _, v := range canUse { if canUseMap[v.LocationId] == nil { canUseMap[v.LocationId] = make(map[string]decimal.Decimal) } canUseMap[v.LocationId][v.ProductId] = canUseMap[v.LocationId][v.ProductId].Add(v.Amount) } locationProductAmounts := make(map[int][]*models.LocationProductAmount) for _, v := range amounts { if locationProductAmounts[v.LocationId] == nil { locationProductAmounts[v.LocationId] = make([]*models.LocationProductAmount, 0) } locationProductAmounts[v.LocationId] = append(locationProductAmounts[v.LocationId], v) } materialMap := service.MaterialMap(materials) var warehouseProductsList []*WarehouseProducts for houseID, locationIDs := range houseLocations { house := houseMap[houseID] productAmountMap := make(map[string]decimal.Decimal, 0) productAvailableNumberMap := make(map[string]decimal.Decimal, 0) productInfoList := make([]*ProductInfo, 0) houseProductAmounts := make([]*models.LocationProductAmount, 0) for _, lid := range locationIDs { houseProductAmounts = append(houseProductAmounts, locationProductAmounts[lid]...) } for _, v := range houseProductAmounts { productAmountMap[v.ProductId] = productAmountMap[v.ProductId].Add(v.Amount) productAvailableNumberMap[v.ProductId] = productAvailableNumberMap[v.ProductId].Add(canUseMap[v.LocationId][v.ProductId]) } for productID, amount := range productAvailableNumberMap { productInfoList = append(productInfoList, &ProductInfo{ Number: productID, Name: materialMap[productID].Name, Unit: materialMap[productID].Unit, Amount: productAmountMap[productID].String(), AvailableNumber: amount.String(), }) } warehouseProducts := &WarehouseProducts{ WarehouseID: house.Code, WarehouseName: house.Name, ProductList: productInfoList, } warehouseProductsList = append(warehouseProductsList, warehouseProducts) } resp.WarehouseProductsList = warehouseProductsList } return resp, nil } func (s *Server) CreateOperation(ctx context.Context, req *CreateOperationRequest) (*CreateOperationResponse, error) { var operations []*models.Operation var operation models.Operation var details []*models.OperationDetails operation.SourceNumber = req.Number operation.OperationDate = timex.TimeToString2(time.Now()) operation.Number = strconv.FormatInt(time.Now().Unix(), 10) operation.Status = constvar.OperationStatus_Ready warehouse, err := models.NewWarehouseSearch().First() if err != nil { return nil, err } operationType, err := models.NewOperationTypeSearch().SetWarehouseId(warehouse.Id).SetBaseOperationType(constvar.BaseOperationTypeOutgoing).First() if err != nil { return nil, err } operation.OperationTypeName = operationType.Name operation.OperationTypeId = operationType.Id location, err := models.NewLocationSearch().SetID(warehouse.LocationId).First() if err != nil { return nil, err } first, err := models.NewLocationSearch().SetType(int(constvar.LocationTypeCustomer)).First() if err != nil { return nil, err } operation.LocationID = location.Id operation.BaseOperationType = constvar.BaseOperationTypeOutgoing operation.ReceiverName = req.Addressee operation.ReceiverPhone = req.Phone operation.ReceiverAddr = req.Address operation.Source = req.Source operation.CompanyID = int(req.ClientId) operation.CompanyName = req.ClientName if req.DeliverType == 1 { for _, product := range req.ProductList { var detail models.OperationDetails 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 operations = append(operations, &operation) } else { for _, product := range req.ProductList { newOperation := operation var detail models.OperationDetails 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) } } err = models.NewOperationSearch().CreateBatch(operations) resp := new(CreateOperationResponse) return resp, err }