public Entity createResource(
      final Entity position,
      final Entity warehouse,
      final Entity resource,
      final BigDecimal quantity,
      Object date) {
    DataDefinition resourceDD =
        dataDefinitionService.get(
            MaterialFlowResourcesConstants.PLUGIN_IDENTIFIER,
            MaterialFlowResourcesConstants.MODEL_RESOURCE);

    Entity newResource = resourceDD.create();

    if (position != null) {
      Entity document = position.getBelongsToField(PositionFields.DOCUMENT);

      if (document != null) {
        Entity user = document.getBelongsToField(DocumentFields.USER);

        newResource.setField(
            ResourceFields.USER_NAME,
            user.getStringField(_FIRST_NAME) + " " + user.getStringField(L_LAST_NAME));
      }
    }

    newResource.setField(ResourceFields.TIME, date);
    newResource.setField(ResourceFields.LOCATION, warehouse);
    newResource.setField(
        ResourceFields.PRODUCT, resource.getBelongsToField(PositionFields.PRODUCT));
    newResource.setField(ResourceFields.QUANTITY, quantity);
    newResource.setField(ResourceFields.AVAILABLE_QUANTITY, quantity);
    newResource.setField(ResourceFields.RESERVED_QUANTITY, BigDecimal.ZERO);
    newResource.setField(ResourceFields.PRICE, resource.getField(PositionFields.PRICE));
    newResource.setField(ResourceFields.BATCH, resource.getField(PositionFields.BATCH));
    newResource.setField(
        ResourceFields.EXPIRATION_DATE, resource.getField(PositionFields.EXPIRATION_DATE));
    newResource.setField(
        ResourceFields.PRODUCTION_DATE, resource.getField(PositionFields.PRODUCTION_DATE));
    newResource.setField(
        ResourceFields.STORAGE_LOCATION, resource.getField(ResourceFields.STORAGE_LOCATION));
    newResource.setField(
        ResourceFields.ADDITIONAL_CODE, resource.getField(ResourceFields.ADDITIONAL_CODE));
    newResource.setField(ResourceFields.CONVERSION, resource.getField(ResourceFields.CONVERSION));
    newResource.setField(
        ResourceFields.PALLET_NUMBER, resource.getField(ResourceFields.PALLET_NUMBER));
    newResource.setField(
        ResourceFields.TYPE_OF_PALLET, resource.getField(ResourceFields.TYPE_OF_PALLET));
    newResource.setField(ResourceFields.GIVEN_UNIT, resource.getField(ResourceFields.GIVEN_UNIT));

    BigDecimal quantityInAdditionalUnit =
        numberService.setScale(
            quantity.multiply(resource.getDecimalField(ResourceFields.CONVERSION)));

    newResource.setField(ResourceFields.QUANTITY_IN_ADDITIONAL_UNIT, quantityInAdditionalUnit);

    setResourceAttributesFromResource(newResource, resource);

    resourceStockService.addResourceStock(newResource);
    return resourceDD.save(newResource);
  }
  public Entity createResource(
      final Entity document, final Entity warehouse, final Entity position, final Object date) {
    DataDefinition resourceDD =
        dataDefinitionService.get(
            MaterialFlowResourcesConstants.PLUGIN_IDENTIFIER,
            MaterialFlowResourcesConstants.MODEL_RESOURCE);

    Entity product = position.getBelongsToField(PositionFields.PRODUCT);
    Entity resource = resourceDD.create();
    Entity user = document.getBelongsToField(DocumentFields.USER);

    resource.setField(
        ResourceFields.USER_NAME,
        user.getStringField(_FIRST_NAME) + " " + user.getStringField(L_LAST_NAME));
    resource.setField(ResourceFields.TIME, date);
    resource.setField(ResourceFields.LOCATION, warehouse);
    resource.setField(ResourceFields.PRODUCT, position.getBelongsToField(PositionFields.PRODUCT));
    resource.setField(ResourceFields.QUANTITY, position.getField(PositionFields.QUANTITY));
    resource.setField(ResourceFields.RESERVED_QUANTITY, BigDecimal.ZERO);
    resource.setField(
        ResourceFields.AVAILABLE_QUANTITY, position.getDecimalField(PositionFields.QUANTITY));
    resource.setField(ResourceFields.PRICE, position.getField(PositionFields.PRICE));
    resource.setField(ResourceFields.BATCH, position.getField(PositionFields.BATCH));
    resource.setField(
        ResourceFields.EXPIRATION_DATE, position.getField(PositionFields.EXPIRATION_DATE));
    resource.setField(
        ResourceFields.PRODUCTION_DATE, position.getField(PositionFields.PRODUCTION_DATE));
    resource.setField(
        ResourceFields.STORAGE_LOCATION, position.getField(PositionFields.STORAGE_LOCATION));
    resource.setField(
        ResourceFields.ADDITIONAL_CODE, position.getField(PositionFields.ADDITIONAL_CODE));
    resource.setField(
        ResourceFields.PALLET_NUMBER, position.getField(PositionFields.PALLET_NUMBER));
    resource.setField(
        ResourceFields.TYPE_OF_PALLET, position.getField(PositionFields.TYPE_OF_PALLET));
    resource.setField(ResourceFields.WASTE, position.getField(PositionFields.WASTE));

    if (StringUtils.isEmpty(product.getStringField(ProductFields.ADDITIONAL_UNIT))) {
      resource.setField(ResourceFields.GIVEN_UNIT, product.getField(ProductFields.UNIT));
      resource.setField(
          ResourceFields.QUANTITY_IN_ADDITIONAL_UNIT, position.getField(PositionFields.QUANTITY));
      resource.setField(ResourceFields.CONVERSION, BigDecimal.ONE);
    } else {
      resource.setField(ResourceFields.GIVEN_UNIT, position.getField(PositionFields.GIVEN_UNIT));
      resource.setField(
          ResourceFields.QUANTITY_IN_ADDITIONAL_UNIT,
          position.getField(PositionFields.GIVEN_QUANTITY));
      resource.setField(ResourceFields.CONVERSION, position.getField(PositionFields.CONVERSION));
    }

    setResourceAttributesFromPosition(resource, position);

    resourceStockService.addResourceStock(resource);
    return resourceDD.save(resource);
  }
  private void moveResources(
      Entity warehouseFrom,
      Entity warehouseTo,
      Entity position,
      Object date,
      WarehouseAlgorithm warehouseAlgorithm) {
    Entity product = position.getBelongsToField(PositionFields.PRODUCT);

    List<Entity> resources =
        getResourcesForWarehouseProductAndAlgorithm(
            warehouseFrom, product, position, warehouseAlgorithm);

    BigDecimal quantity = position.getDecimalField(PositionFields.QUANTITY);

    resourceStockService.removeResourceStock(product, warehouseFrom, quantity);
    for (Entity resource : resources) {
      BigDecimal resourceQuantity = resource.getDecimalField(QUANTITY);

      BigDecimal resourceAvailableQuantity =
          resource.getDecimalField(ResourceFields.AVAILABLE_QUANTITY);
      if (quantity.compareTo(resourceAvailableQuantity) >= 0) {
        quantity = quantity.subtract(resourceAvailableQuantity, numberService.getMathContext());
        if (resourceQuantity.compareTo(resourceAvailableQuantity) <= 0) {
          resource.getDataDefinition().delete(resource.getId());
        } else {
          BigDecimal newResourceQuantity = resourceQuantity.subtract(resourceAvailableQuantity);
          BigDecimal resourceConversion = resource.getDecimalField(ResourceFields.CONVERSION);
          BigDecimal quantityInAdditionalUnit = newResourceQuantity.multiply(resourceConversion);
          resource.setField(ResourceFields.AVAILABLE_QUANTITY, BigDecimal.ZERO);
          resource.setField(ResourceFields.QUANTITY, newResourceQuantity);
          resource.setField(
              ResourceFields.QUANTITY_IN_ADDITIONAL_UNIT,
              numberService.setScale(quantityInAdditionalUnit));
          resource.getDataDefinition().save(resource);
        }

        createResource(position, warehouseTo, resource, resourceAvailableQuantity, date);

        if (BigDecimal.ZERO.compareTo(quantity) == 0) {
          return;
        }
      } else {
        resourceQuantity = resourceQuantity.subtract(quantity, numberService.getMathContext());
        resourceAvailableQuantity =
            resourceAvailableQuantity.subtract(quantity, numberService.getMathContext());
        String givenUnit = resource.getStringField(ResourceFields.GIVEN_UNIT);
        BigDecimal quantityInAdditionalUnit =
            convertToGivenUnit(resourceQuantity, product, givenUnit);

        resource.setField(
            ResourceFields.QUANTITY_IN_ADDITIONAL_UNIT,
            numberService.setScale(quantityInAdditionalUnit));
        resource.setField(ResourceFields.QUANTITY, numberService.setScale(resourceQuantity));
        resource.setField(ResourceFields.AVAILABLE_QUANTITY, resourceAvailableQuantity);

        resource.getDataDefinition().save(resource);

        createResource(position, warehouseTo, resource, quantity, date);

        return;
      }
    }

    position.addError(
        position.getDataDefinition().getField(PositionFields.QUANTITY),
        "materialFlow.error.position.quantity.notEnough");
  }
  private List<Entity> updateResources(
      Entity warehouse, Entity position, WarehouseAlgorithm warehouseAlgorithm) {
    DataDefinition positionDD =
        dataDefinitionService.get(
            MaterialFlowResourcesConstants.PLUGIN_IDENTIFIER,
            MaterialFlowResourcesConstants.MODEL_POSITION);

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

    Entity product = position.getBelongsToField(PositionFields.PRODUCT);

    List<Entity> resources =
        getResourcesForWarehouseProductAndAlgorithm(
            warehouse, product, position, warehouseAlgorithm);

    BigDecimal quantity = position.getDecimalField(PositionFields.QUANTITY);

    resourceStockService.removeResourceStock(product, warehouse, quantity);
    for (Entity resource : resources) {
      BigDecimal resourceQuantity = resource.getDecimalField(ResourceFields.QUANTITY);
      BigDecimal resourceAvailableQuantity =
          resource.getDecimalField(ResourceFields.AVAILABLE_QUANTITY);

      Entity newPosition = positionDD.create();

      newPosition.setField(
          PositionFields.PRODUCT, position.getBelongsToField(PositionFields.PRODUCT));
      newPosition.setField(
          PositionFields.GIVEN_QUANTITY, position.getDecimalField(PositionFields.GIVEN_QUANTITY));
      newPosition.setField(
          PositionFields.GIVEN_UNIT, position.getStringField(PositionFields.GIVEN_UNIT));
      newPosition.setField(PositionFields.PRICE, resource.getField(ResourceFields.PRICE));
      newPosition.setField(PositionFields.BATCH, resource.getField(ResourceFields.BATCH));
      newPosition.setField(
          PositionFields.PRODUCTION_DATE, resource.getField(ResourceFields.PRODUCTION_DATE));
      newPosition.setField(
          PositionFields.EXPIRATION_DATE, resource.getField(ResourceFields.EXPIRATION_DATE));
      newPosition.setField(PositionFields.RESOURCE, resource);
      newPosition.setField(
          PositionFields.STORAGE_LOCATION, resource.getField(ResourceFields.STORAGE_LOCATION));
      newPosition.setField(
          PositionFields.ADDITIONAL_CODE, resource.getField(ResourceFields.ADDITIONAL_CODE));
      newPosition.setField(PositionFields.CONVERSION, position.getField(PositionFields.CONVERSION));
      newPosition.setField(
          PositionFields.PALLET_NUMBER, resource.getField(ResourceFields.PALLET_NUMBER));
      newPosition.setField(
          PositionFields.TYPE_OF_PALLET, resource.getField(ResourceFields.TYPE_OF_PALLET));
      // newPosition.setField(PositionFields.GIVEN_UNIT,
      // resource.getField(ResourceFields.GIVEN_UNIT));

      setPositionAttributesFromResource(newPosition, resource);

      if (quantity.compareTo(resourceAvailableQuantity) >= 0) {
        quantity = quantity.subtract(resourceAvailableQuantity, numberService.getMathContext());
        if (resourceQuantity.compareTo(resourceAvailableQuantity) <= 0) {
          resource.getDataDefinition().delete(resource.getId());
        } else {
          BigDecimal newResourceQuantity = resourceQuantity.subtract(resourceAvailableQuantity);
          BigDecimal resourceConversion = resource.getDecimalField(ResourceFields.CONVERSION);
          BigDecimal quantityInAdditionalUnit = newResourceQuantity.multiply(resourceConversion);
          resource.setField(ResourceFields.AVAILABLE_QUANTITY, BigDecimal.ZERO);
          resource.setField(ResourceFields.QUANTITY, newResourceQuantity);
          resource.setField(
              ResourceFields.QUANTITY_IN_ADDITIONAL_UNIT,
              numberService.setScale(quantityInAdditionalUnit));
          resource.getDataDefinition().save(resource);
        }

        newPosition.setField(
            PositionFields.QUANTITY, numberService.setScale(resourceAvailableQuantity));

        BigDecimal givenResourceQuantity = convertToGivenUnit(resourceAvailableQuantity, position);

        newPosition.setField(
            PositionFields.GIVEN_QUANTITY, numberService.setScale(givenResourceQuantity));

        newPositions.add(newPosition);

        if (BigDecimal.ZERO.compareTo(quantity) == 0) {
          return newPositions;
        }
      } else {
        resourceQuantity = resourceQuantity.subtract(quantity, numberService.getMathContext());
        resourceAvailableQuantity =
            resourceAvailableQuantity.subtract(quantity, numberService.getMathContext());
        if (position.getBelongsToField(PositionFields.RESOURCE) != null
            && reservationsService.reservationsEnabledForDocumentPositions()) {
          BigDecimal reservedQuantity =
              resource
                  .getDecimalField(ResourceFields.RESERVED_QUANTITY)
                  .subtract(quantity, numberService.getMathContext());
          resource.setField(ResourceFields.RESERVED_QUANTITY, reservedQuantity);
        }
        BigDecimal resourceConversion = resource.getDecimalField(ResourceFields.CONVERSION);
        BigDecimal quantityInAdditionalUnit = resourceQuantity.multiply(resourceConversion);

        resource.setField(
            ResourceFields.QUANTITY_IN_ADDITIONAL_UNIT,
            numberService.setScale(quantityInAdditionalUnit));
        resource.setField(ResourceFields.QUANTITY, numberService.setScale(resourceQuantity));
        resource.setField(ResourceFields.AVAILABLE_QUANTITY, resourceAvailableQuantity);

        resource.getDataDefinition().save(resource);
        newPosition.setField(PositionFields.QUANTITY, numberService.setScale(quantity));

        BigDecimal givenQuantity = convertToGivenUnit(quantity, position);

        newPosition.setField(PositionFields.GIVEN_QUANTITY, numberService.setScale(givenQuantity));
        newPositions.add(newPosition);

        return newPositions;
      }
    }

    position.addError(
        position.getDataDefinition().getField(PositionFields.QUANTITY),
        "materialFlow.error.position.quantity.notEnough");

    return Lists.newArrayList(position);
  }