private void generateAndAddOperation() {
    Entity operation =
        dataDefinitionService.get(TECHNOLOGIES_PLUGIN, L_TECHNOLOGY_MODEL_OPERATION).create();

    String number = generateString(CHARS_ONLY, RANDOM.nextInt(40) + 5);

    operation.setField(L_NUMBER, number);
    operation.setField("name", getNameFromNumberAndPrefix("Operation-", number));
    operation.setField(L_BASIC_MODEL_STAFF, getRandomStaff());
    operation.setField(L_BASIC_MODEL_WORKSTATION_TYPE, getRandomMachine());

    operation.setField(L_TPZ, RANDOM.nextInt(1000));
    operation.setField(L_TJ, RANDOM.nextInt(1000));
    operation.setField("productionInOneCycle", RANDOM.nextInt(20));
    operation.setField(L_NEXT_OPERATION_AFTER_PRODUCED_TYPE, RANDOM.nextInt(10));
    operation.setField(
        "machineUtilization", numberService.setScale(new BigDecimal(RANDOM.nextDouble()).abs()));
    operation.setField(
        "laborUtilization", numberService.setScale(new BigDecimal(RANDOM.nextDouble()).abs()));
    operation.setField("nextOperationAfterProducedQuantity", RANDOM.nextInt(15));
    operation.setField(L_NEXT_OPERATION_AFTER_PRODUCED_TYPE, "01all");
    operation.setField("timeNextOperation", RANDOM.nextInt(30));
    operation.setField("nextOperationAfterProducedQuantity", "0");

    if (isEnabledOrEnabling("costNormsForOperation")) {
      operation.setField("pieceworkCost", RANDOM.nextInt(100));
      operation.setField("machineHourlyCost", RANDOM.nextInt(100));
      operation.setField("laborHourlyCost", RANDOM.nextInt(100));
      operation.setField("numberOfOperations", RANDOM.nextInt(10) + 1);
    }
    dataDefinitionService.get(TECHNOLOGIES_PLUGIN, L_TECHNOLOGY_MODEL_OPERATION).save(operation);
  }
  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);
  }
  @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);
    }
  }
 private void addOrderSeries(final Map<String, Object> model, final HSSFSheet sheet) {
   int rowNum = 1;
   Map<Entity, List<Entity>> productOrders =
       qualityControlsReportService.getQualityOrdersForProduct(
           qualityControlsReportService.getOrderSeries(model, "qualityControlsForUnit"));
   productOrders = SortUtil.sortMapUsingComparator(productOrders, new EntityNumberComparator());
   for (Entry<Entity, List<Entity>> entry : productOrders.entrySet()) {
     List<Entity> orders = entry.getValue();
     Collections.sort(orders, new EntityNumberComparator());
     for (Entity order : orders) {
       HSSFRow row = sheet.createRow(rowNum++);
       row.createCell(0)
           .setCellValue(
               entry.getKey() == null ? "" : entry.getKey().getField("number").toString());
       row.createCell(1).setCellValue(order.getField("number").toString());
       row.createCell(2)
           .setCellValue(
               numberService
                   .setScale((BigDecimal) order.getField("controlledQuantity"))
                   .doubleValue());
       row.createCell(3)
           .setCellValue(
               numberService
                   .setScale((BigDecimal) order.getField("rejectedQuantity"))
                   .doubleValue());
       row.createCell(4)
           .setCellValue(
               numberService
                   .setScale((BigDecimal) order.getField("acceptedDefectsQuantity"))
                   .doubleValue());
     }
   }
   sheet.autoSizeColumn((short) 0);
   sheet.autoSizeColumn((short) 1);
   sheet.autoSizeColumn((short) 2);
   sheet.autoSizeColumn((short) 3);
   sheet.autoSizeColumn((short) 4);
 }
  private void addSubstituteComponent(
      final Entity substitute, final Entity product, final double quantity) {
    Entity substituteComponent =
        dataDefinitionService.get(L_BASIC_PLUGIN_IDENTIFIER, "substituteComponent").create();

    substituteComponent.setField(
        "quantity", numberService.setScale(new BigDecimal(quantity + 1).abs()));
    substituteComponent.setField(L_BASIC_MODEL_PRODUCT, product);
    substituteComponent.setField("substitute", substitute);

    dataDefinitionService
        .get(L_BASIC_PLUGIN_IDENTIFIER, "substituteComponent")
        .save(substituteComponent);
  }
  @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);
  }
  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);
  }