@Override
  @Transactional
  public void updateResourcesForReleaseDocuments(final Entity document) {
    Entity warehouse = document.getBelongsToField(DocumentFields.LOCATION_FROM);
    WarehouseAlgorithm warehouseAlgorithm;

    boolean enoughResources = true;

    StringBuilder errorMessage = new StringBuilder();

    Multimap<Long, BigDecimal> quantitiesForWarehouse =
        getQuantitiesInWarehouse(warehouse, getProductsAndPositionsFromDocument(document));

    List<Entity> generatedPositions = Lists.newArrayList();

    for (Entity position : document.getHasManyField(DocumentFields.POSITIONS)) {
      Entity product = position.getBelongsToField(PositionFields.PRODUCT);
      Entity resource = position.getBelongsToField(PositionFields.RESOURCE);

      BigDecimal quantityInWarehouse;

      if (resource != null) {
        warehouse = resource.getBelongsToField(ResourceFields.LOCATION);
        warehouseAlgorithm = WarehouseAlgorithm.MANUAL;
      } else {
        warehouse = document.getBelongsToField(DocumentFields.LOCATION_FROM);
        warehouseAlgorithm =
            WarehouseAlgorithm.parseString(warehouse.getStringField(LocationFieldsMFR.ALGORITHM));
      }

      if (warehouseAlgorithm.equals(WarehouseAlgorithm.MANUAL)) {
        quantityInWarehouse = getQuantityOfProductInWarehouse(warehouse, product, position);
      } else {
        quantityInWarehouse = getQuantityOfProductFromMultimap(quantitiesForWarehouse, product);
      }

      generatedPositions.addAll(updateResources(warehouse, position, warehouseAlgorithm));

      enoughResources = enoughResources && position.isValid();

      if (!position.isValid()) {
        BigDecimal quantity = position.getDecimalField(QUANTITY);

        errorMessage.append(product.getStringField(ProductFields.NAME));
        errorMessage.append(" - ");
        errorMessage.append(numberService.format(quantity.subtract(quantityInWarehouse)));
        errorMessage.append(" ");
        errorMessage.append(product.getStringField(ProductFields.UNIT));
        errorMessage.append(", ");
      }
    }

    if (!enoughResources) {
      addDocumentError(document, warehouse, errorMessage);
    } else {
      deleteReservations(document);
      document.setField(DocumentFields.POSITIONS, generatedPositions);
    }
  }
  @Override
  @Transactional
  public void moveResourcesForTransferDocument(Entity document) {
    Entity warehouseFrom = document.getBelongsToField(DocumentFields.LOCATION_FROM);
    Entity warehouseTo = document.getBelongsToField(DocumentFields.LOCATION_TO);
    Object date = document.getField(DocumentFields.TIME);

    WarehouseAlgorithm warehouseAlgorithm =
        WarehouseAlgorithm.parseString(warehouseFrom.getStringField(LocationFieldsMFR.ALGORITHM));

    boolean enoughResources = true;

    StringBuilder errorMessage = new StringBuilder();

    Multimap<Long, BigDecimal> quantitiesForWarehouse =
        getQuantitiesInWarehouse(warehouseFrom, getProductsAndPositionsFromDocument(document));

    for (Entity position : document.getHasManyField(DocumentFields.POSITIONS)) {
      Entity product = position.getBelongsToField(PositionFields.PRODUCT);
      BigDecimal quantityInWarehouse;

      if (warehouseAlgorithm.equals(WarehouseAlgorithm.MANUAL)) {
        quantityInWarehouse = getQuantityOfProductInWarehouse(warehouseFrom, product, position);
      } else {
        quantityInWarehouse = getQuantityOfProductFromMultimap(quantitiesForWarehouse, product);
      }

      moveResources(warehouseFrom, warehouseTo, position, date, warehouseAlgorithm);
      enoughResources = enoughResources && position.isValid();

      if (!position.isValid()) {
        BigDecimal quantity = position.getDecimalField(QUANTITY);

        errorMessage.append(product.getStringField(ProductFields.NAME));
        errorMessage.append(" - ");
        errorMessage.append(numberService.format(quantity.subtract(quantityInWarehouse)));
        errorMessage.append(" ");
        errorMessage.append(product.getStringField(ProductFields.UNIT));
        errorMessage.append(", ");
      }
    }

    if (!enoughResources) {
      addDocumentError(document, warehouseFrom, errorMessage);
    } else {
      deleteReservations(document);
    }
  }
  @Override
  protected void addSeries(final HSSFSheet sheet, final Entity materialsInLocation) {
    Map<Entity, BigDecimal> reportData =
        materialFlowService.calculateMaterialQuantitiesInLocation(materialsInLocation);

    int rowNum = 1;
    for (Map.Entry<Entity, BigDecimal> data : reportData.entrySet()) {
      HSSFRow row = sheet.createRow(rowNum++);
      row.createCell(0).setCellValue(data.getKey().getStringField(NUMBER));
      row.createCell(1).setCellValue(data.getKey().getStringField(NAME));
      row.createCell(2).setCellValue(numberService.format(data.getValue()));
      row.createCell(3).setCellValue(data.getKey().getStringField(UNIT));
    }
    sheet.autoSizeColumn((short) 0);
    sheet.autoSizeColumn((short) 1);
    sheet.autoSizeColumn((short) 2);
    sheet.autoSizeColumn((short) 3);
  }