Snippets Collections
(function (Drupal) {

  const handleExpand = (element) => {
    const expandElement = element.target.parentElement.querySelector('.to-expand');
    if (expandElement.style.display === "inline") {
      expandElement.style.display = "none";
      element.target.innerHTML = Drupal.t('Read more');
    } else {
      expandElement.style.display = "inline";
      element.target.innerHTML = Drupal.t('Collapse');
    }
  };

  document.querySelectorAll('.expand-link').forEach((element) => {
    element.addEventListener('click', handleExpand);
  });
}) (Drupal);
read_more:
  version: 1.x
  js:
    js/read_more.js: {}
  dependencies:
    - core/drupal
<?php

namespace Drupal\halo_widget_altering\Element;

use Drupal\Core\Render\Element\RenderElement;

/**
 * Provides a render element to display read more text.
 *
 * Properties:
 * - #text: Text to be printed.
 * - #limit_chars: Number of characters to limit.
 *
 * Usage Example:
 * @code
 * $build['read_more'] = [
 *   '#type' => 'correction_value_viewer',
 *   '#entity' => EntityInterface,
 * ];
 * @endcode
 * @RenderElement("read_more")
 */
class ReadMore extends RenderElement {

  /**
   * {@inheritDoc}
   */
  public function getInfo() {
    return [
      '#pre_render' => [
        [get_class($this), 'printText'],
      ],
      '#text' => NULL,
      '#limit_chars' => 250,
    ];
  }



  /**
   * @return
   */
  public static function printText(array $element) {
    $text = $element['#text'];
    $limit_characters = $element['#limit_chars'];

    if (empty($text)) {
      return [];
    }

    if (strlen($text) <= $limit_characters) {
      return [
        'text' => [
          '#type' => 'inline_template',
          '#template' => '{{ value|nl2br }}',
          '#context' => ['value' => $text],
        ],
      ];
    }
    $first_half_text = substr($text, 0, $limit_characters);
    $second_half_text = substr($text, $limit_characters);

    $element['text'] = [
      'text' => [
        '#type' => 'inline_template',
        '#template' => '{{ value1|nl2br }}<span class="to-expand" style="display: none">{{ value2|nl2br }}</span><a class="expand-link">{{ read_more_text }}</a>',
        '#context' => [
          'value1' => $first_half_text,
          'value2' => $second_half_text,
          'read_more_text' => t('Read more'),
        ],
      ],
    ];
    $element['#attached']['library'][] = 'halo_widget_altering/read_more';
    return $element;
  }

}
      $entity_row[] = [
        '#type' => 'read_more',
        '#text' => $entity->get('description')->value,
//        '#limit_chars' => 10,
      ];
    }
<?php
/**
* Implements hook_token_info().
*/
function mycustomtokenmodule_token_info() {
   $type = [
       'name' => t('Custom Token'),
       'description' => t('Tokens for custom things.'),
   ];
   $node['title'] = [
       'name' => t("Node Title"),
       'description' => t('The node\'s title'),
   ];
   $node['dateformat'] = [
       'name' => t("Custom Date Format"),
       'dynamic' => TRUE,
       'description' => t('Show a custom format for the current date'),
   ];
   return [
       'types' => ['customtoken' => $type],
       'tokens' => ['customtoken' => $node],
   ];
}
/**
* Implements hook_tokens().
*/
function mycustomtokenmodule_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
   $replacements = [];
   
   if ($type == 'customtoken' && !empty($data['node'])) {
       foreach ($tokens as $name => $original) {
           switch ($name) {
               case 'title':
                   $replacements[$original] = $data['node']->getTitle();
               break;
           }
       }
       if ($dateTokens = \Drupal::token()->findWithPrefix($tokens, 'dateformat')) {
           // var_dump($dateTokens)
           // retult: array(1) { ["Y-m-d"]=> string(30) "[customtoken:dateformat:Y-m-d]" }
           foreach ($dateTokens as $format => $original) {
               $replacements[$original] = date($format);
           }
       }
   }
   return $replacements;
}
function change_maintenance_date() {
  //Change the date so the Report date is 2024. 07. 15.
  $cfp = \Drupal::entityTypeManager()->getStorage('cfp')->load(190);
  $cfp->set('maintenance_period', '2021-07-15')->save(); // Ovaj datum je 
}
SELECT entity_id, COUNT(variations_target_id)
FROM `commerce_product__variations`
GROUP BY entity_id
HAVING COUNT(variations_target_id) > 1;
<?php

/** @var \Drupal\halo_entity_cfp\Entity\Cfp[] $cfps */
  $cfps = \Drupal::entityTypeManager()->getStorage('cfp')->loadByProperties([
    'type' => 'cfp_2020_01',
    'state' => 'project_implementation',
  ]);
  $first_key = key($cfps);
  $writer = Box\Spout\Writer\Common\Creator\WriterEntityFactory::createXLSXWriter();
  $file_system = \Drupal::service('file_system');
  $temp_path = 'public://ced_NOVI_report.xlsx';
  $temp_path = $file_system->realpath($temp_path);
  $writer->openToFile($temp_path);
  foreach ($cfps as $key => $cfp) {
    $applicant = $cfp->getApplicantEntity();
    $row = [];
    $row['operational_number'] = $cfp->label();
    $row['company_name'] = $applicant->label();
    // Partner countries.
    for ($i = 0;$i < 3;$i++) {
        $index = $i + 1;
        $partner = $cfp->get('partners')[$i] ?? FALSE;
        if ($partner) {
            $partner_entity = $partner->entity;
            $project_implementation_place = $partner_entity->get('project_implementation_place');
            if ($project_implementation_place->first()) {
                $implementation_country = $project_implementation_place->first()->getCountryName();
            }
            $row["partner_$index"] = $partner_entity->get('short_name')->value;
            $row["partner_country_$index"] = $implementation_country ?? '';
        } else {
            $row["partner_$index"] = '';
            $row["partner_country_$index"] = '';
        }
    }
    $contact_person_items = $applicant->get('contact_person');
    for ($i = 0;$i < 3;$i++) {
      $index = $i + 1;
      /** @var \Drupal\halo_entity_person\Entity\PersonEntity $ontact_person */
      $contact_person = $contact_person_items->get($i)->entity ?? FALSE;
      if ($contact_person) {
        $row["contact_person_last_name_$index"] = $contact_person->getLastName();
        $row["contact_person_first_name_$index"] = $contact_person->getFirstName();
        $row["contact_person_phone_1_$index"] = $contact_person->getPhone1();
        $row["contact_person_phone_2_$index"] = $contact_person->getPhone2();
        $row["contact_person_email_$index"] = $contact_person->getEmail();
      } else {
        $row["contact_person_last_name_$index"] = '';
        $row["contact_person_first_name_$index"] = '';
        $row["contact_person_phone_1_$index"] = '';
        $row["contact_person_phone_2_$index"] = '';
        $row["contact_person_email_$index"] = '';
      }
    }
    if ($first_key === $key) {
      $writer->addRow(\Box\Spout\Writer\Common\Creator\WriterEntityFactory::createRowFromArray(array_keys($row)));
    }
    $writer->addRow(\Box\Spout\Writer\Common\Creator\WriterEntityFactory::createRowFromArray($row));
  }
  $writer->close();
function ced_giga_report() {
  /** @var \Drupal\halo_entity_cfp\Entity\Cfp[] $cfps */
  $cfps = \Drupal::entityTypeManager()->getStorage('cfp')->loadByProperties([
    'state' => ['under_contracting', 'reject', 'project_implementation'],
  ]);
  $first_key = key($cfps);
  $writer = Box\Spout\Writer\Common\Creator\WriterEntityFactory::createXLSXWriter();
  $file_system = \Drupal::service('file_system');
  $temp_path = 'public://ced_giga_report.xlsx';
  $temp_path = $file_system->realpath($temp_path);
  $writer->openToFile($temp_path);
  foreach ($cfps as $key => $cfp) {
    $applicant = $cfp->getApplicantEntity();
    $row = [];
    $row['operational_number'] = $cfp->label();
    $row['company_name'] = $applicant->label();
    $row['vat_number'] = $applicant->get('vat_number')->value;
    $row['company_registration_number'] = $applicant->get('company_registration_number')->value;
    $date = $applicant->get('company_establishment_date')->date;
    $row['company_establishment_date'] = $date ? $date->format('Y.m.d') : '';
    $row['entitled_to_vat_refund'] = ((bool) $applicant->get('entitled_to_vat_refund')->value) ? 'Igen' : 'Nem';
    $row['main_company_address'] = $applicant->get('main_company_address')
      ->isEmpty() ? '' : address_basic_view($applicant->get('main_company_address')
      ->first());
    // Bank account.
    $bank_account_item = $applicant->get('bank_account_details');
    for ($i = 0; $i < 2; $i++) {
      /** @var \Drupal\halo_entity_bank_account\Entity\BankAccountEntity $bank_account */
      $bank_account = $bank_account_item->get($i)->entity ?? FALSE;
      $index = $i + 1;
      if ($bank_account) {
        $row["bank_account_name_$index"] = $bank_account->getName();
        $row["bank_address_address_$index"] = $bank_account->getAddress();
        $row["bank_account_number_$index"] = $bank_account->getAccountNumber();
      }
      else {
        $row["bank_account_name_$index"] = '';
        $row["bank_address_address_$index"] = '';
        $row["bank_account_number_$index"] = '';
      }
    }
    $company_representative_item = $applicant->get('company_representative');
    for ($i = 0;$i < 4;$i++) {
      $index = $i + 1;
      /** @var \Drupal\halo_entity_person\Entity\PersonEntity $company_representative */
      $company_representative = $company_representative_item->get($i)->entity ?? FALSE;
      if ($company_representative) {
        $row["company_representative_last_name_$index"] = $company_representative->getLastName();
        $row["company_representative_first_name_$index"] = $company_representative->getFirstName();
        $row["company_representative_assignment_$index"] = $company_representative->getAssignment();
        $row["company_representative_representation_type_$index"] = $company_representative->getRepresentationTypeLabel();
        $row["company_representative_phone_1_$index"] = $company_representative->getPhone1();
        $row["company_representative_email_$index"] = $company_representative->getEmail();
      } else {
        $row["company_representative_last_name_$index"] = '';
        $row["company_representative_first_name_$index"] = '';
        $row["company_representative_assignment_$index"] = '';
        $row["company_representative_representation_type_$index"] = '';
        $row["company_representative_phone_1_$index"] = '';
        $row["company_representative_email_$index"] = '';
      }
    }
    $contact_person_items = $applicant->get('contact_person');
    for ($i = 0;$i < 3;$i++) {
      $index = $i + 1;
      /** @var \Drupal\halo_entity_person\Entity\PersonEntity $ontact_person */
      $contact_person = $contact_person_items->get($i)->entity ?? FALSE;
      if ($contact_person) {
        $row["contact_person_last_name_$index"] = $contact_person->getLastName();
        $row["contact_person_first_name_$index"] = $contact_person->getFirstName();
        $row["contact_person_assignment_$index"] = $contact_person->getAssignment();
        $row["contact_person_phone_1_$index"] = $contact_person->getPhone1();
        $row["contact_person_email_$index"] = $contact_person->getEmail();
      } else {
        $row["contact_person_last_name_$index"] = '';
        $row["contact_person_first_name_$index"] = '';
        $row["contact_person_assignment_$index"] = '';
        $row["contact_person_phone_1_$index"] = '';
        $row["contact_person_email_$index"] = '';
      }
    }
    if ($first_key === $key) {
      $writer->addRow(\Box\Spout\Writer\Common\Creator\WriterEntityFactory::createRowFromArray(array_keys($row)));
    }
    $writer->addRow(\Box\Spout\Writer\Common\Creator\WriterEntityFactory::createRowFromArray($row));
  }
  $writer->close();
}
{#
/**
 * @file
 * Template for the commerce email.
 *
 * Available variables:
 * - order_entity: The order entity.
 * - body: The email body.
 * - totals: An array of order totals values with the following keys:
 *   - subtotal: The order subtotal price.
 *   - adjustments: An array of adjustment totals:
 *     - type: The adjustment type.
 *     - label: The adjustment label.
 *     - total: The adjustment total price.
 *     - weight: The adjustment weight, taken from the adjustment type.
 *
 * @ingroup themeable
 */
#}
<table style="margin: 15px auto 0 auto; max-width: 768px; font-family: arial,sans-serif">
  <tbody>
  <tr>
    <td>
      <table style="text-align: center; min-width: 450px; margin: 5px auto 0 auto; border: 1px solid #cccccc; border-radius: 5px; padding: 40px 30px 30px 30px;">
        <tbody>
        <tr>
          <td style="font-size: 30px; padding-bottom: 30px"><img src="/themes/custom/zadi_theme/belmil_wave_logo_email.png" style="height: 60px;" /></td>
        </tr>
        <tr>
          <td>
            {{ body|raw }}
          </td>

          <tr>
            <td style="font-weight: bold; padding-top:15px; padding-bottom: 15px; text-align: left; border-top: 1px solid #cccccc; border-bottom: 1px solid #cccccc">
              {{ 'Order #@number details:'|t({'@number': order_entity.getOrderNumber}) }}
            </td>
          </tr>
          <tr>
            <td>
              <table style="padding-top: 15px; padding-bottom:15px; width: 100%">
                <tbody style="text-align: left;">
                {% for order_item in order_entity.getItems %}
                  <tr>
                    <td>
                      {{ order_item.getQuantity|number_format }} x
                    </td>
                    <td>
                      <span>{{ order_item.label }}</span>
                      <span style="float: right;">{{ order_item.getTotalPrice|commerce_price_format }}</span>
                    </td>
                  </tr>
                {% endfor %}
                </tbody>
              </table>
            </td>
          </tr>
        <tr>
          <td>
            <p style="margin-bottom: 0;">
              {{ 'Subtotal: @subtotal'|t({'@subtotal': totals.subtotal|commerce_price_format}) }}
            </p>
          </td>
        </tr>
        {% for adjustment in totals.adjustments %}
          <tr>
            <td>
              <p style="margin-bottom: 0;">
                {{ adjustment.label }}: {{ adjustment.total|commerce_price_format }}
              </p>
            </td>
          </tr>
        {% endfor %}
        <tr>
          <td>
            <p style="font-size: 24px; padding-top: 15px; padding-bottom: 5px;">
              {{ 'Order Total: @total'|t({'@total': order_entity.getTotalPrice|commerce_price_format}) }}
            </p>
          </td>
        </tr>

          {% if store_info %}
          <tr>
            <td>
              {% block additional_information %}
                {{ store_info|raw }}
              {% endblock %}
            </td>
          </tr>
          {% endif %}
        </tr>
        </tbody>
      </table>
    </td>
  </tr>
  </tbody>
</table>
<?php

/**
 * @file
 * Provides a bb2b_order.
 */

use Drupal\block\Entity\Block;
use Drupal\commerce_order\Entity\Order;
use Drupal\commerce_shipping\Entity\ShipmentInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\AppendCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\RedirectCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\bb2b_order\Plugin\Commerce\CheckoutPane\OrderTypePane;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\views\Form\ViewsForm;
use Drupal\views\ViewExecutable;
use Drupal\Core\Entity\EntityInterface;

/**
 * Implements hook_cron().
 */
function bb2b_order_cron() {
  $request_time = \Drupal::time()->getRequestTime();
  $state_key = 'bb2b_order.last_queue_time';
  $last_queue_time = \Drupal::state()->get($state_key, 0);

  // Once daily.
  if ($request_time - $last_queue_time >= (24 * 60 * 60)) {
    \Drupal::service('bb2b_order.order_reservation_cron')->run();

    \Drupal::state()->set($state_key, $request_time);
  }
}

/**
 * Implements hook_form_alter().
 */
function bb2b_order_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  // Add to cart on product page. This page will be deactivated.
  if (strpos($form_id, 'commerce_order_item_add_to_cart_form') !== FALSE) {
    array_unshift($form['#validate'], 'validate_available_quantity');
  }

  // Cart page.
  if (strpos($form_id, 'views_form_commerce_cart_form_') !== FALSE) {
    array_unshift($form['#validate'], 'validate_min_quantity');
  }

  // Quick order page.
  if ($form_state->getFormObject() instanceof ViewsForm) {
    /** @var \Drupal\views\ViewExecutable $view */
    $view = reset($form_state->getBuildInfo()['args']);

    if ($view->storage->get('id') == 'quick_order' && !empty($view->result)) {
      $order_id = \Drupal::service('commerce_cart.cart_provider')->getCartIds(\Drupal::currentUser());
      $order_id = reset($order_id);
      $order = \Drupal::entityTypeManager()->getStorage('commerce_order')
        ->load($order_id);

      $form['ddp_package_list'] = [
        '#type' => 'details',
        '#title' => t('At DDP orders, every box must be filled with the MOQ / box quantity.'),
        '#weight' => -2,
        '#open' => FALSE,
      ];

      $form['ddp_package_list']['block'] = [
        '#type' => 'container',
        'block' => [
          '#markup' => bb2b_order_render_shipment_package_block(),
        ],
      ];

      $name = 'field_order_type';
      /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
      $form_display = \Drupal::entityTypeManager()->getStorage('entity_form_display')
        ->load('commerce_order.default.default');

      $widget = $form_display->getRenderer($name);

      $roles = \Drupal::currentUser()->getRoles();
      $is_admin = in_array('administrator', $roles) || in_array('site_administrator', $roles);

      if ($widget) {
        $items = $order->get($name);
        $items->filterEmptyItems();

        $store = \Drupal::service('commerce_store.current_store')->getStore();
        $cart_provider = \Drupal::service('commerce_cart.cart_provider');
        $cart = $cart_provider->getCart('default', $store);

        if (!$cart) {
          $cart = $cart_provider->createCart('default', $store);
        }

        $order_type = $cart->get('field_order_type')->value;

        $form[$name] = $widget->form($items, $form, $form_state);
        $form[$name]['#access'] = $items->access('edit');
        $form[$name]['#required'] = TRUE;
        $form[$name]['#weight'] = -1;
        $form[$name]['widget']['#default_value'] = $order_type ?? 'ddp';
        $form[$name]['widget']['#ajax'] = [
          'callback' => 'bb2b_order_update_min_values',
        ];

        if ($is_admin) {
          unset($form[$name]['widget']['#options']['ddp_reservation']);
        }
        else {
          $form[$name]['widget']['ddp_reservation'] = [
            '#description' => t('You have 5 days to pay the order, otherwise it will be canceled.'),
          ];
        }
      }

      $options = [];
      $companies = \Drupal::entityTypeManager()
        ->getStorage('company')
        ->loadMultiple();

      foreach ($companies as $company) {
        if ($employee = $company->getEmployeeByRole('company_manager')) {
          $options[$employee->id()] = $employee->getDisplayName() . ' (' . $company->getName() . ')';
        }
      }

      $form['client'] = [
        '#type' => 'select2',
        '#id' => 'update-client',
        '#options' => $options,
        '#title' => t('Client'),
        '#required' => FALSE,
        '#weight' => -2,
        '#access' => $is_admin,
        '#ajax' => [
          'callback' => 'bb2b_order_update_client',
        ],
      ];

      if ($client_id = $order->getData('client_id')) {
        $form['client']['#default_value'] = $client_id;
      }

      $form['actions']['checkout'] = [
        '#type' => 'submit',
        '#value' => t('Delivery data'),
        '#weight' => 5,
        '#access' => \Drupal::currentUser()->hasPermission('access checkout'),
        '#submit' => array_merge($form['#submit'], ['bb2b_order_checkout_views_form_submit']),
        '#order_id' => $order_id,
      ];

    }
  }

  if ($form_id == 'commerce_shipping_method_edit_form') {
    $form['plugin']['widget'][0]['target_plugin_configuration']['form']['rate_label']['#attributes'] = ['readonly' => 'readonly'];
    $form['plugin']['widget'][0]['target_plugin_configuration']['form']['rate_label']['#description'] = t('Shown to customers during checkout. This value cannot be changed because we need it to match the name in Linker.');
  }
}

/**
 * Implements hook_views_pre_render().
 */
function bb2b_order_views_pre_render(ViewExecutable $view) {
  if ($view->id() == 'commerce_cart_form') {
    $order_id = $view->args[0];
    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = Order::load($order_id);

    /** @var \Drupal\bb2b_order\OrderServiceInterface $order_service */
    $order_service = \Drupal::service('bb2b_order.order_service');

    if (!$order_service->packageMinQuantityIsValid($order)) {
      $view->build_info['substitutions']['{{ admin_shipment_packages_block }}'] = bb2b_order_render_shipment_package_block();
    }
  }
  if ($view->id() === 'quick_order') {
    //@todo: This will go to history when we create stock base field on product.
    //@todo: Query will be in the StockStatus filter.
    $input = $view->getExposedInput();
    if (isset($input['stock_status']) && $input['stock_status'] === 'only_available') {
      // Get products from the view.
      $products = [];
      foreach ($view->result as $key => $product) {
        $products[$key] = $product->_entity;
      }
      // Check if those products are available.
      $order_service = \Drupal::service('bb2b_order.order_service');
      foreach ($products as $key => $product) {
        if (!$order_service->checkAccessForProduct($product))
        unset($view->result[$key]);
      }

    }
  }
}

/**
 * Gets the cart order for the given store and user.
 *
 * @param \Drupal\Core\Session\AccountInterface $account
 *   The user. If empty, the current user is assumed.
 *
 * @return \Drupal\commerce_order\Entity\OrderInterface|null
 *   The cart order, or NULL if none found.
 */
function bb2b_order_get_cart(AccountInterface $account = NULL) {
  $store = \Drupal::service('commerce_store.current_store')->getStore();
  $cart_provider = \Drupal::service('commerce_cart.cart_provider');
  $cart = $cart_provider->getCart('default', $store, $account);

  if (!$cart) {
    $cart = $cart_provider->createCart('default', $store, $account);
  }

  return $cart;
}

/**
 * Ajax handler used to remove min values validation for drop shipping.
 */
function bb2b_order_update_client($form, FormStateInterface $form_state) {
  $response = new AjaxResponse();

  $triggering_element = $form_state->getTriggeringElement();
  $trigger_name = array_shift($triggering_element['#parents']);

  if ($trigger_name === 'client') {
    $client_id = $triggering_element['#value'];
    $cart = bb2b_order_get_cart();

    $user = \Drupal::entityTypeManager()
      ->getStorage('user')
      ->load($client_id);

    $email = $user ? $user->getEmail() : NULL;

    $cart->setData('client_id', $client_id);
    $cart->setData('client_email', $email);
    $cart->save();

    $content = '<div class="ajax-progress-throbber"></div>';
    $response->addCommand(new AppendCommand('body', $content));
    $response->addCommand(new RedirectCommand(Url::fromUri('internal:/orders/quick-order')->toString()));
  }

  return $response;
}

/**
 * Ajax handler used to remove min values validation for drop shipping.
 */
function bb2b_order_update_min_values($form, FormStateInterface $form_state) {
  $response = new AjaxResponse();

  $triggering_element = $form_state->getTriggeringElement();
  $trigger_name = array_shift($triggering_element['#parents']);

  if ($trigger_name === 'field_order_type') {
    $order_type = $triggering_element['#value'];
    $rows = $form['output'][0]['#rows'];

    /** @var \Drupal\bb2b_order\OrderServiceInterface $order_service */
    $order_service = \Drupal::service('bb2b_order.order_service');

    $cart = bb2b_order_get_cart();

    /*if ($order_type !== 'drop_shipping') {
    $cart->setData('client_id', NULL);
    $cart->setData('client_email', NULL);
    }*/

    $cart->set('field_order_type', $order_type);
    $cart->save();

    foreach ($rows as $key => $row) {
      $field_stock = $form['warehouse_stock'][$key];
      $field_quantity = $form['edit_quantity'][$key];
      $field_chk = $form['chk_add_to_cart'][$key];
      $field_price = $form['price_group_price'][$key];
      $add_to_cart_button = $form['add_to_cart_button'][$key];

      /** @var \Drupal\commerce_product\Entity\ProductInterface $product */
      $product = $row->_entity;

      $access = $order_service->checkAccessForProduct($product);
      $available = $order_service->getAvailableStock($product);

      if ($order_type === 'drop_shipping') {
        $class = $field_quantity['#attributes']['class'] ?? [];
        $key = array_search('visually-hidden', $class);
        if ($key !== FALSE && $available > 0) {
          unset($field_quantity['#attributes']['class'][$key]);
        }

        $class = $field_chk['#attributes']['class'] ?? [];
        $key = array_search('visually-hidden', $class);
        if ($key !== FALSE && $available > 0) {
          unset($field_chk['#attributes']['class'][$key]);
        }

        $class = $add_to_cart_button['#attributes']['class'] ?? [];
        $key = array_search('visually-hidden', $class);
        if ($key !== FALSE && $available > 0) {
          unset($add_to_cart_button['#attributes']['class'][$key]);
        }
      }
      else {
        if (!$access || $available == 0) {
          if (!isset($field_quantity['#attributes']['class']['visually-hidden'])) {
            $field_quantity['#attributes']['class'][] = 'visually-hidden';
          }

          if (!isset($field_chk['#attributes']['class']['visually-hidden'])) {
            $field_chk['#attributes']['class'][] = 'visually-hidden';
          }

          $field_chk['#value'] = 0;
          if (!isset($add_to_cart_button['#attributes']['class']['visually-hidden'])) {
            $add_to_cart_button['#attributes']['class'][] = 'visually-hidden';
          }
        }
      }

      $method = $order_type === 'drop_shipping' ? 'addClass' : 'removeClass';
      $response->addCommand(new InvokeCommand('.min-qty', $method, ['visually-hidden']));

      $selector = $field_quantity['#attributes']['data-drupal-selector'];
      $quantity_selector = 'div[class*="' . preg_replace('/edit/', 'form-item', $selector, 1) . '"]';
      $response->addCommand(new ReplaceCommand($quantity_selector, $field_quantity));

      $selector = $field_chk['#attributes']['data-drupal-selector'];
      $chk_selector = 'div[class*="' . preg_replace('/edit/', 'form-item', $selector, 1) . '"]';
      $response->addCommand(new ReplaceCommand($chk_selector, $field_chk));

      $selector = $field_stock['#attributes']['data-drupal-selector'];
      $stock_selector = 'div[id="' . preg_replace('/edit/', 'form-item', $selector, 1) . '"]';
      $response->addCommand(new ReplaceCommand($stock_selector, $field_stock));

      $company = $order_service->getCompanyForClient($cart);
      $price = $order_service->getProductPriceForClient($product->getDefaultVariation(), $cart, $company);
      $field_price['list_price']['#value'] = $price['list_price'];
      $field_price['price']['#value'] = $price['price'];

      $selector = $field_price['#attributes']['data-drupal-selector'];
      $price_selector = 'div[id="' . preg_replace('/edit/', 'form-item', $selector, 1) . '"]';
      $response->addCommand(new ReplaceCommand($price_selector, $field_price));

      $button_selector = 'button[name="' . $add_to_cart_button['#name'] . '"]';
      $response->addCommand(new ReplaceCommand($button_selector, $add_to_cart_button));

      // Cart block.
      /** @var \Drupal\Core\Block\BlockPluginInterface $cart_block */
      $cart_block = \Drupal::service('plugin.manager.block')->createInstance('commerce_cart', []);
      if ($cart_block) {
        $response->addCommand(new ReplaceCommand('.cart--cart-block', $cart_block->build()));
      }
    }
  }

  return $response;
}

/**
 * Submit handler used to redirect to the checkout page.
 */
function bb2b_order_checkout_views_form_submit($form, FormStateInterface $form_state) {
  $order_id = $form_state->getTriggeringElement()['#order_id'];
  $form_state->setRedirect('commerce_checkout.form', ['commerce_order' => $order_id]);
}

/**
 * Form validation handler for commerce_order_item_add_to_cart_form*().
 *
 * @param array $form
 *   A build form array.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The form state.
 */
function validate_available_quantity(array $form, FormStateInterface $form_state) {
  $product = $form_state->get('product');
  $quantity = (int) $form_state->getValue('quantity')[0]['value'];

  /** @var \Drupal\bb2b_order\OrderServiceInterface $order_service */
  $order_service = \Drupal::service('bb2b_order.order_service');

  $available = $order_service->getAvailableStock($product);
  if ($available < $quantity) {
    $form_state->setErrorByName('quantity][0][value', t('There are not enough quantity on the stock. Available: @available', [
      '@available' => $available,
    ]));
  }

}

/**
 * Form validation handler for views_form_commerce_cart_form_*().
 *
 * @param array $form
 *   A build form array.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The form state.
 */
function validate_min_quantity(array $form, FormStateInterface $form_state) {
  $quantity = $form_state->getValue('edit_quantity');
  $rows = $form['output'][0]['#rows'];

  $triggering_element = $form_state->getTriggeringElement();
  $trigger_name = array_shift($triggering_element['#parents']);

  if ($trigger_name !== 'remove_button') {
    foreach ($rows as $key => $row) {
      /** @var \Drupal\commerce_product\Entity\ProductVariationInterface $product_variation */
      $product_variation = $row->_relationship_entities['commerce_product_variation'];

      /** @var \Drupal\commerce_product\Entity\ProductInterface $product */
      $product = $product_variation->getProduct();

      /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
      $order = $row->_entity;

      /** @var \Drupal\bb2b_order\OrderServiceInterface $order_service */
      $order_service = \Drupal::service('bb2b_order.order_service');

      $available = $order_service->getAvailableStock($product);

      foreach ($order->getItems() as $order_item) {
        if ($order_item->getPurchasedEntityId() == $product_variation->id()) {
          $order_quantity = (int) $order_item->getQuantity();
          $diff_quantity = $quantity[$key] - $order_quantity;

          if ($available < $diff_quantity || ($diff_quantity == 0 && $available < $order_quantity)) {
            $form_state->setErrorByName('edit_quantity][' . $key, t('There are not enough quantity on the stock for product: @product_title. Available: @available', [
              '@product_title' => $product->getTitle(),
              '@available' => $diff_quantity == 0 ? $available : $available + $order_quantity,
            ]));
          }
        }
      }

    }
  }

}

/**
 * Implements hook_commerce_inline_form_PLUGIN_ID_alter().
 */
function bb2b_order_commerce_inline_form_customer_profile_alter(array &$inline_form, FormStateInterface $form_state, array &$complete_form) {
  if ($inline_form['#profile_scope'] === 'checkout' && !isset($inline_form['rendered'])) {
    $inline_form['address']['widget'][0]['address']['#after_build'] = [
      'change_country_code_ajax_callback',
      ['\Drupal\address\Element\Address', 'clearValues'],
    ];
  }
}

/**
 * Form API callback: Change ajax callback on country select.
 *
 * @param array $element
 *   The element array.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   Form state object.
 *
 * @return array
 *   The element array.
 */
function change_country_code_ajax_callback(array $element, FormStateInterface &$form_state) {
  $element['country_code']['country_code']['#ajax']['callback'] = [
    OrderTypePane::class,
    'ajaxRefresh',
  ];

  if ($form_state->getTriggeringElement()) {
    if ($form_state->getTriggeringElement()['#name'] === $element['country_code']['country_code']['#name']) {
      $form_state->setTriggeringElement($element['country_code']['country_code']);
    }
  }

  return $element;
}

/**
 * Implements hook_mail_alter().
 */
function bb2b_order_mail_alter(&$message) {
  if ($message['key'] == 'order_receipt' && !empty($message['params']['order'])) {
    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = $message['params']['order'];
    $message['from'] = 'noreply@bescool.net';

    $subject_order_number = $order->getOrderNumber();
    if ($order->get('field_your_order_id')->isEmpty() === FALSE) {
      $client_order_number = $order->get('field_your_order_id')->value;
      $subject_order_number .= ' (' . $client_order_number . ')';
    }

    $message['subject'] = t('Order confirmation ID: @number', [
      '@number' => $subject_order_number,
    ]);
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function bb2b_order_form_views_exposed_form_alter(&$form, FormStateInterface $form_state) {
  $view = $form_state->get('view');

  if ($view && in_array($view->id(), ['ongoing_orders', 'orders'])) {
    $form['search']['#placeholder'] = t('By email, order IDs, recipient name');
  }
}

/**
 * Implements hook_views_data_alter().
 */
function bb2b_order_views_data_alter(array &$data) {
  $data['commerce_order']['own_company_orders'] = [
    'title' => t('Own company orders'),
    'help' => t('Filter orders by own company for company managers.'),
    'filter' => [
      'group' => 'Order',
      'field' => 'uid',
      'id' => 'own_company_orders_filter',
      'entity_type' => 'commerce_order',
    ],
  ];
}

/**
 * Implements hook_views_data().
 */
function bb2b_order_views_data() {
  $data = [];

  //@todo: Maybe we could put ["products"] instead of ["views"].
  $data['views']['stock_status'] = [
    'title' => t('Stock status - Custom Filter'),
    'filter' => [
      'title' => t('Stock status - Custom Filter'),
      'field' => 'id',
      'id' => 'stock_status',
    ]
  ];

  return $data;
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function bb2b_order_commerce_order_presave(EntityInterface $entity) {
  if ($entity->get('field_created_invoice')->isEmpty()) {
    $entity->set('field_created_invoice', 'no');
  }
  // In case the your_order_id is edited after the order has been created,
  // and before the order is being shipped.
  if (!empty($entity->get('placed')->value)) {
    $order_service = \Drupal::service('bb2b_order.order_service');
    $order_service->resolveShipping($entity);
  }
}

/**
 * Implements hook_entity_access().
 */
function bb2b_order_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
  $allowed_entities = [
    'commerce_order',
    'commerce_order_item',
    'commerce_shipment',
  ];

  if (in_array($entity->getEntityTypeId(), $allowed_entities)) {
    if ($account->hasPermission('update default commerce_order')) {
      return AccessResult::allowed();
    }
  }

  return AccessResult::neutral();
}

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function bb2b_order_form_commerce_shipment_default_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if (!\Drupal::currentUser()->hasPermission('access commerce administration pages')) {
    $form['title']['#access'] = FALSE;
    $form['shipping_method']['#access'] = FALSE;
    $form['tracking_code']['#access'] = FALSE;
    $form['shipment_items']['#access'] = FALSE;
    $form['recalculate_shipping']['#access'] = FALSE;
    $form['actions']['delete']['#access'] = FALSE;

    $request = \Drupal::requestStack()->getCurrentRequest();
    $shipment = $request->get('commerce_shipment');
    $form_state->set('shipment', $shipment);
    $shipment->setData('shipping_force_resolve', TRUE);

    if (isset($form['shipping_profile']['widget'][0]['profile']['edit_button'])) {
      $form['shipping_profile']['widget'][0]['profile']['edit_button']['#attributes']['class'][] = 'button-secondary';
    }

    // Redirect user to order view.
    $form['actions']['submit']['#submit'][] = 'bb2b_order_shipment_edit_form_submit';
  }
}

/**
 * Custom submit handler for the shipment edit form.
 */
function bb2b_order_shipment_edit_form_submit($form, FormStateInterface $form_state) {
  $shipment = $form_state->get('shipment');
  $account = \Drupal::currentUser();
  if ($shipment) {
    $admin_permission = $account
      ->hasPermission($shipment->getEntityType()->getAdminPermission());
    $order = $shipment->getOrder();

    if ($order && !$admin_permission) {
      /*$form_state->setRedirect('entity.commerce_order.user_view', [
      'commerce_order' => $order->id(),
      'user' => $order->getCustomerId(),
      ]);*/

      $form_state->setRedirect('entity.commerce_order.edit_form', [
        'commerce_order' => $order->id(),
      ]);
    }
  }
}

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function bb2b_order_form_commerce_order_default_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $user = \Drupal::currentUser();
  if (!$user->hasPermission('access commerce administration pages')) {
    $form['field_credit_note']['#access'] = FALSE;
    $form['field_internal_note']['#access'] = FALSE;
    $form['field_order_notes']['#access'] = FALSE;
    $form['field_order_type']['#access'] = FALSE;
    $form['field_vat_verified']['#access'] = FALSE;
    $form['field_tracking_code_date']['#access'] = FALSE;
    $form['coupons']['#access'] = FALSE;
    $form['billing_profile']['widget'][0]['profile']['select_address']['#access'] = FALSE;
    $form['billing_profile']['widget'][0]['profile']['edit_button']['#access'] = FALSE;
    $form['billing_profile']['widget'][0]['profile']['copy_fields']['enable']['#access'] = FALSE;
    $form['shipments']['#access'] = FALSE;

    $form['order_items']['widget']['actions']['ief_add']['#attributes']['class'][] = 'button-secondary';

    if (isset($form['order_items']['widget']['entities'])) {
      foreach ($form['order_items']['widget']['entities'] as $key => &$entity) {
        if (is_numeric($key)) {
          $entity['actions']['ief_entity_edit']['#attributes']['class'][] = 'button-secondary';
          $entity['actions']['ief_entity_remove']['#attributes']['class'][] = 'delete-order-item';
        }
      }
    }

    $form['ddp_package_list'] = [
      '#type' => 'details',
      '#title' => t('At DDP orders, every box must be filled with the MOQ / box quantity.'),
      '#weight' => -2,
      '#open' => FALSE,
    ];

    $form['ddp_package_list']['block'] = [
      '#type' => 'container',
      'block' => [
        '#markup' => bb2b_order_render_shipment_package_block(),
      ],
    ];

    $header = [t('Title'), t('Shipping method'), t('Price'), t('Actions')];
    $rows = [];
    $request = \Drupal::requestStack()->getCurrentRequest();

    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = $request->get('commerce_order');
    if ($order && $user->hasPermission('update default commerce_order')) {
      $form_state->set('order', $order);
      /** @var \Drupal\commerce_shipping\Entity\ShipmentInterface[] $shipments */
      $shipments = $order->get('shipments')->referencedEntities();
      foreach ($shipments as $shipment) {
        $row = $links = [];
        $links['edit'] = [
          'title' => t('Edit'),
          'url' => $shipment->toUrl('edit-form'),
          'attributes' => [
            'role' => 'button',
            'class' => ['button button-secondary'],
            // 'target' => '_blank',
          ],
        ];

        $row[] = [
          'data' => [
            '#type' => 'markup',
            '#markup' => $shipment->label(),
          ],
        ];

        $row[] = [
          'data' => [
            '#type' => 'markup',
            '#markup' => $shipment->getShippingMethod()->label(),
          ],
        ];

        $row[] = [
          'data' => [
            '#type' => 'markup',
            '#markup' => $shipment->getAmount(),
          ],
        ];

        $row[] = [
          'data' => [
            '#type' => 'operations',
            '#links' => $links,
          ],
        ];

        $rows[] = $row;
      }
    }

    $form['shipments_list'] = [
      '#type' => 'container',
      '#weight' => $form['shipments']['#weight'] ?? 0,
      'shipments' => [
        '#type' => 'fieldset',
        '#title' => t('Shipments'),
        'entities' => [
          '#theme' => 'table',
          '#rows' => $rows,
          '#header' => $header,
        ],
      ],
    ];

    array_unshift($form['#validate'], 'validate_first_package_is_full');

    // Redirect user to order view.
    $form['actions']['submit']['#submit'][] = 'bb2b_order_order_edit_form_submit';
  }
}

/**
 * Custom submit handler for the order edit form.
 */
function bb2b_order_order_edit_form_submit($form, FormStateInterface $form_state) {
  $order = $form_state->get('order');
  if ($order) {
    $form_state->setRedirect('entity.commerce_order.user_view', [
      'commerce_order' => $order->id(),
      'user' => $order->getCustomerId(),
    ]);
  }
}

/**
 * Render shipment packages block content.
 *
 * @return mixed
 *   The rendered content.
 */
function bb2b_order_render_shipment_package_block() {
  $shipment_package_view = views_embed_view('shipment_package_list', 'block_1');

  return \Drupal::service('renderer')
    ->render($shipment_package_view);
}

/**
 * Form validation handler for commerce_order_default_edit_form().
 *
 * @param array $form
 *   A build form array.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The form state.
 */
function validate_first_package_is_full(array $form, FormStateInterface $form_state) {
  $triggering_element = $form_state->getTriggeringElement();

  $parents = $triggering_element['#array_parents'];
  $triggering_element_name = array_pop($parents);

  if ($triggering_element_name === 'submit') {
    $storage = $form_state->getStorage();
    $order_items_array = $storage['inline_entity_form']['order_items-form']['entities'] ?? [];

    /** @var \Drupal\bb2b_order\OrderServiceInterface $order_service */
    $order_service = \Drupal::service('bb2b_order.order_service');

    $order_type = NULL;
    $order_items = [];
    foreach ($order_items_array as $order_item_array) {
      if (isset($order_item_array['entity'])) {
        $order_items[] = $order_item_array['entity'];
        if (!$order_type) {
          $order = $order_item_array['entity']->getOrder();
          $order_type = $order ? $order->get('field_order_type')->value : NULL;
        }
      }
    }

    if ($order_items && $order_type !== 'drop_shipping') {
      $quantities = $order_service->getOrderedQuantitiesByTag($order_items);
      if ($order_service->minQuantityIsNotValid($quantities)) {
        $form_state->setErrorByName('full_package', t('Your order can not be completed because the conditions for minimum order quantity is not met.'));
      }
    }
  }

}

/**
 * Implements hook_inline_entity_form_entity_form_alter().
 */
function bb2b_order_inline_entity_form_entity_form_alter(&$entity_form, &$form_state) {
  $access_commerce_admin_pages = \Drupal::currentUser()
    ->hasPermission('access commerce administration pages');
  if (!$access_commerce_admin_pages) {
    if ($entity_form['#entity_type'] === 'commerce_shipment') {
      $entity_form['title']['#access'] = FALSE;
      $entity_form['shipping_method']['#access'] = FALSE;
      $entity_form['tracking_code']['#access'] = FALSE;
    }
    elseif ($entity_form['#entity_type'] === 'commerce_order_item') {
      $entity_form['unit_price']['#access'] = FALSE;
      $default_quantity = (int) ($entity_form['quantity']['widget'][0]['value']['#default_value'] ?? 0);
      $entity_form['quantity']['widget'][0]['value']['#default_value'] = $default_quantity;
      $entity_form['purchased_entity']['widget'][0]['target_id']['#attributes']['class'][] = 'form-order-item-autocomplete';
    }
  }
}

/**
 * Implements hook_entity_base_field_info_alter().
 */
function bb2b_order_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
  if ($entity_type->id() === 'commerce_order_item' && isset($fields['quantity'])) {
    $fields['quantity']->addConstraint('CheckAvailable');
  }
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function bb2b_order_commerce_shipment_presave(ShipmentInterface $shipment) {
  $order = $shipment->getOrder();
  $pending_order = $order && $order->getState()->getId() === 'pending';
  $shipping_force_resolve = $shipment->getData('shipping_force_resolve', FALSE);

  if ($shipment->original && $pending_order && $shipping_force_resolve) {
    /** @var \Drupal\bb2b_order\OrderServiceInterface $order_service */
    $order_service = \Drupal::service('bb2b_order.order_service');
    $order = $shipment->getOrder();

    $shipping_method = $order_service
      ->getShippingMethodForOrder($order, $shipment->getShippingProfile());

    if ($shipping_method) {
      $adjustments = $order->getAdjustments();
      $order_service->setShippingMethodForShipment($shipment, $shipping_method, 0, $adjustments);
      $order->set('adjustments', $adjustments);
    }
    $shipment->setData('shipping_force_resolve', FALSE);
  }
}

/**
 * Implements hook_theme().
 */
function bb2b_order_theme($existing, $type, $theme, $path) {
  return [
    'commerce_checkout_form__with_sidebar' => [
      'base hook' => 'commerce_checkout_form',
      'variables' => [
        'ordered_products' => NULL,
      ],
    ],
  ];
}

/**
 * Implements hook_preprocess_HOOK().
 */
function bb2b_order_preprocess_commerce_checkout_form__with_sidebar(&$variables) {
  $block = Block::load('views_block__ordered_products_block_2');
  $step = $variables['form']['#step_id'] ?? NULL;

  if ($block && $step === 'complete') {
    $variables['ordered_products'] = $block->getPlugin()->build();
    $variables['ordered_products']['#attributes']['class'][] = 'ordered-products-block';
  }
}

/**
 * Implements hook_tokens_alter().
 */
function bb2b_order_tokens_alter(array &$replacements, array $context, BubbleableMetadata $bubbleable_metadata) {
  // Clear empty token.
  if (isset($context['data']['entity_type']) &&
    $context['data']['entity_type'] === 'commerce_order'
  ) {
    foreach ($context['tokens'] as $token) {
      if (!isset($replacements[$token])) {
        $replacements[$token] = '';
      }
    }
  }
}

/**
 * Implements hook_entity_view_alter().
 */
function bb2b_order_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  if ($build['#view_mode'] === 'user' &&
    $build['#entity_type'] === 'commerce_order'
  ) {
    /** @var \Drupal\commerce_order\Entity\OrderInterface $entity */
    $entity_state = $entity->getState()->getId();

    if ($entity_state === 'pending') {
      $order = $build['#commerce_order'];
      $vat_verified = $order->get('field_vat_verified')->value;

      if (($vat_verified === '1') || ($vat_verified === '0')) {
        $ship_uri = '/orders/' . $entity->id() . '/send';
        $ship_url = Url::fromUri('internal:' . $ship_uri);

        $build['ship_the_order_link'] = [
          '#type' => 'link',
          '#title' => t('Ship the order'),
          '#url' => $ship_url,
          '#weight' => -11,
          '#attributes' => [
            'class' => ['button button-secondary'],
          ],
        ];
      }

      $user = $entity->getCustomer();
      if ($user->hasPermission('update default commerce_order')) {
        $build['edit_link'] = [
          '#type' => 'link',
          '#title' => t('Edit order'),
          '#url' => $entity->toUrl('edit-form'),
          '#weight' => -10,
          '#attributes' => [
            'class' => ['button button-secondary'],
          ],
        ];
      }
    }
  }
}
<?php

namespace Drupal\bb2b_order;

use Drupal\bb2b_company\CompanyInterface;
use Drupal\commerce_order\Adjustment;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_price\Price;
use Drupal\commerce_product\Entity\ProductInterface;
use Drupal\commerce_product\Entity\ProductVariationInterface;
use Drupal\commerce_shipping\Entity\ShipmentInterface;
use Drupal\commerce_shipping\Entity\ShippingMethod;
use Drupal\commerce_shipping\Entity\ShippingMethodInterface;
use Drupal\commerce_shipping\ShippingOrderManagerInterface;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\paragraphs\ParagraphInterface;
use Drupal\profile\Entity\ProfileInterface;

/**
 * Class Order Service.
 */
class OrderService implements OrderServiceInterface {

  use StringTranslationTrait;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The messenger.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * The cache.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cache;

  /**
   * The shipping order manager.
   *
   * @var \Drupal\commerce_shipping\ShippingOrderManagerInterface
   */
  protected $shippingOrderManager;

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * The private temp store.
   *
   * @var \Drupal\Core\TempStore\PrivateTempStore
   */
  protected $tempStore;

  /**
   * The Base Linker config.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected $baseLinkerConfig;

  /**
   * Constructs a new OrderService object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
   *   The cache.
   * @param \Drupal\commerce_shipping\ShippingOrderManagerInterface $shipping_order_manager
   *   The shipping order manager.
   * @param \Drupal\Core\Database\Connection $database
   *   The database connection.
   * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $temp_store_factory
   *   The tempstore factory.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The configuration factory.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    MessengerInterface $messenger,
    CacheBackendInterface $cache,
    ShippingOrderManagerInterface $shipping_order_manager,
    Connection $database,
    PrivateTempStoreFactory $temp_store_factory,
    ConfigFactoryInterface $config_factory
  ) {
    $this->entityTypeManager = $entity_type_manager;
    $this->messenger = $messenger;
    $this->cache = $cache;
    $this->shippingOrderManager = $shipping_order_manager;
    $this->database = $database;
    $this->tempStore = $temp_store_factory->get('bb2b_order');
    $this->baseLinkerConfig = $config_factory->get('bb2b_baselinker.settings');
  }

  /**
   * {@inheritdoc}
   */
  public function getApplicableWarehouse(ProductInterface $product) {
    $cid = 'get_applicable_warehouse_' . $product->id();
    $cache_data = $this->cache->get($cid);

    if (isset($cache_data->data)) {
      return $cache_data->data;
    }
    else {
      // @todo Logic to check which warehouse will be used in reality.
      $warehouse = $this->entityTypeManager->getStorage('taxonomy_term')->loadByProperties([
        'vid' => 'warehouse',
        'field_warehouse_code' => 'PL',
      ]);

      $warehouse = reset($warehouse);

      $product_warehouses = $product->get('field_warehouse')->referencedEntities();

      $applicable_warehouse = NULL;
      foreach ($product_warehouses as $product_warehouse) {
        $warehouse_target_id = $product_warehouse->get('field_warehouse')->target_id;

        if ($warehouse_target_id == $warehouse->id()) {
          $applicable_warehouse = $product_warehouse;
        }
      }

      if (!empty($applicable_warehouse)) {
        $cache_tags = [
          'commerce_product:' . $product->id(),
          'paragraph:' . $applicable_warehouse->id(),
        ];
        $this->cache->set($cid, $applicable_warehouse, CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
      }

      return $applicable_warehouse;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function setStockOnWarehouse(ParagraphInterface $warehouse, int $stock) {
    if ($stock <= 0) {
      $warehouse->setUnpublished();
    }
    elseif (!$warehouse->isPublished() && $stock > 0) {
      $warehouse->setPublished();
    }

    $warehouse->set('field_available', $stock);
    $warehouse->set('field_last_linker_stock_sync', time());
    $warehouse->save();
  }

  /**
   * {@inheritdoc}
   */
  public function getAvailableStock(ProductInterface $product, ?ParagraphInterface $product_warehouse = NULL) {
    $cid = 'get_available_stock_' . $product->id();
    $cache_data = $this->cache->get($cid);

    if (isset($cache_data->data)) {
      return $cache_data->data;
    }
    else {
      // For regular non-bundle products.
      if ($product->get('field_bundle_product_skus')->isEmpty()) {
        $available_stock = $this->doGetAvailableStock($product, $product_warehouse);
      }
      // For bundle products we need to check all products that are part of the
      // bundle.
      else {
        /** @var \Drupal\commerce_product\Entity\ProductVariationInterface $variation_item */
        $available_stock_for_product = [];

        foreach ($product->get('field_bundle_product_skus')->referencedEntities() as $variation_item) {
          $product_item = $variation_item->getProduct();
          $available_stock_for_product[] = $this->doGetAvailableStock($product_item, $product_warehouse);
        }

        $available_stock = min($available_stock_for_product);
      }

      $cache_tags = [
        'commerce_product:' . $product->id(),
      ];

      if ($product_warehouse !== NULL) {
        $cache_tags[] = 'paragraph:' . $product_warehouse->id();
      }

      $this->cache->set($cid, $available_stock, CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
      return $available_stock;
    }
  }

  /**
   * Gets the available stock value.
   *
   * @param \Drupal\commerce_product\Entity\ProductInterface $product
   *   The product.
   * @param \Drupal\paragraphs\ParagraphInterface|null $product_warehouse
   *   The warehouse.
   *
   * @return int
   *   The available stock.
   */
  protected function doGetAvailableStock(ProductInterface $product, ?ParagraphInterface $product_warehouse = NULL) {
    if (!$product_warehouse) {
      /** @var \Drupal\paragraphs\ParagraphInterface $product_warehouse */
      $product_warehouse = $this->getApplicableWarehouse($product);

      if (!$product_warehouse) {
        return 0;
      }
    }

    $local_stock = (int) $product_warehouse->get('field_available')->value;

    $stock_reserved_belmil_de = (int) $product->get('field_stock_reserved_belmil_de')->value;
    if ($stock_reserved_belmil_de > 0) {
      $local_stock -= $stock_reserved_belmil_de;
    }

    $stock_reserved = (int) $product_warehouse->get('field_reserved')->value;
    if ($stock_reserved > 0) {
      $local_stock -= $stock_reserved;
    }

    return $local_stock > 0 ? $local_stock : 0;
  }

  /**
   * {@inheritdoc}
   */
  public function checkAccessForProduct(ProductInterface $product) {
    $cid = 'access_for_product_' . $product->id();
    $cache_data = $this->cache->get($cid);

    if (isset($cache_data->data)) {
      return $cache_data->data;
    }
    else {
      /** @var \Drupal\paragraphs\ParagraphInterface $warehouse */
      $warehouse = $this->getApplicableWarehouse($product);
      $available = $this->getAvailableStock($product, $warehouse);
      $result = $warehouse && $available > 0;

      $cache_tags = [
        'commerce_product:' . $product->id(),
      ];

      if ($warehouse !== NULL) {
        $cache_tags[] = 'paragraph:' . $warehouse->id();
      }

      $this->cache->set($cid, $result, CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
      return $result;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function getCompanyForClient(OrderInterface $order) {
    $customer_id = $order->getData('client_id', $order->getCustomerId());
    if (!$customer_id) {
      return NULL;
    }

    return $this->getCompanyForCustomer($customer_id);
  }

  /**
   * {@inheritdoc}
   */
  public function getCompanyForCustomer($customer_id) {
    $company_storage = $this->entityTypeManager->getStorage('company');
    $company = $company_storage->loadByProperties([
      'employees' => $customer_id,
    ]);
    $company = reset($company);

    if (!$company) {
      return NULL;
    }

    return $company;
  }

  /**
   * {@inheritdoc}
   */
  public function getProductPriceForClient(ProductVariationInterface $variation, OrderInterface $order, CompanyInterface $company = NULL) {
    $price = $variation->getPrice();
    $list_price = $variation->getListPrice();
    $calculated_price = [
      'price' => $price,
      'list_price' => $list_price,
    ];

    if (!$company) {
      return $calculated_price;
    }

    $order_type = $order->get('field_order_type')->value;

    $client_price_groups = $company->get('price_group')->referencedEntities() ?? NULL;
    $with_return = $company->get('auto_generate_return_label')->value;

    if (!$client_price_groups) {
      return $calculated_price;
    }

    $client_price_group_ids = array_map(function ($client_price_group) {
      return $client_price_group->id();
    }, $client_price_groups);

    $product = $variation->getProduct();
    $product_price_groups = $product->get('field_price_group')->referencedEntities();

    $price_groups = array_filter($product_price_groups, function ($product_price_group) use ($client_price_group_ids) {
      $price_group_terms = $product_price_group->get('field_price_group')->referencedEntities();

      /** @var \Drupal\taxonomy\Entity\Term $price_group_term */
      $price_group_term = reset($price_group_terms);

      return $price_group_term && in_array($price_group_term->id(), $client_price_group_ids);
    });

    if (!$price_groups) {
      return $calculated_price;
    }

    $price_group_price = 0;
    foreach ($price_groups as $price_group) {
      if ($order_type === 'ddp' || $order_type === 'ddp_reservation') {
        $price_group_price = $price_group->get('field_ddp')->value;
      }
      elseif ($order_type === 'drop_shipping' && !$with_return) {
        $price_group_price = $price_group->get('field_dsnr')->value;
      }
      elseif ($order_type === 'drop_shipping' && $with_return) {
        $price_group_price = $price_group->get('field_dswr')->value;
      }

      if ($price_group_price > 0) {
        break;
      }
    }

    if ($price_group_price == 0) {
      return $calculated_price;
    }

    $currency = $price->getCurrencyCode();

    $calculated_price['price'] = new Price((string) $price_group_price, $currency);
    if ($list_price) {
      $calculated_price['list_price'] = new Price((string) $price_group_price, $currency);
    }

    return $calculated_price;
  }

  /**
   * {@inheritdoc}
   */
  public function packageMinQuantityIsValid(OrderInterface $order): bool {
    return $this->getNotFullPackageCount($order) === 0;
  }

  /**
   * {@inheritdoc}
   */
  public function getNotFullPackageCount(OrderInterface $order): int {
    $order_type = $order->get('field_order_type')->value;
    $not_valid_packages = 0;

    if ($order_type === 'drop_shipping') {
      return 0;
    }

    // Sum order item quantities by Tag.
    $quantities = $this->getOrderedQuantitiesByTag($order->getItems());

    if (!$quantities) {
      return 1;
    }

    $shipment_packages = $this->entityTypeManager
      ->getStorage('shipment_package')
      ->loadMultiple();

    // Check min quantities.
    foreach ($shipment_packages as $shipment_package) {
      $ordered_quantity = 0;
      $min_order_quantity = (int) $shipment_package->get('max_item_per_package')->value;
      $articles = $shipment_package->get('article_no')->referencedEntities();
      foreach ($articles as $article) {
        if (isset($quantities[$article->id()])) {
          $ordered_quantity += $quantities[$article->id()];
        }
      }

      if ($ordered_quantity > 0 &&
        (!$min_order_quantity
        || $ordered_quantity < $min_order_quantity
        || $ordered_quantity % $min_order_quantity != 0)
      ) {
        $not_valid_packages++;
      }
    }

    return $not_valid_packages;
  }

  /**
   * {@inheritdoc}
   */
  public function firstPackageIsNotFull(OrderInterface $order): bool {
    $order_type = $order->get('field_order_type')->value;
    if ($order_type === 'drop_shipping') {
      return FALSE;
    }

    // Sum order item quantities by Tag.
    $quantities = $this->getOrderedQuantitiesByTag($order->getItems());

    return $this->minQuantityIsNotValid($quantities);
  }

  /**
   * Check ordered quantity.
   *
   * @param array $quantities
   *   The ordered quantities.
   *
   * @return bool
   *   Return TRUE if minimum ordered quantity is not valid.
   */
  public function minQuantityIsNotValid(array $quantities): bool {
    $shipment_packages = $this->entityTypeManager
      ->getStorage('shipment_package')
      ->loadMultiple();

    // Check min quantities.
    foreach ($shipment_packages as $shipment_package) {
      $ordered_quantity = 0;
      $min_order_quantity = (int) $shipment_package->get('max_item_per_package')->value;
      $articles = $shipment_package->get('article_no')->referencedEntities();
      foreach ($articles as $article) {
        if (isset($quantities[$article->id()])) {
          $ordered_quantity += $quantities[$article->id()];
        }
      }

      if ($ordered_quantity > 0 && $ordered_quantity < $min_order_quantity) {
        return TRUE;
      }
    }

    return FALSE;
  }

  /**
   * Gets the order item quantities by tag.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface[] $order_items
   *   The order items.
   */
  public function getOrderedQuantitiesByTag(array $order_items): array {
    $quantities = [];

    foreach ($order_items as $order_item) {
      /** @var \Drupal\commerce_product\Entity\ProductVariationInterface $purchased_entity */
      $purchased_entity = $order_item->getPurchasedEntity();
      if (!$purchased_entity || $purchased_entity->getEntityTypeId() != 'commerce_product_variation') {
        continue;
      }

      /** @var \Drupal\commerce_product\Entity\ProductInterface $product */
      $product = $purchased_entity->getProduct();

      $tag = $product->get('field_tag')->referencedEntities();
      $tag = reset($tag);

      if (!$tag) {
        return [];
      }

      $tag_id = $tag->id();

      if (isset($quantities[$tag_id])) {
        $quantities[$tag_id] += (int) $order_item->getQuantity();
      }
      else {
        $quantities[$tag_id] = (int) $order_item->getQuantity();
      }
    }

    return $quantities;
  }

  /**
   * {@inheritdoc}
   */
  public function getMinOrderQuantity(ProductInterface $product) {
    $min_order_quantity = 1;

    $tag = $product->get('field_tag')->referencedEntities();
    $tag = reset($tag);

    if ($tag) {
      $shipment_packages = $this->entityTypeManager
        ->getStorage('shipment_package')
        ->loadMultiple();

      $package = array_filter($shipment_packages, function ($shipment_package) use ($tag) {
        $terms = $shipment_package->get('article_no')->referencedEntities();

        $term_ids = array_map(function ($term) {
          return $term->id();
        }, $terms);

        return in_array($tag->id(), $term_ids);
      });

      $package = reset($package);

      $min_order_quantity = $package ? $package->get('max_item_per_package')->value : 1;
    }

    return $min_order_quantity;
  }

  /**
   * Resolve shipping for order.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   *   The order.
   * @param \Drupal\profile\Entity\ProfileInterface|null $billing_profile
   *   The billing profile.
   * @param \Drupal\profile\Entity\ProfileInterface|null $shipping_profile
   *   The shipping profile.
   * @param string|null $shipping_country
   *   The shipping country.
   */
  public function resolveShipping(
    OrderInterface $order,
    ?ProfileInterface $billing_profile = NULL,
    ?ProfileInterface $shipping_profile = NULL,
    ?string $shipping_country = NULL
  ) {

    if (!$billing_profile) {
      $billing_profile = $order->getBillingProfile();
    }

    if (!$shipping_profile) {
      $shipping_profile = $order->collectProfiles()['shipping'] ?? NULL;
    }

    if (!$shipping_profile && $billing_profile) {
      $shipping_profile = $billing_profile->createDuplicate();
      $shipping_profile->unsetData('copy_to_address_book');
    }

    if (!$billing_profile && $shipping_profile) {
      $billing_profile = $shipping_profile->createDuplicate();
      $billing_profile->unsetData('copy_to_address_book');
    }

    if (!$billing_profile || !$shipping_profile) {
      return;
    }

    $shipments = $this->shippingOrderManager->pack($order, $shipping_profile);

    $store_key = 'shipping_force_resolve:' . $order->id();
    $shipping_force_resolve = $this->tempStore->get($store_key);
    $this->tempStore->delete($store_key);

    $shipping_country = $shipping_country ?: $shipping_profile
      ->get('address')->country_code;
    $shipping_method = $this->getShippingMethodForOrder($order, $billing_profile, $shipping_country);

    if ($shipping_method) {
      $shipping_adjustments = $order->getAdjustments(['shipping']);
      foreach ($shipping_adjustments as $adjustment) {
        $order->get('adjustments')->removeAdjustment($adjustment);
      }

      $adjustments = $order->getAdjustments();

      /** @var \Drupal\commerce_shipping\Entity\ShipmentInterface $shipment */
      foreach ($shipments as $key => $shipment) {
        $this->setShippingMethodForShipment($order, $shipment, $shipping_method, $key, $adjustments);
        if ($shipping_force_resolve) {
          $shipment->save();
        }
      }

      $order->set('adjustments', $adjustments);
    }

    $order->set('shipments', $shipments);
  }

  /**
   * Get shipping method for order.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   *   The order.
   * @param \Drupal\profile\Entity\ProfileInterface|null $profile
   *   The profile.
   * @param string|null $shipping_country
   *   The shipping country.
   *
   * @return \Drupal\commerce_shipping\Entity\ShippingMethodInterface|null
   *   The shipping method.
   */
  public function getShippingMethodForOrder(OrderInterface $order, ProfileInterface $profile, ?string $shipping_country = NULL) {
    $shipping_method = NULL;

    /** @var \Drupal\commerce_shipping\Entity\ShippingMethodInterface[] $shipping_methods */
    $shipping_methods = ShippingMethod::loadMultiple();
    $shipping_methods = array_filter($shipping_methods, function ($item) {
      return $item->getPlugin()->getPluginId() == 'belmil_shipping' && $item->isEnabled();
    });

    usort($shipping_methods, function ($a, $b) {
      return $a->getWeight() <=> $b->getWeight();
    });

    $time_now = DrupalDateTime::createFromTimestamp(time());
    $time_now->setTimezone(new \DateTimeZone('Europe/Belgrade'));
    // Saturday is also working day. Only sunday is weekend.
    $is_weekend = $time_now->format('N') == 7;

    $order_type = $order->get('field_order_type')->value;
    $order_source = $order->get('field_source')->value;
    $belmil_de_shipping_method = NULL;
    if ($order_source === 'belmilde') {
      $belmil_de_shipping_method = $order->getData('belmil_de_shipping_method', 'standard');
    }

    $amazon_shipping_method = NULL;
    if ($order_source === 'amazon') {
      $amazon_shipping_method = $order->getData('amazon_shipping_method', 'Std DE Dom_3');
    }

    $packstation_address = $profile->hasField('field_packstation_address') &&
      $profile->get('field_packstation_address')->value;

    $packstation_postnumber = $profile->hasField('field_packstation_postnumber') ?
      $profile->get('field_packstation_postnumber')->value : NULL;

    $shipping_profile_country = $shipping_country ?: $profile->get('address')->country_code;

    $shipping_with_packstation = $shipping_profile_country === 'DE' &&
      $packstation_address && $packstation_postnumber;

    foreach ($shipping_methods as $shipping_method_entity) {
      $method_configuration = $shipping_method_entity->getPlugin()
        ->getConfiguration();
      $method_countries = $method_configuration['belmil'] ?? [];

      // Set amazon related shipping method.
      if ($order_source == 'amazon') {
        // DE Standard or Express.
        if ($shipping_method_entity->label() == 'DEDHL' &&
          in_array($amazon_shipping_method, ['Std DE Dom_3', 'Exp DE Dom_1'])
        ) {
          $shipping_method = $shipping_method_entity;
          break;
        }
        // International EU.
        elseif ($shipping_method_entity->label() == 'DHL DE INTERNATIONAL' &&
          $amazon_shipping_method == 'Std DE Intl_2'
        ) {
          $shipping_method = $shipping_method_entity;
          break;
        }
      }

      // DHL Packstation address.
      if ($shipping_with_packstation &&
        isset($method_configuration['address']) &&
        $method_configuration['address']['packstation']
      ) {
        foreach ($method_countries as $country_code => $country_config) {
          if ($shipping_profile_country == $country_code &&
            !empty($country_config['enabled'])
          ) {
            $shipping_method = $shipping_method_entity;
            break 2;
          }
        }
      }

      // Check store condition.
      if (!in_array($order->getStoreId(), $shipping_method_entity->getStoreIds())) {
        continue;
      }

      // Order total conditions check.
      $conditions = $shipping_method_entity->getConditions();
      if ($conditions) {
        /** @var \Drupal\commerce\Plugin\Commerce\Condition\ConditionInterface[] $order_total_conditions */
        $order_total_conditions = array_filter($conditions, function ($condition) {
          /** @var \Drupal\commerce\Plugin\Commerce\Condition\ConditionInterface $condition */
          return $condition->getEntityTypeId() == 'commerce_order' &&
            $condition->getPluginId() === 'order_total_price';
        });
        $order_total_condition = reset($order_total_conditions);
        if ($order_total_condition && !$order_total_condition->evaluate($order)) {
          continue;
        }
      }

      if (
        isset($method_configuration['belmil']) &&
        isset($method_configuration['order_types']) &&
        isset($method_configuration['time']) &&
        !$shipping_with_packstation
      ) {
        foreach ($method_countries as $country_code => $country_config) {
          if (
            $shipping_profile_country == $country_code &&
            !empty($country_config['enabled']) &&
            !empty($method_configuration['order_types'][$order_type])
          ) {
            // Check time conditions for weekend.
            if ($is_weekend === TRUE) {
              if (!empty($method_configuration['time']['use_on_weekends']) && !empty($method_configuration['time']['use_on_weekends_type'])) {
                $weekends_time_until = new DrupalDateTime($method_configuration['time']['weekends_time_until']);
                $weekends_time_after = new DrupalDateTime($method_configuration['time']['weekends_time_after']);

                // For DDP orders we don't have to check time conditions.
                $ignore_time_conditions_for_ddp = !empty($method_configuration['time']['ignore_for_ddp']);
                if ($ignore_time_conditions_for_ddp === TRUE &&
                  in_array($order_type, ['ddp', 'ddp_reservation'])
                ) {
                  $shipping_method = $shipping_method_entity;
                  break 2;
                }

                // Check if the current time is in range for non-ddp orders.
                if ($method_configuration['time']['use_on_weekends_type'] == 'included') {
                  if ($time_now >= $weekends_time_until && $time_now <= $weekends_time_after) {
                    $shipping_method = $shipping_method_entity;
                    break 2;
                  }
                }
                elseif ($method_configuration['time']['use_on_weekends_type'] == 'excluded') {
                  if ($time_now < $weekends_time_until || $time_now > $weekends_time_after) {
                    $shipping_method = $shipping_method_entity;
                    break 2;
                  }
                }
              }
            }
            // Check time conditions for weekdays.
            else {
              if (!empty($method_configuration['time']['use_on_workdays']) && !empty($method_configuration['time']['use_on_workdays_type'])) {
                $workdays_time_until = new DrupalDateTime($method_configuration['time']['workdays_time_until']);
                $workdays_time_after = new DrupalDateTime($method_configuration['time']['workdays_time_after']);

                // For DDP orders we don't have to check time conditions.
                $ignore_time_conditions_for_ddp = !empty($method_configuration['time']['ignore_for_ddp']);
                if ($ignore_time_conditions_for_ddp === TRUE &&
                  in_array($order_type, ['ddp', 'ddp_reservation'])
                ) {
                  $shipping_method = $shipping_method_entity;
                  break 2;
                }

                // Check if the current time is in range for non-ddp orders.
                if ($method_configuration['time']['use_on_workdays_type'] == 'included') {
                  if ($time_now >= $workdays_time_until && $time_now <= $workdays_time_after) {
                    $shipping_method = $shipping_method_entity;
                    break 2;
                  }
                }
                elseif ($method_configuration['time']['use_on_workdays_type'] == 'excluded') {
                  $excluded = $time_now < $workdays_time_until ||
                    $time_now > $workdays_time_after;
                  if ($excluded ||
                    (!$excluded && $belmil_de_shipping_method === 'standard')
                  ) {
                    $shipping_method = $shipping_method_entity;
                    break 2;
                  }
                }
              }
            }
          }
        }
      }
    }

    return $shipping_method;
  }

  /**
   * Set shipping method for shipment.
   *
   * @param \Drupal\commerce_shipping\Entity\ShipmentInterface $shipment
   *   The shipment.
   * @param \Drupal\commerce_shipping\Entity\ShippingMethodInterface $shipping_method
   *   The shipping method.
   * @param int|null $key
   *   The shipment key.
   * @param \Drupal\commerce_order\Adjustment[] $adjustments
   *   The order adjustments.
   */
  public function setShippingMethodForShipment(OrderInterface $order, ShipmentInterface $shipment, ShippingMethodInterface $shipping_method, ?int $key = 0, array &$adjustments = []) {
    $shipment->setShippingMethod($shipping_method);

    $order_type = $order->get('field_order_type')->value;
    $order_source = $order->get('field_source')->value;
    $your_order_id = $order->get('field_your_order_id')->value;

    $shipping_method_plugin = $shipping_method->getPlugin();
    $shipping_rates = $shipping_method_plugin->calculateRates($shipment);
    $shipping_rate = reset($shipping_rates);
    $shipping_label = $shipping_rate->getService()->getLabel();
    /** @var \Drupal\commerce_price\Price $amount */
    $amount = $shipping_rate->getAmount();

    // Belmil.de express price is 10 EUR.
    if ($order_source === 'belmilde' &&
      $shipping_label === 'DEDHL Prime'
    ) {
      $amount = new Price('10', $amount->getCurrencyCode());
    }

    // DDP is FREE.
    if (in_array($order_type, ['ddp', 'ddp_reservation'])) {
      $amount = new Price('0', $amount->getCurrencyCode());
    }

    // Amazon.
    if ($order_source === 'amazon') {
      $amount_number = 0;
      $amazon_shipping_method = $order->getData('amazon_shipping_method', 'Std DE Dom_3');

      // DE Standard.
      if ($amazon_shipping_method === 'Std DE Dom_3') {
        $amount_number = $this->baseLinkerConfig->get('amazon_standard_de_price');
      }
      // DE Express.
      elseif ($amazon_shipping_method === 'Exp DE Dom_1') {
        $amount_number = $this->baseLinkerConfig->get('amazon_express_de_price');
      }
      // International EU.
      elseif ($amazon_shipping_method === 'Std DE Intl_2') {
        $amount_number = $this->baseLinkerConfig->get('amazon_eu_price');
      }

      $items = count($shipment->getItems());

      $amount = new Price($items * $amount_number, $amount->getCurrencyCode());
    }

    $shipment->setAmount($amount);

    $shipping_service = $shipping_rate->getService()->getId();
    $shipment->setShippingService($shipping_service);

    $shipment_number = str_pad(($key + 1), 2, '0', STR_PAD_LEFT);
    $shipment_number = $your_order_id ?
      $shipment_number . ' #' . $your_order_id : $shipment_number;

    $shipment_title = $this->t('Shipping for package @order_id', [
      '@order_id' => $shipment_number,
    ]);

    $shipment->setTitle($shipment_title);
    // In case there are some changes on placed order that are
    // affecting shipment information.
    if (!empty($order->get('placed')->value)) {
      $shipment->save();
    }

    $cloned_adjustment = NULL;
    foreach ($adjustments as $key => $adjustment) {
      // Edit existing shipment amount.
      if ($adjustment->getSourceId() == $shipment->id()) {
        $cloned_adjustment = $adjustment->toArray();
        $cloned_adjustment['amount'] = $amount;
        unset($adjustments[$key]);
        $order->get('adjustments')->removeAdjustment($adjustment);
        $adjustments[] = new Adjustment($cloned_adjustment);
      }
    }

    if (!$cloned_adjustment) {
      $adjustments[] = new Adjustment([
        'type' => 'shipping',
        'label' => $shipment_title,
        'amount' => $amount,
        'source_id' => $shipment->id(),
      ]);
    }
  }

  /**
   * Set surcharges on order.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   *   The order.
   */
  public function setOrderSurcharges(OrderInterface $order) {
    $adjustments = $order->getAdjustments(['custom']);
    foreach ($adjustments as $adjustment) {
      $order->get('adjustments')->removeAdjustment($adjustment);
    }

    $currency = $order->getTotalPrice()->getCurrencyCode();
    $not_full_package_cnt = $this->getNotFullPackageCount($order);

    // Convert back to while if we need more surcharge.
    if ($not_full_package_cnt > 0) {
      $order->addAdjustment(new Adjustment([
        'type' => 'custom',
        'label' => $this->t('Surcharge'),
        'amount' => new Price('4.00', $currency),
        'source_id' => $order->id() . '|' . $not_full_package_cnt,
      ]));

      // $not_full_package_cnt--;
    }
  }

  /**
   * Get bundle products variation ids.
   *
   * @return mixed
   *   The ids.
   */
  public function getBundleProductIds() {
    $query = $this->database->query("SELECT DISTINCT p.field_bundle_product_skus_target_id AS field_bundle_product_skus_target_id
      FROM {commerce_product__field_bundle_product_skus} p
      INNER JOIN {commerce_product_variation_field_data} pv ON pv.variation_id = p.field_bundle_product_skus_target_id
      LEFT OUTER JOIN {commerce_product__field_main_and_bundle_product} mb ON mb.entity_id = pv.product_id
      WHERE (p.deleted = 0) AND ((mb.field_main_and_bundle_product_value IS NULL) OR (mb.field_main_and_bundle_product_value <> 1))");

    return $query->fetchCol();
  }

}
<?php

namespace Drupal\bb2b_order\Plugin\views\filter;

use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\filter\FilterPluginBase;

/**
 * Filter products by stock status.
 *
 * @ingroup views_filter_handlers
 *
 * @ViewsFilter("stock_status")
 */
class StockStatus extends FilterPluginBase {

  /**
   * {@inheritDoc}
   */
  public function acceptExposedInput($input) {
    return TRUE;
  }

  /**
   * {@inheritDoc}
   */
  public function buildExposedForm(&$form, FormStateInterface $form_state) {
    if (empty($this->options['exposed'])) {
      return;
    }
    $identifier = $this->options['expose']['identifier'];
    $exposed_input = $this->view->getExposedInput();
    $options = [
      NULL => t('Show all products'),
      'only_available' => t('Show only available products'),
    ];

    $form[$identifier] = [
      '#type' => 'select',
      '#title' => t('Stock status'),
      '#options' => $options,
      '#default_value' => $exposed_input,
    ];
    return $form;
  }

  /**
   * {@inheritDoc}
   */
  public function query() {
    /** @var \Drupal\views\Plugin\views\query\Sql $query */
    $query = $this->query;
    $stock_status = $this->view->getExposedInput();
    if (isset($stock_status['stock_status']) && $stock_status['stock_status'] === 'only_available') {
      $query->addWhereExpression($this->options['group'], "commerce_product_field_data.stock > 0");
    }
  }

}
<?php

/**
 * @file
 * BaseLinker module functions.
 */

/**
 * Implements hook_cron().
 */
function bb2b_baselinker_cron() {
  /** @var \Drupal\bb2b_baselinker\SyncService $sync_service */
  $sync_service = \Drupal::service('bb2b_baselinker.sync_service');
  $sync_service->getOrders();
  $sync_service->addProduct();
}

/**
 * Implements hook_theme().
 */
function bb2b_baselinker_theme($existing, $type, $theme, $path) {
  return [
    'belmilb2b_baselinker_pdf' => [
      'variables' => [
        'title' => '',
        'order' => [],
        'order_total_paid' => '',
        'currency' => '',
      ],
    ],
  ];
}
<?php

namespace Drupal\bb2b_baselinker\Plugin\QueueWorker;

use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Queue\QueueWorkerBase;
use Drupal\Core\Queue\RequeueException;
use Drupal\Tests\Core\Logger\LoggerChannelFactoryTest;
use GuzzleHttp\Client;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Defines 'bb2b_baselinker_addproduct' queue worker.
 *
 * @QueueWorker(
 *   id = "bb2b_baselinker_addproduct",
 *   title = @Translation("AddProduct"),
 *   cron = {"time" = 60}
 * )
 */
class AddProductQueue extends QueueWorkerBase {

  /**
   * The http client.
   *
   * @var \GuzzleHttp\Client
   */
  protected $httpClient;

  /**
   * The logger.
   *
   * @var \Drupal\Core\Logger\LoggerChannelInterface
   */
  protected $logger;

  public function __construct(
    array $configuration, $plugin_id,
    $plugin_definition,
    Client $httpClient,
    LoggerChannelFactoryInterface $logger_factory
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->httpClient = $httpClient;
    $this->logger = $logger_factory->get('bb2b_baselinker');
  }

  public static function create (
    ContainerInterface $container,
    array $configuration,
    $plugin_id,
    $plugin_definition
  ) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('http_client'),
      $container->get('logger.factory')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function processItem($data) {
    // @todo Process data here.
    $params = [
      'storage_id' => '4721',
      'product_id' => $data['product']->id(),
      'ean' => $data['product']->get('ean')->value,
    ];

    try {
      $response = $this->httpClient->request('post', $data['connected_domain'], [
        'headers' => [
          'Content-Type' => 'application/x-www-form-urlencoded',
          'X-BLToken' => $data['token'],
        ],
        'form_params' => [
          'method' => 'addProduct',
          'parameters' => $params,
        ]
      ]);
    }
    catch (RequeueException $e) {
      $this->logger->debug('BaseLinker request failed with the message: @message', [
        '@message' => $e->getMessage(),
      ]);
    }

    $response = json_decode($response->getStatusCode());
    return $response;

  }

}
<?php

namespace Drupal\bb2b_baselinker;

use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\Core\Asset\AssetCollectionRendererInterface;
use Drupal\Core\Asset\AssetResolverInterface;
use Drupal\Core\Asset\AttachedAssets;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ExtensionPathResolver;
use Drupal\Core\Extension\InfoParserInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\File\FileUrlGeneratorInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Queue\QueueFactory;
use Drupal\Core\Queue\RequeueException;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Theme\ThemeInitializationInterface;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use GuzzleHttp\RequestOptions;
use Mpdf\Mpdf;
use Mpdf\Output\Destination;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * BaseLinker Sync Service.
 */
class SyncService {

  use StringTranslationTrait;

  /**
   * Get orders method name.
   *
   * @var string
   */
  const GET_ORDERS_METHOD = 'getOrders';

  /**
   * Last order confirmed time key.
   *
   * @var string
   */
  const LAST_ORDER_CONFIRMED_TIME = 'bb2b_baselinker.last_order_confirmed_time';

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The config.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected $config;

  /**
   * The config for athenapdf.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected $athenapdfConfig;

  /**
   * The logger.
   *
   * @var \Drupal\Core\Logger\LoggerChannelInterface
   */
  protected $logger;

  /**
   * The http client.
   *
   * @var \GuzzleHttp\Client
   */
  protected $httpClient;

  /**
   * The order queue.
   *
   * @var \Drupal\Core\Queue\QueueFactory
   */
  protected $getOrderQueue;

  /**
   * The state.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * The renderer.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * The theme handler.
   *
   * @var \Drupal\Core\Extension\ThemeHandlerInterface
   */
  protected $themeHandler;

  /**
   * The extension path resolver.
   *
   * @var \Drupal\Core\Extension\ExtensionPathResolver
   */
  protected $extensionPathResolver;

  /**
   * The info parser.
   *
   * @var \Drupal\Core\Extension\InfoParserInterface
   */
  protected $infoParser;

  /**
   * The theme initialization.
   *
   * @var \Drupal\Core\Theme\ThemeInitializationInterface
   */
  protected $themeInitialization;

  /**
   * The asset resolver.
   *
   * @var \Drupal\Core\Asset\AssetResolverInterface
   */
  protected $assetResolver;

  /**
   * The CSS collection renderer.
   *
   * @var \Drupal\Core\Asset\AssetCollectionRendererInterface
   */
  protected $cssCollectionRenderer;

  /**
   * The current request.
   *
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $request;

  /**
   * File system.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * The file URL generator.
   *
   * @var \Drupal\Core\File\FileUrlGeneratorInterface
   */
  protected $fileUrlGenerator;

  /**
   * Constructs a new SyncService object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The configuration factory.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory_athenapdf
   *   The configuration factory for athenapdf api.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger.
   * @param \GuzzleHttp\Client $http_client
   *   The http client.
   * @param \Drupal\Core\Queue\QueueFactory $queue_factory
   *   The queue factory.
   * @param \Drupal\Core\State\StateInterface $state
   *   The state.
   * @param \Drupal\Core\Database\Connection $database
   *   The database connection.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer.
   * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
   *   The theme handler.
   * @param \Drupal\Core\Extension\ExtensionPathResolver $extension_path_resolver
   *   The extension path resolver.
   * @param \Drupal\Core\Extension\InfoParserInterface $info_parser
   *   The info parser.
   * @param \Drupal\Core\Theme\ThemeInitializationInterface $theme_initialization
   *   The theme initialization.
   * @param \Drupal\Core\Asset\AssetResolverInterface $asset_resolver
   *   The asset resolver.
   * @param \Drupal\Core\Asset\AssetCollectionRendererInterface $css_collection_renderer
   *   The CSS collection renderer.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request stack.
   * @param \Drupal\Core\File\FileSystemInterface $fileSystem
   *   File System.
   * @param \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator
   *   The file URL generator.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    ConfigFactoryInterface $config_factory,
    ConfigFactoryInterface $config_factory_athenapdf,
    LoggerChannelFactoryInterface $logger_factory,
    Client $http_client,
    QueueFactory $queue_factory,
    StateInterface $state,
    Connection $database,
    RendererInterface $renderer,
    ThemeHandlerInterface $theme_handler,
    ExtensionPathResolver $extension_path_resolver,
    InfoParserInterface $info_parser,
    ThemeInitializationInterface $theme_initialization,
    AssetResolverInterface $asset_resolver,
    AssetCollectionRendererInterface $css_collection_renderer,
    RequestStack $request_stack,
    FileSystemInterface $fileSystem,
    FileUrlGeneratorInterface $file_url_generator
  ) {
    $this->entityTypeManager = $entity_type_manager;
    $this->config = $config_factory->get('bb2b_baselinker.settings');
    $this->athenapdfConfig = $config_factory_athenapdf->get('athenapdf_api.settings');
    $this->logger = $logger_factory->get('bb2b_baselinker');
    $this->httpClient = $http_client;
    $this->getOrderQueue = $queue_factory->get('get_orders_from_baselinker');
    $this->addProductQueue = $queue_factory->get('bb2b_baselinker_addproduct');
    $this->state = $state;
    $this->database = $database;
    $this->renderer = $renderer;
    $this->themeHandler = $theme_handler;
    $this->extensionPathResolver = $extension_path_resolver;
    $this->infoParser = $info_parser;
    $this->themeInitialization = $theme_initialization;
    $this->assetResolver = $asset_resolver;
    $this->cssCollectionRenderer = $css_collection_renderer;
    $this->request = $request_stack->getCurrentRequest();
    $this->fileSystem = $fileSystem;
    $this->fileUrlGenerator = $file_url_generator;
  }

  /**
   * Get orders from BaseLinker API.
   *
   * A maximum of 100 orders are returned at a time.
   */
  public function getOrders() {
    // The buyer's data are deleted after 30 days of shipment.
    $date_confirmed_from = $this->state
      ->get(self::LAST_ORDER_CONFIRMED_TIME, strtotime('-30 days'));

    $parameters = [
      'date_confirmed_from' => $date_confirmed_from,
    ];
    $items = $this->getItems(self::GET_ORDERS_METHOD, $parameters);

    $api_orders = $items['orders'] ?? [];
    if ($api_orders && $items['status'] === 'SUCCESS') {
      foreach ($api_orders as $order) {
        if ($order['delivery_fullname'] !== '-') {
          $query = $this->database->select('queue', 'q');
          $query->condition('name', 'get_orders_from_baselinker');
          $query->condition('data', serialize($order));
          $query->fields('q', ['item_id']);

          // Skip same queue items.
          if (empty($query->execute()->fetchAll())) {
            $this->getOrderQueue->createItem($order);
          }
        }
      }
    }

  }

  /**
   * Sync products to BaseLinker API.
   */
  public function addProduct() {
    // BaseLinker API credentials.
    $data = [];
    $data['token'] = $this->config->get('token');
    $data['connected_domain'] = $this->config->get('connected_domain');

    // Get products that we want to integrate in BaseLinker.
    $products = $this->entityTypeManager
      ->getStorage('commerce_product')
      ->loadMultiple();

    // Send request to BaseLinker.
    foreach ($products as $product) {
      $data['product'] = $product;

      $params = [
        'storage_id' => '4721',
        'product_id' => $data['product']->id(),
      ];

      try {
        $response = $this->httpClient->request('post', $data['connected_domain'], [
          'headers' => [
            'Content-Type' => 'application/x-www-form-urlencoded',
            'X-BLToken' => $data['token'],
          ],
          'form_params' => [
            'method' => 'addProduct',
            'parameters' => $params,
          ]
        ]);
      }
      catch (RequeueException $e) {
        $this->logger->debug('BaseLinker request failed with the message: @message', [
          '@message' => $e->getMessage(),
        ]);
      }

      $response = json_decode($response->getStatusCode());
    }
  }

  /**
   * Request to the connected domain.
   *
   * @param string $method
   *   Which method is used for request.
   * @param array $parameters
   *   Order parameters for request.
   *
   * @return array
   *   Return items.
   */
  public function getItems(string $method, array $parameters = []): array {
    $token = $this->config->get('token');
    $connected_domain = $this->config->get('connected_domain');

    $base_parameters = [];
    if ($method === self::GET_ORDERS_METHOD) {
      $base_parameters = [
        'get_unconfirmed_orders' => FALSE,
      ];
    }
    $parameters = array_merge($base_parameters, $parameters);

    try {
      $response = $this->httpClient->request('post', $connected_domain, [
        'headers' => [
          'Content-Type' => 'application/x-www-form-urlencoded',
          'X-BLToken' => $token,
        ],
        'form_params' => [
          'method' => $method,
          'parameters' => json_encode($parameters),
        ],
        'verify' => FALSE,
        'http_errors' => FALSE,
      ]);
    }
    catch (RequestException $e) {
      $this->logger->debug('BaseLinker request failed with the message: @message', [
        '@message' => $e->getMessage(),
      ]);
    }

    $this->logger->debug('BaseLinker API response: <pre>@body</pre>', [
      '@body' => $response ? $response->getBody()->getContents() : '',
    ]);

    $items = json_decode($response->getBody(), TRUE);

    return $items ?: [];
  }

  /**
   * Generate PDF file.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   *   Order Interface.
   * @param bool $is_html
   *   Html.
   * @param bool $return_with_file
   *   Return with file.
   *
   * @return string|\Symfony\Component\HttpFoundation\Response|null
   *   Retrun response.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Theme\MissingThemeDependencyException
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function generatePdf(OrderInterface $order, bool $is_html = FALSE, bool $return_with_file = FALSE) {
    $renderer = $this->renderer;
    $theme = $this->themeHandler->getDefault();

    $theme_path = $this->extensionPathResolver->getPath('theme', $theme);
    $theme_info = $this->infoParser->parse("$theme_path/$theme.info.yml");
    $pdf_title = $this->t('Baselinker');

    $applying_guidelines = NULL;

    $order_items = [];

    foreach ($order->getItems() as $order_item) {
      $title = $order_item->get('title')->value;
      $sku = substr($title, strpos($title, ":") + 1);
      $shipping = $this->entityTypeManager->getStorage('commerce_shipment')
        ->load($order->get('shipments')[0]->target_id);

      // Get asin from product variation.
      $product = $this->entityTypeManager->getStorage('commerce_product')->load($order_item->getPurchasedEntityId());

      if ($product == NULL) {
        continue;
      }

      $order_items[] = [
        'quantity' => $order_item->get('quantity')->value,
        'title' => $title,
        'price' => $order_item->get('total_price')->number,
        'sku' => $sku,
        'shipping' => $shipping->get('amount')[0]->number,
      ];
    }

    $save_order = [
      'delivery_fullname' => $order->getBillingProfile()->get('address')[0]->given_name . ' ' . $order->getBillingProfile()->get('address')->family_name,
      'delivery_address' => $order->getBillingProfile()->get('address')->address_line1,
      'delivery_postal_code' => $order->getBillingProfile()->get('address')->postal_code,
      'delivery_city' => $order->getBillingProfile()->get('address')[0]->locality,
      'delivery_country' => $order->getBillingProfile()->get('address')[0]->country_code,
      'order_number' => $order->getOrderNumber(),
      'date_add' => date('D., d.M.Y', $order->get('created')->value),
      'order_items' => $order_items,
    ];

    $currency = $this->entityTypeManager->getStorage('commerce_currency')->load($order->getTotalPrice()->getCurrencyCode());

    $build = [
      '#theme' => 'belmilb2b_baselinker_pdf',
      '#order_total_paid' => $order->getTotalPrice()->getNumber(),
      '#pdf_title' => $pdf_title,
      '#title' => 'test',
      '#applying_guidelines' => $applying_guidelines,
      '#order' => $save_order,
      '#attached' => [
        'library' => $theme_info['libraries'],
      ],
      '#currency' => $currency->getSymbol(),
    ];

    $logo = $this->themeInitialization->getActiveThemeByName($theme)
      ->getLogo();
    if (strpos($logo, '.svg')) {
      $logo = str_replace('.svg', '.png', $logo);
    }

    $build['#site_logo'] = $logo;

    $context = new RenderContext();

    $css_assets = $this->assetResolver->getCssAssets(AttachedAssets::createFromRenderArray($build), TRUE);
    $rendered_css = $this->cssCollectionRenderer->render($css_assets);

    /** @var \Drupal\Core\Cache\CacheableDependencyInterface $rendered_css_build */
    $rendered_css_build = $this->renderer->executeInRenderContext($context, function () use ($rendered_css, $renderer) {
      return $renderer->render($rendered_css);
    });

    if (!$context->isEmpty()) {
      $bubbleable_metadata = $context->pop();
      BubbleableMetadata::createFromObject($rendered_css_build)
        ->merge($bubbleable_metadata);
    }

    $build['#rendered_css'] = $rendered_css_build;

    /** @var \Drupal\Core\Cache\CacheableDependencyInterface $html */
    $html = $this->renderer->executeInRenderContext($context, function () use ($build, $renderer) {
      return $renderer->render($build);
    });

    if (!$context->isEmpty()) {
      $bubbleable_metadata = $context->pop();
      BubbleableMetadata::createFromObject($html)
        ->merge($bubbleable_metadata);
    }
    $host = $this->request->getSchemeAndHttpHost();

    if (!$is_html && strpos($host, 'docker') !== FALSE) {
      $host = 'http://nginx';
    }

    $media_string = '<link rel="stylesheet" media="all" href=""';
    $css_string = '<link rel="stylesheet" type="text/css" href=""';

    $html = str_replace('<img src=""', '<img src=""' . $host, $html);
    $html = str_replace($media_string, $media_string . $host, $html);
    $html = str_replace($css_string, $css_string . $host, $html);

    if (!$is_html) {
      $destination_dir = 'public://baselinker_order_pdf';
      $destination = $destination_dir . '/baselinker-pdf- ' . $save_order['order_number'] . '.pdf';
      $this->fileSystem->prepareDirectory($destination_dir, FileSystemInterface::CREATE_DIRECTORY || FileSystemInterface::MODIFY_PERMISSIONS);

      $pdf_data = $this->httpClient
        ->request('POST', $this->athenapdfConfig->get('endpoint') . '?auth=' . $this->athenapdfConfig->get('auth_key') . '&ext=html', [
          RequestOptions::MULTIPART => [
            [
              'name' => 'file',
              'contents' => $html,
              'filename' => 'input.html',
              'headers' => [
                'Content-Type' => 'text/html; charset=utf-8',
              ],
            ],

          ],

          RequestOptions::SINK => $destination,
        ])->getBody()->getContents();

      $pdf_file = $this->fileSystem
        ->saveData($pdf_data, $destination, FileSystemInterface::EXISTS_REPLACE);

      $order->field_documents->target_id = $pdf_file;
      $order->save();

      if ($return_with_file) {
        return $pdf_file ? $this->fileUrlGenerator->generateAbsoluteString($pdf_file) : NULL;
      }
      else {
        $this->setPDFTitle($destination, $pdf_title);

        $response = new Response();
        $response->headers->set('Content-Type', 'application/pdf');
        $response->headers->set('Content-Disposition', 'inline; filename="' . $pdf_title . '.pdf"');
        $response->setContent($pdf_data);

        return $response;
      }
    }
    else {
      return new Response($html);
    }

    throw new NotFoundHttpException();

  }

  /**
   * Set PDF title.
   *
   * @param string $outputFilePath
   *   Output file path.
   * @param string $title
   *   Title.
   */
  protected function setPdfTitle(string $outputFilePath, string $title) {
    try {
      $mpdf = new Mpdf(['tempDir' => $this->fileSystem->getTempDirectory()]);
      $page_count = $mpdf->setSourceFile($outputFilePath);
      for ($i = 1; $i <= $page_count; $i++) {
        $import_page = $mpdf->ImportPage($i);
        $mpdf->UseTemplate($import_page);

        if ($i < $page_count) {
          $mpdf->AddPage();
        }
      }

      $mpdf->setTitle($title);
      $mpdf->Output($outputFilePath, Destination::FILE);
    }
    catch (\Exception $e) {
      // Do nothing.
    }
  }

}
protected function sendPassMail($order) {
    // Gathering values for mail.
    $langcode = $order->getCustomer()->getPreferredLangcode();
    $client = $order->getCustomer()->name->value;
    $shipping_information = \Drupal::service('commerce_shipping.order_shipment_summary')->build($order);

    $body = [
      '#theme' => 'linker_order_pass',
      '#order' => $order,
      '#shipping_information' => $shipping_information,
    ];

    $params = [
      'headers' => [
        'Content-Type' => 'text/html; charset=UTF-8;',
        'Content-Transfer-Encoding' => '8Bit',
      ],
      'id' => 'linker_order_pass',
      'langcode' => $langcode,
      'subject' => $client . ' issued the order ' . $order->id(),
      'body' => $body,
    ];

    $this->mailManager
      ->mail('bb2b_linker', $params['id'], 'bestellung@bescool.net', $params['langcode'], $params);
  }

// DI za mailManager-a.

/**
   * The mail manager.
   *
   * @var \Drupal\Core\Mail\MailManagerInterface
   */
  protected $mailManager;

/**
 * Implements hook_mail().
 */
function bb2b_linker_mail($key, &$message, $params) {
  switch ($key) {
    case 'commerce_tracking_code':
    case 'linker_order_rejected':
    case 'linker_order_returned':
    case 'linker_order_not_pass':
    case 'linker_order_pass':
      /** @var \Drupal\Core\Render\RendererInterface $renderer */
      $renderer = \Drupal::service('renderer');

      if (isset($params['headers'])) {
        $message['headers'] = array_merge($message['headers'], $params['headers']);
      }
      if (!empty($params['from'])) {
        $message['from'] = $params['from'];
      }
      $message['subject'] = $params['subject'];
      $message['body'][] = $renderer->render($params['body']);
      break;
  }
}
if ($view->id() === 'more_like_this' &&
    $view->current_display === 'rest_similar_by_popularity'
  ) {
    $product_id = $view->args[0];
    $product = \Drupal::entityTypeManager()
      ->getStorage('commerce_product')
      ->load($product_id);
    $term = $product->get('app_group')->referencedEntities()[0];
    $top_term = get_top_level_parent($term);
    if ($top_term) {
      switch ($top_term->get('name')->value) {
        case 'Kültéri lámpák' || 'Beltéri lámpák':
          // Recommended manufacturer.
          $manufacturer = \Drupal::entityTypeManager()
            ->getStorage('taxonomy_term')
            ->loadByProperties([
              'vid' => 'manufacturer',
              'name' => 'AZzardo',
            ]);
          $manufacturer = reset($manufacturer);
          // Get all products belonging to the same term (group)
          // and recommended manufacturer.
          $products = \Drupal::entityTypeManager()
            ->getStorage('commerce_product')
            ->loadByProperties([
              'app_group' => $term->id(),
              'app_manufacturer' => $manufacturer->id(),
            ]);
          foreach ($products as $key => $product) {
            $onDiscount = checkIfOnDiscountAndOnStock($product);
            if (!$onDiscount) {
              unset($products[$key]);
            }
          }
          $product_ids = [];
          array_walk($products, function ($product) use (&$product_ids) {
            $product_ids[] = $product->id();
          });
          $query->addWhere(0, 'product_id', $product_ids, 'IN');
          break;
      }
    }
  }
  

function checkIfOnDiscountAndOnStock($product): bool {
  $variations = $product->getVariations();
  foreach ($variations as $variation) {
    if (!empty($variation->get('list_price')) && $variation->get('app_purchaseitem')->value == 1) {
      if ($variation->get('list_price')->number > $variation->get('price')->number) {
        return TRUE;
      }
    }
  }
  return FALSE;
}

function get_top_level_parent($term) {
  if ($term->hasField('parent') && $term->get('parent')->target_id !== '0') {
    $term = $term->get('parent')->referencedEntities()[0];
    return get_top_level_parent($term);
  }
  else {
    return $term;
  }
}
/**
 * Implements hook_views_data().
 */
function app_core_views_data() {
  $data  = [];

  $data['views']['recommended_products'] = [
    'title' => t('Recommended products - Custom Filter' ),
    'filter' => [
      'title' => t('Recommended products - Custom Filter' ),
      'field' => 'id',
      'id' => 'recommended_products'
    ]
  ];

  return $data;
}
<?php

namespace Drupal\app_core\Plugin\views\filter;

use Drupal\views\Plugin\views\filter\FilterPluginBase;

/**
 * Filter for recommended products.
 *
 * @ingroup views_filter_handlers
 *
 * @ViewsFilter("recommended_products")
 */
class RecommendedProductsFilter extends FilterPluginBase {

  public function query() {
    $this->ensureMyTable();
    $product_id = $this->view->args[0];
    $product = \Drupal::entityTypeManager()
      ->getStorage('commerce_product')
      ->load($product_id);
    $term = $product->get('app_group')->referencedEntities()[0];
    // Recommended manufacturer.
    $manufacturer = \Drupal::entityTypeManager()
      ->getStorage('taxonomy_term')
      ->loadByProperties([
        'vid' => 'manufacturer',
        'name' => 'AZzardo',
      ]);
    $manufacturer = reset($manufacturer);
    // Get all products belonging to the same term (group)
    // and recommended manufacturer.
    $products = \Drupal::entityTypeManager()
      ->getStorage('commerce_product')
      ->loadByProperties([
        'app_group' => $term->id(),
        'app_manufacturer' => $manufacturer->id(),
      ]);
    foreach ($products as $key => $product) {
      $onDiscount = $this->checkIfOnDiscountAndOnStock($product);
      if (!$onDiscount) {
        unset($products[$key]);
      }
    }
    $product_ids = [];
    array_walk($products, function($product) use (&$product_ids) {
      $product_ids[] = $product->id();
    });
    $this->query->addWhere(0, 'product_id', $product_ids, 'IN');
    $mile = 'mile';
  }

  public function checkIfOnDiscountAndOnStock($product){
    $variations = $product->getVariations();
    foreach ($variations as $variation) {
      if (!empty($variation->get('list_price')) && $variation->get('app_purchaseitem')->value == 1) {
        if ($variation->get('list_price')->number > $variation->get('price')->number) {
          return TRUE;
        }
      }
    }
    return FALSE;
  }

}
<?php

namespace Drupal\app_core\Plugin\views\filter;

use Drupal\views\Plugin\views\filter\FilterPluginBase;

/**
 * Filter for recommended products.
 *
 * @ingroup views_filter_handlers
 *
 * @ViewsFilter("recommended_products")
 */
class RecommendedProductsFilter extends FilterPluginBase {

  public function query() {
    $this->ensureMyTable();
    $product_id = $this->view->args[0];
    $product = \Drupal::entityTypeManager()
      ->getStorage('commerce_product')
      ->load($product_id);
    $term = $product->get('app_group')->referencedEntities()[0];
    // Get all products belonging to the same term (group).
    $products = \Drupal::entityTypeManager()
      ->getStorage('commerce_product')
      ->loadByProperties([
        'app_group' => $term->id(),
      ]);
    $product_ids = [];
    array_walk($products, function($product) use (&$product_ids) {
      $product_ids[] = $product->id();
    });
    $this->query->addWhere(0, 'product_id', $product_ids, 'IN');
//    $product_top_group = $this->findProductsTopGroup($term);
//    $child_terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree('group', $product_top_group->id());
//    $acceptable_terms = [];
//    foreach ($child_terms as $child_term) {
//      $acceptable_terms[] = $child_term->name;
//    }
//    $products = \Drupal::entityTypeManager()->getStorage('commerce_product')->loadMultiple();
    $mile = 'mile';
  }

//  public function findProductsTopGroup($term) {
//    if ($term->hasField('parent') && $term->get('parent')->target_id !== '0') {
//      $term = $term->get('parent')->referencedEntities()[0];
//      return $this->findProductsTopGroup($term);
//    }
//    else {
//      return $term;
//    }
//
//  }

}
if ($display->getComponent('item_approvement_table')) {
      $form = \Drupal::classResolver()->getInstanceFromDefinition(PaymentRequestItemsApprovementForm::class);
      $form->setPaymentRequest($entity);
      $form_state = new FormState();
      $form_array = \Drupal::formBuilder()->buildForm($form, $form_state);
      $form_array['#current_tab_redirect'] = TRUE;
      $build['item_approvement_table'] = $form_array;
    }
+------------+--------------------------------------------------+-----------+
| Collection | Config                                           | Operation |
+------------+--------------------------------------------------+-----------+
|            | field.storage.user.field_phone_number            | Create    |
|            | field.storage.node.field_media_contact           | Create    |
|            | field.field.node.news.field_media_contact        | Create    |
|            | field.field.user.user.field_phone_number         | Create    |
|            | user.role.media_team                             | Create    |
|            | system.action.user_remove_role_action.media_team | Create    |
|            | system.action.user_add_role_action.media_team    | Create    |
|            | core.entity_form_display.node.news.default       | Update    |
|            | core.entity_view_display.user.user.default       | Update    |
|            | core.entity_view_display.user.user.compact       | Update    |
|            | core.entity_view_display.node.news.teaser_card   | Update    |
|            | core.entity_view_display.node.news.teaser        | Update    |
|            | core.entity_view_display.node.news.image_card    | Update    |
|            | core.entity_view_display.node.news.default       | Update    |
|            | core.entity_form_display.user.user.register      | Update    |
|            | core.entity_form_display.user.user.default       | Update    |
|            | content_access.settings                          | Update    |
+------------+--------------------------------------------------+-----------+
/**
 * Implements hook_preprocess_HOOK().
 */
function carters_core_preprocess_facets_result_item(&$variables) {
  if ($variables['facet']->get('name') == 'Popust') {
    $variables['value'] = $variables['value'] . '%';
  }
}
$types = [];
$contentTypes = \Drupal::entityTypeManager()->getStorage('node_type')->loadMultiple();
foreach ($contentTypes as $contentType) {
  $types[] = $contentType->id();
}
<?php

/**
 * @file
 * Contains musin_core.module.
 */

use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Url;

/**
 * Implements hook_views_data_alter().
 */
function musin_core_views_data_alter(array &$data) {

  $data['private_message_threads']['members_list'] = [
    'title' => t('Member(s) name list'),
    'help' => t('The member(s) name of the private message thread'),
    'field' => [
      'id' => 'musin_core_private_message_members_list',
    ],
  ];

  $data['private_message_threads']['members_pictures'] = [
    'title' => t('Member(s) pictures'),
    'help' => t('The member(s) pictures of the private message thread'),
    'field' => [
      'id' => 'musin_core_private_message_members_pictures',
    ],
  ];

  $data['private_message_threads']['thread_last_message'] = [
    'title' => t('Last message'),
    'help' => t('The last message of the private message thread'),
    'field' => [
      'id' => 'musin_core_private_message_thread_last_message',
    ],
  ];

  $data['private_message_threads']['thread_is_unread'] = [
    'title' => t('Is unread or not'),
    'help' => t('The last message is unreaded of the private message thread'),
    'field' => [
      'id' => 'musin_core_private_message_thread_is_unread',
    ],
  ];

}

/**
 * Implements hook_entity_extra_field_info().
 */
function musin_core_entity_extra_field_info() {
  $extra_field = [];

  $extra_field['private_message']['private_message']['display']['author_image'] = [
    'label' => t('Author image'),
    'description' => t('Author image.'),
    'weight' => 100,
    'visible' => TRUE,
  ];

  $extra_field['private_message']['private_message']['display']['author_name'] = [
    'label' => t('Author name'),
    'description' => t('Author name.'),
    'weight' => 100,
    'visible' => TRUE,
  ];

  return $extra_field;
}

/**
 * Implements hook_ENTITY_TYPE_view().
 */
function musin_core_private_message_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {

  if ($display->getComponent('author_image')) {

    /** @var \Drupal\musin_core\MessagesService $messages_service */
    $messages_service = \Drupal::service('musin_core.messages.service');

    $build['author_image'] = $messages_service->getUserPictureElement($entity->getOwner());

  }
  if ($display->getComponent('author_name')) {

    /** @var \Drupal\private_message\Entity\PrivateMessage $entity*/
    //$author_name = $entity->getOwner()->get('field_first_name')->value . ' ' . $entity->getOwner()->get('field_last_name')->value;
    $author_name = $entity->getOwner()->get('name')->value;

    $build['author_name'] = [
      '#type' => 'markup',
      '#markup' => $author_name,
    ];

  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function musin_core_form_views_exposed_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $view = $form_state->getStorage('view');

  if ($view && $view['view']->id() == 'search') {
    $form['search_api_fulltext_1']['#prefix'] = '<div class="search-dropdown">';
    $form['field_genres']['#suffix'] = '</div>';
    $form['field_instruments']['#options']['All'] = 'Instruments';
    $form['field_genres']['#options']['All'] = 'Genres';
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 * Redirect user to profile page after saving the profile
 */

function musin_core_form_alter(&$form, $form_state, $form_id) {
  if ($form_id === 'user_form') {
    $form['#after_build'][] = '_musin_core_user_edit_change_password_label';
    $form['actions']['submit']['#submit'][] = 'musin_core_user_edit_form_submit';
  }

  if ($form_id === 'node_gig_edit_form') {
    $form['revision_information']['#access'] = FALSE;
  }
}

function _musin_core_user_edit_change_password_label($form, &$form_state) {
  //dsm($form['group_email_password_artist_name']['#groups']);
  $form['group_email_password_artist_name']['#groups']['group_email_password_artist_name'][0]['pass']['pass1']['#title'] = t('New password');
  $form['group_email_password_artist_name']['#groups']['group_email_password_artist_name'][0]['pass']['pass2']['#title'] = t('Confirm new password');

  return $form;
}


/**
 * Implements hook_field_widget_file_generic_form_alter().
 */
function musin_core_field_widget_file_generic_form_alter(&$element, FormStateInterface $form_state, $context) {
  if ($context['form']['#parents'][0] == "field_sample_tracks") {
    $element['#after_build'][] = '_set_description_field_required';
  }
}

function _set_description_field_required($element, FormStateInterface $form_state) {
  if (isset($element['description'])) {
    $element['description']['#required'] = TRUE;
  }
  return $element;
}

function musin_core_user_edit_form_submit($form, &$form_state) {
  $form_state->setRedirect('entity.user.canonical', ['user' => \Drupal::currentUser()->id()]);
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function musin_core_form_user_login_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['#submit'][] = 'musin_core_user_login_form_submit';
}

/**
 * Custom submit handler for the login form.
 */
function musin_core_user_login_form_submit($form, FormStateInterface $form_state) {
  $url = Url::fromRoute('<front>');
  $form_state->setRedirectUrl($url);
}

/**
 * Implements hook_preprocess_HOOK().
 */
function musin_core_preprocess_region(&$variables) {
  if ($variables['region'] == 'primary_navigation') {
    $variables['#cache']['contexts'][] = 'user';
  }
}

/**
 * Implements hook_entity_presave().
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 * @param $term
 */
function musin_core_entity_presave(EntityInterface $entity) {
  if ($entity instanceof \Drupal\user\UserInterface) {
    $completeness = \Drupal\musin_core\Services\UserHelperService::getProfileCompleteness($entity);
    $entity->set('field_completeness', $completeness);
//    // Add typed in instrument to users profile view.
//    $terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
//      'field_typed_in_instrument' => 1
//    ]);
//    $term = reset($terms);
//    if ($term !== false) {
//      $entity->set('field_typed_in_instrument', $term);
//    }
  }


  // Moving typed in instruments to their vocabulary.
  if ($entity instanceof \Drupal\taxonomy\Entity\Term) {
    $name = $entity->get('name')->value;
    if ($entity->get('vid')->getValue()[0]['target_id'] == 'instruments' && $entity->get('field_typed_in_instrument')->value === 1) {
      $entity->set('vid', 'extra_instruments');
    } else if ($entity->get('vid')->getValue()[0]['target_id'] == 'genres' && $entity->get('field_typed_in_genre')->value === 1) {
      $entity->set('vid', 'extra_genres');
    }
  }

}
<?php

/**
 * @file
 * Contains fontana_commerce.module.
 */

use Drupal\commerce\EntityHelper;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\RedirectCommand;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\commerce_product\Entity\ProductVariationInterface;

/**
 * Implements hook_views_data_alter().
 */
function fontana_commerce_views_data_alter(array &$data) {

  $data['views']['custom_category_filter'] = [
    'title' => t('Custom category filter'),
    'filter' => [
      'title' => t('Custom category filter'),
      'help' => t('Provides a custom filter logic.'),
      'field' => 'nid',
      'id' => 'category_views_filter',
    ],
  ];

  $data['views']['sku_filter'] = [
    'title' => t('SKU filter'),
    'filter' => [
      'title' => t('SKU filter'),
      'help' => t('Provides a custom filter for filtering orders by sku.'),
      'field' => 'id',
      'id' => 'sku_filter',
    ],
  ];

  $data['commerce_shipment']['shipping_profile'] = [
    'title' => t('Shipping Profile'),
    'help' => t('Reference to the shipping profile of a commerce shipment.'),
    'relationship' => [
      'group' => 'Shipment',
      // Views name of the table being joined to from commerce_shipment.
      'base' => 'profile',
      // Database field name in profile for the join.
      'base field' => 'profile_id',
      // Real database field name in commerce_shipment for the join, to override
      // 'unique_dummy_name'.
      'field' => 'shipping_profile__target_id',
      // ID of relationship handler plugin to use.
      'id' => 'standard',
      'label' => t('Shipping Profile'),
    ],
  ];

  $data['commerce_order']['quick_view'] = [
    'title' => t('Quick view'),
    'field' => [
      'id' => 'commerce_order_quick_view',
    ],
  ];

  $data['commerce_order']['update_state']['field'] = [
    'title' => t('Update state'),
    'help' => t('Add buttons for update the order state.'),
    'id' => 'commerce_order_update_state',
  ];

}

/**
 * Implements hook_entity_extra_field_info().
 */
function fontana_commerce_entity_extra_field_info() {
  $extra = [];

  $extra['commerce_product']['default']['display']['manufacturer_declaration'] = [
    'label' => t('Manufacturer(display: declaration)'),
    'visible' => FALSE,
  ];

  $extra['commerce_product']['default']['display']['variation_sizes'] = [
    'label' => t('Product variations size attribute'),
    'visible' => TRUE,
  ];

  $extra['commerce_product']['default']['display']['variation_colors'] = [
    'label' => t('Product variations color attribute'),
    'visible' => TRUE,
  ];

  return $extra;
}

/**
 * Implements hook_entity_view().
 */
function fontana_commerce_entity_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  if ($entity->getEntityTypeId() === 'commerce_product' && $entity->bundle() === 'default' && $display->getComponent('manufacturer_declaration')) {
    if ($entity->hasField('field_manufacturer')) {
      /** @var \Drupal\taxonomy\Entity\Term $manufacturer */
      if ($manufacturer = $entity->get('field_manufacturer')->entity) {
        $view_builder = \Drupal::entityTypeManager()->getViewBuilder('taxonomy_term');
        $build['manufacturer_declaration'] = $view_builder->view($manufacturer, 'declaration');
      }
    }
  }

  if ($view_mode === 'teaser' && $entity->getEntityTypeId() === 'commerce_product' && $entity->bundle() === 'default') {
    $sizes = [];
    $colors = [];

    /** @var \Drupal\commerce_product\Entity\ProductVariationInterface $variation */
    foreach ($entity->getVariations() as $variation) {
      if ($size = $variation->getAttributeValue('attribute_size')) {
        $sizes[] = $size->label();
      }

      if ($color = $variation->getAttributeValue('attribute_boja')) {
        $colors[] = $color->label();
      }
    }

    if ($display->getComponent('variation_sizes')) {
      $build['variation_sizes'] = [
        '#type' => 'html_tag',
        '#tag' => 'div',
        '#value' => implode(', ', array_unique($sizes)),
        '#attributes' => [
          'class' => ['size-wrapper'],
        ],
      ];
    }

    if ($display->getComponent('variation_colors')) {
      $build['variation_colors'] = [
        '#type' => 'html_tag',
        '#tag' => 'div',
        '#value' => implode(', ', array_unique($colors)),
        '#attributes' => [
          'class' => ['color-wrapper'],
        ],
      ];
    }
  }
}

/**
 * Implements hook_form_alter().
 */
function fontana_commerce_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  // Get add to cart form from product page.
  if (
    str_contains($form_id, "commerce_order_item_dc_ajax_add_cart_form_commerce_product") ||
    str_contains($form_id, 'commerce_order_item_add_to_cart_form_commerce_product')
  ) {
    // Check if product contain variations.
    if (isset($form['purchased_entity']['widget'][0]['variation']['#options'])) {
      // Get variations.
      $variations = $form['purchased_entity']['widget'][0]['variation']['#options'];
      foreach ($variations as $key => $item) {
        // Load variation by key(id).
        $variation = \Drupal::entityTypeManager()->getStorage('commerce_product_variation')->load($key);
        // Set boja if exists.
        !empty($variation->get('attribute_boja')->target_id) ? $color = $variation->get('attribute_boja')->entity->getName() : $color = "";
        // Set size if exists.
        !empty($variation->get('attribute_size')->target_id) ? $size = $variation->get('attribute_size')->entity->getName() : $size = "";
        // If both fields are empty use default option.
        if (!empty($size) || !empty($color)) {
          $form['purchased_entity']['widget'][0]['variation']['#options'][$key] = $size . " " . $color;
        }
        $item_title = $variation->getTitle();
        $variation_images = $variation->get('field_image')->getValue();
        $images = [];
        foreach ($variation_images as $image) {
          if (empty($image['title'])) {
            $image['title'] = $item_title;
          }
          if (empty($image['alt'])) {
            $image['alt'] = $item_title;
          }
          $images[] = $image;
        }
        $variation->set('field_image', $images);
      }
    }
    if (isset($form['purchased_entity']['widget'][0]['variation'])) {
      if (isset($form['purchased_entity']['widget'][0]['variation']['#value'])) {
        $variation_id = $form['purchased_entity']['widget'][0]['variation']['#value'];
      }
      else {
        $variation_id = $form['purchased_entity']['widget'][0]['variation']['#default_value'];
      }
      $variation = \Drupal::entityTypeManager()->getStorage('commerce_product_variation')->load($variation_id);
      $square_meter_per_box = $variation->get('field_square_meters_per_box')->value;
      if (!empty($square_meter_per_box)) {
        $form['quantity']['widget'][0]['value']['#step'] = '0.01';
      }
    }
  }
  // Get checkout flow form and step order information.
  if ($form_id == 'commerce_checkout_flow_multistep_default' && $form['#step_id'] == 'order_information') {
    $form['actions']['captcha'] = [
      '#type' => 'captcha',
      '#captcha_type' => 'recaptcha/reCAPTCHA',
    ];
  }

  if ($form_id == 'commerce_order_default_edit_form') {
    $order_id = \Drupal::routeMatch()->getRawParameter('commerce_order');
    $order = \Drupal::entityTypeManager()->getStorage('commerce_order')->load($order_id);
    $payment_gateway = $order->payment_gateway->first()->entity;
    if (!empty($payment_gateway)) {
      $payment_label = $payment_gateway->label();
      $form['payment_gateway'] = [
        '#type' => 'details',
        '#group' => 'advanced',
        '#open' => TRUE,
        '#title' => t('Payment Method'),
        'payment_gateway' => [
          '#type' => 'item',
          '#markup' => $payment_label,
        ],
      ];
    }
  }

  $input = $form_state->getUserInput();
  $is_ajax = (bool) ($input['_drupal_ajax'] ?? FALSE);
  if (str_contains($form_id, 'state_machine_transition_form_commerce_order_state') && $is_ajax) {
    foreach ($form['actions'] as $name => $action) {
      if (strpos($name, '#') !== FALSE) {
        continue;
      }
      $form['actions'][$name]['#ajax'] = [
        'callback' => 'fontana_commerce_order_state_ajax',
      ];
    }
  }
}

/**
 * Ajax callback for the order state form.
 *
 * @param array $form
 *   The form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The form state.
 *
 * @return \Drupal\Core\Ajax\AjaxResponse
 *   The ajax response.
 */
function fontana_commerce_order_state_ajax(array $form, FormStateInterface $form_state) {
  $response = new AjaxResponse();

  $destination = \Drupal::request()->query->get('destination');
  $response->addCommand(new RedirectCommand($destination));

  return $response;
}

/**
 * Implements hook_element_info_alter().
 */
function fontana_commerce_element_info_alter(array &$info) {
  if (isset($info['address'])) {
    $info['address']['#process'][] = 'fontana_commerce_make_address_line2_visible';
  }
}

/**
 * Process callback for address element.
 */
function fontana_commerce_make_address_line2_visible(array &$element, FormStateInterface $form_state, array &$complete_form) {
  $element['address_line2']['#title_display'] = 'before';
  return $element;
}

/**
 * Implements hook_preprocess_HOOK().
 */
function fontana_commerce_preprocess_commerce_product(&$variables) {
  /** @var \Drupal\commerce_product\Entity\ProductInterface $product_entity */
  $product_entity = $variables['product_entity'];
  $variation = $product_entity->getDefaultVariation();

  if (!$variation instanceof ProductVariationInterface) {
    $variables['calculator_visible'] = FALSE;
  }
  else {
    /** @var \Drupal\presentcommerce_box_calculator\Service\BoxCalculator $box_calculator */
    $box_calculator = \Drupal::service('presentcommerce_box_calculator.box_calculator');
    if ($box_calculator->isVisible($variation)) {
      $variables['calculator_visible'] = TRUE;
    }
    else {
      $variables['calculator_visible'] = FALSE;
    }
  }
}

/**
 * Implements hook_entity_presave().
 */
function fontana_commerce_entity_presave(EntityInterface $entity) {
  // Check if entity is product variation and if autogenerate title is selected.
  if ($entity->getEntityTypeId() == "commerce_product_variation" && $entity->get('field_auto_generate_title')->value == TRUE) {
    $title = generate_variation_title($entity);
    $entity->setTitle($title);
  }
  elseif ($entity->getEntityTypeId() == "commerce_product_variation") {
    $title_alt = generate_image_title_alt($entity);
    if ($title_alt !== "") {
      $entity->set('field_image', $title_alt);
    }
  }

  if ($entity->getEntityTypeId() == 'commerce_product') {
    $userId = \Drupal::currentUser()->id();
    $user = \Drupal::entityTypeManager()->getStorage('user')->load($userId);
    $entity->set('field_updated_by', $user);
  }
   if ($entity->getEntityTypeId() == 'commerce_order_item' && $entity->getPurchasedEntity()->get('field_square_meters_per_box')->value !== NULL) {
     $quantity = $entity->getQuantity();
     $product = \Drupal::entityTypeManager()
       ->getStorage('commerce_product_variation')
       ->load($entity->getPurchasedEntityId());
     $square_meters = $product->get('field_square_meters_per_box')->value;
     $number_of_boxes = (integer) round($quantity / $square_meters);
     if ($number_of_boxes < 1) {
       $number_of_boxes = 1;
     }
     $entity->set('field_number_of_boxes', $number_of_boxes);
   }
}

/**
 * Generate Variation title based on attributes.
 */
function generate_variation_title(EntityInterface $entity) {
  if (!$entity->getProductId()) {
    // Title generation is not possible before the parent product is known.
    return '';
  }

  $product_title = $entity->getProduct()->getTitle();
  if ($attribute_values = $entity->getAttributeValues()) {
    $attribute_labels = EntityHelper::extractLabels($attribute_values);
    $title = $product_title . ' - ' . implode(', ', $attribute_labels);
  }
  else {
    // When there are no attribute fields, there's only one variation.
    $title = $product_title;
  }

  return $title;
}

/**
 * Generate Variation title based on attributes.
 */
function generate_image_title_alt(EntityInterface $entity) {

  if (!$entity->getProductId()) {
    // Title generation is not possible before the parent product is known.
    return '';
  }

  $product_title = $entity->getProduct()->getTitle();

  $variation_images = $entity->get('field_image')->getValue();
  $images = reset($variation_images);
  foreach ($variation_images as $image) {
    if (empty($image['alt'])) {
      $image['alt'] = $product_title;
    }
    if (empty($image['title'])) {
      $image['title'] = $product_title;
    }
    $images[] = $image;
  }
  return $images;
}

/**
 * Implements hook_page_attachments().
 */
function fontana_commerce_page_attachments(array &$attachments) {
  $config = \Drupal::config('system.theme');
  $theme = \Drupal::theme()->getActiveTheme()->getName();
  if ($theme == $config->get('admin')) {
    $attachments['#attached']['library'][] = 'fontana_commerce/extra.admin';
  }
}

/**
 * Implements hook_field_widget_form_alter().
 */
function fontana_commerce_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
  // Fix problem with displaying description on shipping pane
  // for single shipping method.
  if ($context['items']->getFieldDefinition()->getName() === 'shipping_method' && $context['items']->getFieldDefinition()->getTargetEntityTypeId() === 'commerce_shipment') {
    foreach ($element['#options'] as $key => $option) {
      $title = $element[$key]["#rate"]->getService()->getLabel();
      $option = (new FormattableMarkup('@service @amount', [
        '@service' => $title,
        '@amount' => '',
      ]));
      $element['#options'][$key] = $option;
    }
  }
}

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function fontana_commerce_form_views_form_commerce_cart_form_default_alter(&$form, FormStateInterface $form_state) {
  $order_items = $form['output'][0]['#view']->result[0]->_entity->getItems();
  foreach ($order_items as $key => $order_item) {
    $purchased_entity = $order_item->getPurchasedEntity();
    if (!empty($purchased_entity->get('field_square_meters_per_box')->getValue())) {
      $form['edit_quantity'][$key]['#step'] = '0.01';
    }
  }
}
<?php

namespace Drupal\musin_core\Plugin\Field\FieldWidget;

use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Custom field widget for instruments.
 *
 * @FieldWidget(
 *   id = "instruments_widget",
 *   label = @Translation("Instruments widget"),
 *   description = @Translation("Instruments widget"),
 *   field_types = {
 *     "entity_reference",
 *     "string"
 *   }
 * )
 */
class InstrumentsWidget extends WidgetBase {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, EntityTypeManagerInterface $entityTypeManager) {
    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
    $this->entityTypeManager = $entityTypeManager;
  }

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $plugin_id,
      $plugin_definition,
      $configuration['field_definition'],
      $configuration['settings'],
      $configuration['third_party_settings'],
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    // TODO: Implement formElement() method.
    $value = isset($items[$delta]->value) ? $items[$delta]->value : '';

    $rows = [];
    $taxonomies = $this->entityTypeManager
      ->getStorage('taxonomy_term')
      ->loadByProperties([
        'vid' => 'instruments',
      ]);
    foreach ($taxonomies as $term) {
      $rows[$term->getName()] = $term->getName();
    }

    $element['first'] = [
      '#type' => 'checkboxes',
      '#options' => $rows,
      '#attributes' => [
        'name' => 'base_taxonomy',
      ]
    ];

    $element['second'] = [
      '#type' => 'textfield',
      '#title' => 'Enter your instruments',
      '#states' => [
        'visible' => [
          ':input[name="base_taxonomy"]' => ['value' => 'Other']
        ]
      ]
    ];

    return $element;
  }

}

$variation = \Drupal::entityTypeManager()->getStorage('commerce_product_variation')->load(id)->delete();
<?php

namespace Drupal\csv_import\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\Messenger;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
use Drupal\file\Entity\File;
use Drupal\node\Entity\Node;
use Drupal\paragraphs\Entity\Paragraph;
use Symfony\Component\DependencyInjection\ContainerInterface;

class CSVImportForm extends FormBase {

  public function getFormId() {
    return 'csv_import';
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['csv_file'] = [
      '#title' => 'Upload your file',
      '#type' => 'managed_file',
      '#upload_location' => 'public://',
      '#upload_validators' => [
        'file_validate_extensions' => ['csv']
      ]
    ];

    $form['actions']['#type'] = 'actions';
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save'),
    ];

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    $csv_file = $form_state->getValue('csv_file');
    $csv_file = reset($csv_file);
    $file = File::load($csv_file);
    $data = $this->csvtoarray($file->getFileUri(), ',');
    foreach ($data as $row) {
      $operations[] = ['\Drupal\csv_import\Form\CSVImportForm::addImportContentItem', [$row]];
    }

    $batch = [
      'title' => $this->t('Importing data...'),
      'operations' => $operations,
      'init_message' => $this->t('Import is starting.'),
      'finished' => '\Drupal\csv_import\Form\CSVImportForm::addImportContentItemCallback',
    ];
    batch_set($batch);

    $this->messenger()->addMessage($this->t('Your form was submitted!'));
  }

  public function csvtoarray($filename='', $delimiter) {
    if (!file_exists($filename) || !is_readable($filename)) return FALSE;
    $header = NULL;

    if(($handle = fopen($filename, 'r')) !== FALSE) {
      while(($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
        if(!$header) {
          $header = $row;
        } else {
          $data[] = array_combine($header, $row);
        }
      }
      fclose($handle);
    }
    return $data;
  }

  public static function addImportContentItem($item, &$context) {
    $message = 'Creating ' . $item['Title'];
    $results = [];
    self::create_node($item);
    $context['message'] = $message;
    $context['results'] = $item;
  }

  public function addImportContentItemCallback($success, $results, $operations) {
    $number = count($results);
    if ($success) {
      $message = new PluralTranslatableMarkup($number, 'One item processed.','@count items processed.');
    } else {
      $message = t('Finished with an error.');
    }
    \Drupal::messenger()->addMessage(t($message->render()));
  }

  public static function create_node($item)
  {
    $data = file_get_contents($item['Image']);
    $file = file_save_data($data, 'public://sample.png', \Drupal\Core\File\FileSystemInterface::EXISTS_RENAME);

    $nodes = [
      'type' => 'articles_about_programming',
      'title' => $item['Title'],
      'field_description' => $item['Description'],
      'field_myimage' => [
        'target_id' => $file->id(),
        'alt' => 'Sample',
        'title' => 'Sample file',
      ],
      'field_link_to_website' => [
        'uri' => 'https://www.' . $item['Link to website'],
        'title' => $item['Title'],
        'options' => ['target' => '_blank'],
      ],
    ];
    $node = Node::create($nodes);
    $node->setPublished(TRUE);
    $node->save();
  }
}
// If we want to use it as a dependency injection (we should),
// than this is the right way.

/**
 * Logger interface.
 *
 * @var \Psr\Log\LoggerInterface
 */
protected $logger;

// After that we add it to constructor method.

/**
* Controller_name constructor
 *
 * @param \Psr\Log\LoggerInterface $logger
 *  Logger interface.
 */
public function __construct(LoggerInterface $logger) {
  $this->logger = $logger;
}

public function someFunction(){
  if (something) {
    // Line of code...
  } else {
    $this->logger->error('Error message');
  }
}
stormtextil_core.edifact_orders:
  path: '/cron/synchronize-edifact-orders'
  defaults:
    _controller: '\Drupal\stormtextil_synchronization\Controller\SynchronizeEdifactOrders::parse'
    _title: 'Edifact Parser'
  requirements:
    _permission: 'access content'
<?php

namespace Drupal\stormtextil_config\Form;

use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class StormTextil Config Form.
 */
class StormTextilConfigForm extends ConfigFormBase {

  /**
   * EntityTypeManagerInterface.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * StormTextilConfigForm constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The Entity Type Manager.
   */
  public function __construct(EntityTypeManagerInterface $entityTypeManager) {
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'stormtextil_config.config_form';
  }

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return ['stormtextil_config.settings'];
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    $config = $this->config('stormtextil_config.settings');

    // Promotions e-mail.
    $form['promotions_email'] = [
      '#type' => 'details',
      '#title' => $this->t('Promotions in Order e-mail'),
      '#description' => $this->t('Add custom promotional text into order confirmation e-mail'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $promotions_email = $config->get('promotions_email');

    $form['promotions_email']['enabled'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable promotions'),
      '#default_value' => isset($promotions_email['enabled']) ? $promotions_email['enabled'] : '',
    ];

    $form['promotions_email']['EN'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Text - en'),
      '#format' => 'full_html',
      '#default_value' => isset($promotions_email['EN']['value']) ? $promotions_email['EN']['value'] : '',
    ];

    $form['promotions_email']['DA'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Text - da'),
      '#format' => 'full_html',
      '#default_value' => isset($promotions_email['DA']['value']) ? $promotions_email['DA']['value'] : '',
    ];

    $form['promotions_email']['DE'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Text - de'),
      '#format' => 'full_html',
      '#default_value' => isset($promotions_email['DE']['value']) ? $promotions_email['DE']['value'] : '',
    ];

    // Stock notify e-mail.
    $form['stock_notify_email'] = [
      '#type' => 'details',
      '#title' => $this->t('Stock notify e-mail'),
      '#description' => $this->t('Add custom text into stock notify e-mail'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $stock_notify_email = $config->get('stock_notify_email');

    $form['stock_notify_email']['en']['subject'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Subject - en'),
      '#default_value' => isset($stock_notify_email['en']['subject']) ? $stock_notify_email['en']['subject'] : '',
      '#size' => 50,
    ];

    $form['stock_notify_email']['en']['message'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Text - en'),
      '#format' => 'full_html',
      '#default_value' => isset($stock_notify_email['en']['message']['value']) ? $stock_notify_email['en']['message']['value'] : '',
    ];

    $form['stock_notify_email']['da']['subject'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Subject - da'),
      '#default_value' => isset($stock_notify_email['da']['subject']) ? $stock_notify_email['da']['subject'] : '',
      '#size' => 50,
    ];

    $form['stock_notify_email']['da']['message'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Text - da'),
      '#format' => 'full_html',
      '#default_value' => isset($stock_notify_email['da']['message']['value']) ? $stock_notify_email['da']['message']['value'] : '',
    ];

    $form['stock_notify_email']['de']['subject'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Subject - de'),
      '#default_value' => isset($stock_notify_email['de']['subject']) ? $stock_notify_email['de']['subject'] : '',
      '#size' => 50,
    ];

    $form['stock_notify_email']['de']['message'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Text - de'),
      '#format' => 'full_html',
      '#default_value' => isset($stock_notify_email['de']['message']['value']) ? $stock_notify_email['de']['message']['value'] : '',
    ];

    // Exchange rates.
    $form['exchange_rates'] = [
      '#type' => 'details',
      '#title' => $this->t('Exchange rates'),
      '#description' => $this->t('Defines the exchange rate for 1 unit of the currency in DKK.'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $exchange_rates = $config->get('exchange_rates');

    $form['exchange_rates']['EUR'] = [
      '#type' => 'textfield',
      '#title' => $this->t('EUR to DKK'),
      '#default_value' => isset($exchange_rates['EUR']) ? $exchange_rates['EUR'] : '',
      '#size' => 10,
    ];

    $form['exchange_rates']['SEK'] = [
      '#type' => 'textfield',
      '#title' => $this->t('SEK to DKK'),
      '#default_value' => isset($exchange_rates['SEK']) ? $exchange_rates['SEK'] : '',
      '#size' => 10,
    ];

    // Order fees.
    $form['order_fees'] = [
      '#type' => 'details',
      '#title' => $this->t('Order fees'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $form['order_fees']['administration_fee'] = [
      '#type' => 'details',
      '#title' => $this->t('Administration fees'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $administration_fee = $config->get('administration_fee');

    $form['order_fees']['administration_fee']['DKK']['range'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Invoice total (DKK)'),
      '#default_value' => isset($administration_fee['DKK']['range']) ? $administration_fee['DKK']['range'] : '',
      '#size' => 10,
    ];

    $form['order_fees']['administration_fee']['DKK']['fee'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Fee (DKK)'),
      '#default_value' => isset($administration_fee['DKK']['fee']) ? $administration_fee['DKK']['fee'] : '',
      '#size' => 10,
    ];

    $form['order_fees']['administration_fee']['EUR']['range'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Invoice total (EUR)'),
      '#default_value' => isset($administration_fee['EUR']['range']) ? $administration_fee['EUR']['range'] : '',
      '#size' => 10,
    ];

    $form['order_fees']['administration_fee']['EUR']['fee'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Fee (EUR)'),
      '#default_value' => isset($administration_fee['EUR']['fee']) ? $administration_fee['EUR']['fee'] : '',
      '#size' => 10,
    ];

    $form['order_fees']['administration_fee']['SEK']['range'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Invoice total (SEK)'),
      '#default_value' => isset($administration_fee['SEK']['range']) ? $administration_fee['SEK']['range'] : '',
      '#size' => 10,
    ];

    $form['order_fees']['administration_fee']['SEK']['fee'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Fee (SEK)'),
      '#default_value' => isset($administration_fee['SEK']['fee']) ? $administration_fee['SEK']['fee'] : '',
      '#size' => 10,
    ];

    // Added costs.
    $form['order_fees']['added_cost'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Added cost price (DKK)'),
      '#default_value' => $config->get('added_cost'),
      '#size' => 10,
    ];

    // VAT.
    $form['order_fees']['vat'] = [
      '#type' => 'textfield',
      '#title' => $this->t('VAT (%)'),
      '#default_value' => $config->get('vat'),
      '#size' => 10,
    ];

    // Balance is overdue notice.
    $form['balance_is_overdue'] = [
      '#type' => 'details',
      '#title' => $this->t('Balance is overdue notification'),
      '#description' => $this->t('Add custom notification text for user with overdue balance'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $balance_is_overdue = $config->get('balance_is_overdue');

    $form['balance_is_overdue']['enabled'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable notifications'),
      '#default_value' => isset($balance_is_overdue['enabled']) ? $balance_is_overdue['enabled'] : '',
    ];

    $form['balance_is_overdue']['EN'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Text - en'),
      '#format' => 'full_html',
      '#default_value' => isset($balance_is_overdue['EN']['value']) ? $balance_is_overdue['EN']['value'] : '',
    ];

    $form['balance_is_overdue']['DA'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Text - da'),
      '#format' => 'full_html',
      '#default_value' => isset($balance_is_overdue['DA']['value']) ? $balance_is_overdue['DA']['value'] : '',
    ];

    $form['balance_is_overdue']['DE'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Text - de'),
      '#format' => 'full_html',
      '#default_value' => isset($balance_is_overdue['DE']['value']) ? $balance_is_overdue['DE']['value'] : '',
    ];
    // Edifact orders ftp connection.
    $form['edifact'] = [
      '#type' => 'details',
      '#title' => $this->t('Ftp connection'),
      '#description' => $this->t('Configure ftp connection to remote server'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $ftp_connection = $config->get('edifact');

    $form['edifact']['server'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Ftp server'),
      '#default_value' => isset($ftp_connection['server']) ? $ftp_connection['server'] : '',
      '#size' => 30,
    ];
    $form['edifact']['username'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Username'),
      '#default_value' => isset($ftp_connection['username']) ? $ftp_connection['username'] : '',
      '#size' => 30,
    ];
    $form['edifact']['password'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Password'),
      '#default_value' => isset($ftp_connection['password']) ? $ftp_connection['password'] : '',
      '#size' => 30,
    ];
    // Samba connection.
    $form['samba'] = [
      '#type' => 'details',
      '#title' => $this->t('Samba connection'),
      '#description' => $this->t('Configure connection to remote computer'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $samba = $config->get('samba');

    $form['samba']['username'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Username'),
      '#default_value' => isset($samba['username']) ? $samba['username'] : '',
      '#size' => 30,
    ];

    $form['samba']['password'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Password'),
      '#default_value' => isset($samba['password']) ? $samba['password'] : '',
      '#size' => 30,
    ];

    $form['samba']['workgroup'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Workgroup'),
      '#default_value' => isset($samba['workgroup']) ? $samba['workgroup'] : '',
      '#size' => 30,
    ];

    $form['samba']['pdf'] = [
      '#type' => 'details',
      '#title' => $this->t('Order PDF files'),
      '#description' => $this->t('Configure connection to remote computer to synchronize PDF files'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $form['samba']['pdf']['host'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Host (IP address of remote computer)'),
      '#default_value' => isset($samba['pdf']['host']) ? $samba['pdf']['host'] : '',
      '#size' => 30,
    ];

    $form['samba']['pdf']['share'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Shared folder'),
      '#default_value' => isset($samba['pdf']['share']) ? $samba['pdf']['share'] : '',
      '#size' => 30,
    ];

    $form['samba']['invoice'] = [
      '#type' => 'details',
      '#title' => $this->t('Order invoices'),
      '#description' => $this->t('Configure connection to remote computer to synchronize invoices'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $form['samba']['invoice']['host'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Host (IP address of remote computer)'),
      '#default_value' => isset($samba['invoice']['host']) ? $samba['invoice']['host'] : '',
      '#size' => 30,
    ];

    $form['samba']['invoice']['share'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Shared folder'),
      '#default_value' => isset($samba['invoice']['share']) ? $samba['invoice']['share'] : '',
      '#size' => 30,
    ];

    // Samba connection.
    $form['theme'] = [
      '#type' => 'details',
      '#title' => $this->t('Theme settings'),
      '#description' => $this->t('Configure theme specific variables'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $theme = $config->get('theme');

    $form['theme']['theme_color'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Theme color'),
      '#default_value' => isset($theme['theme_color']) ? $theme['theme_color'] : '',
      '#description' => $this->t('Insert color HEX code'),
      '#size' => 10,
    ];

    /** @var \Drupal\taxonomy\TermStorageInterface $termStorage */
    $termStorage = $this->entityTypeManager->getStorage('taxonomy_term');
    $categoriesTree = $termStorage->loadTree('categories', 0, NULL, TRUE);
    $options = [];

    foreach ($categoriesTree as $category) {
      $options[$category->id()] = $category->label();
    }

    $form['designer_exclude_categories'] = [
      '#type' => 'details',
      '#title' => $this->t('Designer Exclude Categories'),
      '#description' => $this->t('Designer Exclude Categories'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $form['designer_exclude_categories']['exclude'] = [
      '#type' => 'select',
      '#title' => $this->t('Excluded'),
      '#default_value' => $config->get('designer_exclude_categories'),
      '#options' => $options,
      '#multiple' => TRUE,
      '#size' => 120,
      '#attributes' => [
        'style' => 'height: 240px',
      ],
    ];

    $form['designer_query_maps_id'] = [
      '#type' => 'details',
      '#title' => $this->t('Designer Query Maps'),
      '#description' => $this->t('Set the active query maps.'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $form['designer_query_maps_id']['id'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Designer Query Maps'),
      '#description' => Link::createFromRoute(
        $this->t('See more'),
        'graphql.query_maps'
      ),
      '#default_value' => $config->get('designer_query_maps_id'),
    ];

    // Checkout text.
    $form['checkout'] = [
      '#type' => 'details',
      '#title' => $this->t('Checkout'),
      '#open' => FALSE,
      '#tree' => TRUE,
    ];

    $checkout = $config->get('checkout');

    $form['checkout']['enabled'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable checkout text'),
      '#default_value' => isset($checkout['enabled']) ? $checkout['enabled'] : '',
    ];

    $form['checkout']['EN'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Checkout text - en'),
      '#format' => 'full_html',
      '#default_value' => isset($checkout['EN']['value']) ? $checkout['EN']['value'] : '',
    ];

    $form['checkout']['DA'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Checkout text - da'),
      '#format' => 'full_html',
      '#default_value' => isset($checkout['DA']['value']) ? $checkout['DA']['value'] : '',
    ];

    $form['checkout']['DE'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Checkout text - de'),
      '#format' => 'full_html',
      '#default_value' => isset($checkout['DE']['value']) ? $checkout['DE']['value'] : '',
    ];

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $form_values = $form_state->getValues();

    if (!empty($form_values['exchange_rates'])) {
      $error_msg = $this->t('Exchange rate values must be numeric and decimal points should be used. Commas are not allowed.');

      foreach ($form_values['exchange_rates'] as $key => $value) {
        if (!is_numeric($value)) {
          $form_state->setError($form['exchange_rates'][$key], $error_msg);
        }
      }
    }

    if (!empty($form_values['order_fees']['added_cost'])) {
      $error_msg = $this->t('Added cost price must be numeric and decimal points should be used. Commas are not allowed.');

      if (!is_numeric($form_values['order_fees']['added_cost'])) {
        $form_state->setError($form['order_fees']['added_cost'], $error_msg);
      }
    }

    if (!empty($form_values['order_fees']['administration_fee'])) {
      $error_msg = $this->t('Administration fee values must be numeric and decimal points should be used. Commas are not allowed.');

      foreach ($form_values['order_fees']['administration_fee'] as $currency => $item) {
        foreach ($form_values['order_fees']['administration_fee'][$currency] as $key => $value) {
          if (!is_numeric($value)) {
            $form_state->setError($form['order_fees']['administration_fee'][$currency][$key], $error_msg);
          }
        }
      }
    }

  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $config = $this->config('stormtextil_config.settings');
    $form_values = $form_state->getValues();

    $config->set('promotions_email', $form_values['promotions_email'])
      ->set('stock_notify_email', $form_values['stock_notify_email'])
      ->set('exchange_rates', $form_values['exchange_rates'])
      ->set('balance_is_overdue', $form_values['balance_is_overdue'])
      ->set('administration_fee', $form_values['order_fees']['administration_fee'])
      ->set('edifact', $form_values['edifact'])
      ->set('samba', $form_values['samba'])
      ->set('theme', $form_values['theme'])
      ->set('added_cost', $form_values['order_fees']['added_cost'])
      ->set('vat', $form_values['order_fees']['vat'])
      ->set('designer_exclude_categories', array_values($form_values['designer_exclude_categories']['exclude']))
      ->set('designer_query_maps_id', $form_values['designer_query_maps_id']['id'])
      ->set('checkout', $form_values['checkout'])
      ->save();

    Cache::invalidateTags(['designer_exclude_categories']);

    parent::submitForm($form, $form_state);
  }

}
<?php

namespace Drupal\stormtextil_core\Controller;

use Drupal\commerce_shipping\Entity\Shipment;
use Drupal\commerce_shipping\Entity\ShippingMethod;
use Drupal\commerce_shipping\ShipmentItem;
use Drupal\Core\Controller\ControllerBase;
use Drupal\physical\Weight;
use Drupal\physical\WeightUnit;
use Drupal\profile\Entity\Profile;
use EDI\Parser;
use Drupal\commerce_price\Price;
use Drupal\commerce_order\Entity\OrderItem;
use Drupal\commerce_order\Entity\Order;

class EdifactController extends ControllerBase {

  public function parse() {
    $parser = new Parser();
    $ediFile = file_get_contents('./sites/default/files/1509018E1-000523-1611970.EDI');
    $parsedEdiFile = $parser->loadString($ediFile);

    $lineItems = [];
    $orderItems = [];
    $currency = $parsedEdiFile[18][1][1];

    foreach ($parsedEdiFile as $ediElement) {
      switch($ediElement[0]) {
        case 'NAD':
          if ($ediElement[1] == 'DP') {
            $organization = $ediElement[3][0];
            $address_line1 = $ediElement[3][1];
            $postal_local = explode(" ", $ediElement[3][2]);
            $postal_code = $postal_local[0];
            $locality = $postal_local[1];
            $country_code = $ediElement[3][3];
          } else if ($ediElement[1] == 'BY') {
            $billing_address = $ediElement[5];
            $billing_city = $ediElement[6];
            $billing_company = $ediElement[4];
            $billing_zip_code = $ediElement[8];
          };
          break;
        // Name that we are going to use in profile.
        case 'CTA':
          $name = explode(" ", $ediElement[2][1]);
          $given_name = $name[0];
          $family_name = $name[1];
          break;
        case 'TAX':
          if (!isset($tax)) {
            $tax = $ediElement[5][3] / 100;
            break;
          }
        // Name of shipping method.
        case 'ALC':
          $shipping_method_name = $ediElement[2];
          break;
        case 'MOA':
          if($ediElement[1][0] == '8') {
            $shipping_price = $ediElement[1][1];
          }
        // Line item variation.
        case 'PIA':
          if ($ediElement[1] == '5') {
            $sku = $ediElement[2][0];
            $rawProductVariation = $this->entityTypeManager()
              ->getStorage('commerce_product_variation')
              ->loadByProperties([
                'sku' => $sku,
              ]);
            $productVariation = reset($rawProductVariation);
            $lineItems[$productVariation->getTitle()]['variation'] = $productVariation;
          }
          break;
        // Line item quantity.
        case 'QTY':
          $quantity = $ediElement[1][1];
          $lineItems[$productVariation->getTitle()]['quantity'] = $quantity;
          break;
        // Line item price.
        case 'PRI':
          if ($ediElement[1][0] == 'AAA') {
            $price = $ediElement[1][1];
            $lineItems[$productVariation->getTitle()]['price'] = $price;
          }
          break;
        // Number of line items.
        case 'CNT':
          $numberOfLineItems = $ediElement[1][1];
          break;
      }
    }

    // Creating order item for each line item.
    foreach ($lineItems as $lineItem) {
      $orderItem = OrderItem::create([
        'type' => 'default',
        'purchased_entity' => $lineItem['variation'],
        'quantity' => $lineItem['quantity'],
        'unit_price' => new Price($lineItem['price'], $currency),
        'overridden_unit_price' => TRUE,
      ]);
      $orderItem->save();
      $orderItems[] = $orderItem;
    }

    // Creating order.
    $order = Order::create([
      'type' => 'default',
      'mail' => $this->currentUser()->getEmail(),
      'uid' => $this->currentUser()->id(),
      'store_id' => 1,
      'order_items' => [$orderItems[0], $orderItems[1]],
      'placed' => \Drupal::time()->getCurrentTime(),
    ]);
    $order->save();

    // Creating shipment.
    if ($order->get('shipments')->count() == 0) {
      $first_shipment = Shipment::create([
        'type' => 'default',
        'order_id' => $order->id(),
        'title' => 'Shipment',
        'state' => 'ready'
      ]);
      $first_shipment->save();
    }

    foreach ($orderItems as $order_item) {
      $quantity = $order_item->getQuantity();
      $purchased_entity = $order_item->getPurchasedEntity();

      if ($purchased_entity->get('weight')->isEmpty()) {
        $weight = new Weight(1, WeightUnit::GRAM);
      } else {
        $weight_item = $purchased_entity->get('weight')->first();
        $weight = $weight_item->toMeasurement();
      }

      // Creating shipment item.
      $shipment_item = new ShipmentItem([
        'order_item_id' => $order_item ->id(),
        'title' => $purchased_entity->label(),
        'quantity' => $quantity,
        'weight' => $weight->multiply($quantity),
        'declared_value' => $order_item->getTotalPrice(),
      ]);
      $first_shipment->addItem($shipment_item);
    }
    // Creating shipping method.
    $shipping_method = ShippingMethod::create([
      'stores' => 1,
      'name' => $shipping_method_name,
      'plugin' => [
        'target_plugin_id' => 'flat_rate',
        'target_plugin_configuration' => [
          'rate_label' =>'Shipping GG',
          'rate_amount' => [
            'number' => $shipping_price, //TODO: Zameniti sa varijablom
            'currency_code' => $currency
          ]
        ],
      ],
      'status' => TRUE,
      'weight' => 0,
    ]);
    $shipping_method->save();
    // Adding newly created shipment method to shipment.
    $first_shipment->setShippingMethod($shipping_method);

    // Adding amount to shipment.
    $shipping_method_plugin = $shipping_method->getPlugin();
    $shipping_rates = $shipping_method_plugin->calculateRates($first_shipment);
    $shipping_rate = reset($shipping_rates);
    $shipping_service = $shipping_rate->getService()->getId();
    $amount = reset($shipping_rates)->getAmount();
    $first_shipment->setAmount($amount);
    $first_shipment->save();

    $order->set('shipments', [$first_shipment]);
    $order->save();

    // Creating profile using data from EDI file.
    $profile = Profile::create([
      'uid' => $order->getCustomerId(),
      'type' => 'customer',
    ]);
    $profile->address->given_name = $given_name;
    $profile->set('field_address_1', $name);
    $profile->address->family_name = $family_name;
    $profile->address->organization = $organization;
    $profile->set('field_company', $organization);
    $profile->address->country_code = $country_code;
    $profile->set('field_new_country', $country_code);
    $profile->address->locality = $locality;
    $profile->set('field_city', $locality);
    $profile->address->postal_code = $postal_code;
    $profile->set('field_zip_code', $postal_code);
    $profile->address->address_line1 = $address_line1;
    $profile->set('field_address_1', $address_line1);
    $profile->save();

    // Create a billing profile.
    if(empty($order->getBillingProfile())) {
      $billing_profile = Profile::create([
        'type' => 'customer',
        'uid' => $order->getCustomerId(),
      ]);
      $billing_profile->save();
      $billing_profile->set('field_address_1', $billing_address);
      $billing_profile->set('field_city', $billing_city);
      $billing_profile->set('field_company', $billing_company);
      $billing_profile->set('field_zip_code', $billing_zip_code);
      $billing_profile->save();
      $order->setBillingProfile($billing_profile);
      $order->save();
    }

    //TODO: Add other data to profile.

    $first_shipment->setShippingProfile($profile);
    $first_shipment->setShippingService($shipping_service);
    $first_shipment->save();
    $order->set('shipments', $first_shipment);
    // Including tax into price.
    $priceWithTax = $order->getTotalPrice()->getNumber() + ($order->getTotalPrice()->getNumber() * $tax);
    $order->set('total_price', new Price($priceWithTax, $currency));
    $order->save();

    // Checking the number of line items.
    if ($numberOfLineItems == count($orderItems)) {
      $poruka = 'Provera prošla';
    } else {
      $poruka = 'Provera nije prošla';
    }

    return [
      '#markup' => $poruka,
    ];
  }

}
/**
 * Implements hook_preprocess_HOOK().
 */
function green_deal_core_preprocess_commerce_product__teaser(&$variables) {
  $product = $variables['elements']['#commerce_product'];
  $product_variation = reset($product);
  $price = $product_variation->get('price')->number;
  $list_price = $product_variation->get('list_price')->number;

  if ($list_price != NULL) {
    $percentage = round((($list_price - $price) / $list_price) * 100);
    if ($percentage < 10) {
      $percentage = 10;
    }
    $variables['percentage'] = $percentage . '%';
  }
}

function green_deal_core_preprocess_commerce_product__full(&$variables) {
  $product = $variables['elements']['#commerce_product'];
  $product_variation = reset($product);
  $price = $product_variation->get('price')->number;
  $list_price = $product_variation->get('list_price')->number;

  if ($list_price != NULL) {
    $percentage = round((($list_price - $price) / $list_price) * 100);
    if ($percentage < 10) {
      $percentage = 10;
    }
    $variables['percentage'] = $percentage . '%';
  }
}
green_deal_core.test:
  path: '/product_action'
  defaults:
    _controller: '\Drupal\green_deal_core\Controller\ProductActionController::test'
    _title: 'Product action controller'
  requirements:
    _permission: 'access content'
<?php

namespace Drupal\green_deal_core\Controller;

use Drupal\commerce_price\Price;
use Drupal\Core\Controller\ControllerBase;

class ProductActionController extends ControllerBase {

  public function test() {

    $flag_id = 'promotion_akcija';

    $flag_service = \Drupal::service('flag');
    $flag = $flag_service->getFlagById($flag_id);
    $products = $this->entityTypeManager()
      ->getStorage('commerce_product')
      ->loadByProperties([
        'type' => 'default'
      ]);

    $variation = $this->entityTypeManager()
      ->getStorage('commerce_product_variation')
      ->load(1267);

    foreach ($products as $product) {
      if($flag_service->getEntityFlaggings($flag, $product)) {
        $variation = $product->getVariations();
        $variation = reset($variation);
        $price = $variation->getPrice()->getNumber();
        $nesto[] = $price;
        $list_price = ceil($price / 0.9);
        $variation->setListPrice(new Price($list_price, 'RSD'));
        $variation->save();
        $poruka = 'nesto';
      }
    }

    return ([
      '#markup' => $poruka,
    ]);
  }

}
// First we create order items.
    foreach ($lineItems as $lineItem) {
      $orderItem = OrderItem::create([
        'type' => 'default',
        'purchased_entity' => $lineItem['variation'],
        'quantity' => $lineItem['quantity'],
        'unit_price' => new Price($lineItem['price'], $currency),
        'overridden_unit_price' => TRUE,
      ]);
      $orderItem->save();
      $orderItems[] = $orderItem;
    }

// Than we create order.
    $order = Order::create([
      'type' => 'default',
      'mail' => $this->currentUser()->getEmail(),
      'uid' => $this->currentUser()->id(),
      'store_id' => 1,
      'order_items' => [$orderItems[0], $orderItems[1]],
      'placed' => \Drupal::time()->getCurrentTime(),
    ]);
    $order->save();

// Than we create shipment.
    if ($order->get('shipments')->count() == 0) {
      $first_shipment = Shipment::create([
        'type' => 'default',
        'order_id' => $order->id(),
        'title' => 'Shipment',
        'state' => 'ready'
      ]);
      $first_shipment->save();
    }

// After that we create data for shipment item and shipment items.
    foreach ($orderItems as $order_item) {
      $quantity = $order_item->getQuantity();
      $purchased_entity = $order_item->getPurchasedEntity();

      if ($purchased_entity->get('weight')->isEmpty()) {
        $weight = new Weight(1, WeightUnit::GRAM);
      } else {
        $weight_item = $purchased_entity->get('weight')->first();
        $weight = $weight_item->toMeasurement();
      }

      // Creating shipment item.
      $shipment_item = new ShipmentItem([
        'order_item_id' => $order_item ->id(),
        'title' => $purchased_entity->label(),
        'quantity' => $quantity,
        'weight' => $weight->multiply($quantity),
        'declared_value' => $order_item->getTotalPrice(),
      ]);
      $first_shipment->addItem($shipment_item);
    }

//Than we create shipping methods and add them to shipment.
    $shipping_method = ShippingMethod::create([
      'stores' => 1,
      'name' => $shipping_method_name,
      'plugin' => [
        'target_plugin_id' => 'flat_rate',
        'target_plugin_configuration' => [
          'rate_label' =>'Shipping GG',
          'rate_amount' => [
            'number' => $shipping_price, //TODO: Zameniti sa varijablom
            'currency_code' => $currency
          ]
        ],
      ],
      'status' => TRUE,
      'weight' => 0,
    ]);
    $shipping_method->save();
    // Adding newly created shipment method to shipment.
    $first_shipment->setShippingMethod($shipping_method);

// After that we add amount to shipment.
    $shipping_method_plugin = $shipping_method->getPlugin();
    $shipping_rates = $shipping_method_plugin->calculateRates($first_shipment);
    $shipping_rate = reset($shipping_rates);
    $shipping_service = $shipping_rate->getService()->getId();
    $amount = reset($shipping_rates)->getAmount();
    $first_shipment->setAmount($amount);
    $first_shipment->save();

    $order->set('shipments', [$first_shipment]);
    $order->save();

// And finally we create shipping and billing profile.
    $profile = Profile::create([
      'uid' => $order->getCustomerId(),
      'type' => 'customer',
    ]);
    $profile->address->given_name = $given_name;
    $profile->set('field_address_1', $name);
    $profile->address->family_name = $family_name;
    $profile->address->organization = $organization;
    $profile->set('field_company', $organization);
    $profile->address->country_code = $country_code;
    $profile->set('field_new_country', $country_code);
    $profile->address->locality = $locality;
    $profile->set('field_city', $locality);
    $profile->address->postal_code = $postal_code;
    $profile->set('field_zip_code', $postal_code);
    $profile->address->address_line1 = $address_line1;
    $profile->set('field_address_1', $address_line1);
    $profile->save();

    if(empty($order->getBillingProfile())) {
      $billing_profile = Profile::create([
        'type' => 'customer',
        'uid' => $order->getCustomerId(),
      ]);
      $billing_profile->save();
      $billing_profile->set('field_address_1', $billing_address);
      $billing_profile->set('field_city', $billing_city);
      $billing_profile->set('field_company', $billing_company);
      $billing_profile->set('field_zip_code', $billing_zip_code);
      $billing_profile->save();
      $order->setBillingProfile($billing_profile);
      $order->save();
    }

    //TODO: Add other data to profile.

    $first_shipment->setShippingProfile($profile);
    $first_shipment->setShippingService($shipping_service);
    $first_shipment->save();
    $order->set('shipments', $first_shipment);
    // Including tax into price.
    $priceWithTax = $order->getTotalPrice()->getNumber() + ($order->getTotalPrice()->getNumber() * $tax);
    $order->set('total_price', new Price($priceWithTax, $currency));
    $order->save();

{#
/**
 * @file
 * Template for the shipment confirmation.
 *
 * Available variables:
 * - order_entity: The order entity.
 * - shipment_entity: The shipment entity.
 * - shipping_profile: The profile associated with a shipment.
 * - tracking_code: The tracking code associated with the shipment.
 *
 * @ingroup themeable
 */
#}
{% set shipmentItemCount = shipment_entity.getItems|length %}
<table style="margin: 15px auto 0 auto; max-width: 768px; font-family: arial,sans-serif">
  <tbody>
  <tr>
    <td>
      <table style="margin-left: auto; margin-right: auto; max-width: 768px; text-align: center;">
        <tbody>
        <tr>
          <td>
            <a href="{{ url('<front>') }}" style="color: #0e69be; text-decoration: none; font-weight: bold; margin-top: 15px;">{{ order_entity.getStore.label }}</a>
          </td>
        </tr>
        </tbody>
      </table>
      <table style="margin-left: auto; margin-right: auto; min-width: 450px; margin: 5px auto 0 auto; border: 1px solid #cccccc; border-radius: 5px; padding: 40px 30px 30px 30px;">
        <tbody>
        <tr>
          <td style="text-align: center; font-weight: bold; padding-top:15px; padding-bottom: 15px; border-top: 1px solid #cccccc; border-bottom: 1px solid #cccccc">
            {% trans %}
              An item in your order #{{ order_entity.getOrderNumber }} has shipped!
            {% plural shipmentItemCount %}
              Items in your order #{{ order_entity.getOrderNumber }} have shipped!
            {% endtrans %}
          </td>
        </tr>
        <tr>
          <td>
            <table style="width: 100%; padding-top:15px; padding-bottom: 15px; text-align: left; border-bottom: 1px solid #cccccc">
              <tbody>
              <tr>
                <td style="font-weight: bold; padding-bottom: 15px; text-align: left; vertical-align: top;">
                  {{ 'Shipped to:'|t }}
                </td>
              </tr>
              <tr>
                <td>
                  {% block shipping_profile %}
                    {{ shipping_profile }}
                  {% endblock %}
                </td>
              </tr>
              </tbody>
            </table>
          </td>
        </tr>
        <tr>
          <td>
            {% block shipment_items %}
              <table style="padding-top: 15px; padding-bottom:15px; width: 100%">
                <tbody style="text-align: left;">
                <tr>
                  <td colspan="2" style="font-weight: bold; padding-bottom: 15px; text-align: left; vertical-align: top;">
                    {% trans %}
                      Item in shipment
                    {% plural shipmentItemCount %}
                      Items in shipment
                    {% endtrans %}
                  </td>
                </tr>
                {% for shipment_item in shipment_entity.getItems() %}
                  <tr>
                    <td>
                      {{ shipment_item.quantity|number_format }} x
                    </td>
                    <td>
                      <span>{{ shipment_item.title }}</span>
                    </td>
                  </tr>
                {% endfor %}
                </tbody>
              </table>
            {% endblock %}
          </td>
        </tr>
        {% if (tracking_code) %}
          {% block tracking_info %}
            <tr>
              <td style="font-weight: bold; padding-top:15px; padding-bottom: 15px; text-align: left; vertical-align: top; border-top: 1px solid #cccccc">
                {{ 'Tracking information:'|t }}
              </td>
            </tr>
            <tr>
              <td style="padding-bottom: 15px;">
                {{ tracking_code }}
              </td>
            </tr>
            <tr>
              <td style="padding-top:15px; padding-bottom: 15px; text-align: center; border-top: 1px solid #cccccc">
                {{ 'Thank you for your order!'|t }}
              </td>
            </tr>
          {% endblock %}
        {% endif %}
        </tbody>
      </table>
    </td>
  </tr>
  </tbody>
</table>
	/**
 * Implements hook_theme().
 */
function commerce_shipping_theme() {
  return [
    'commerce_shipment' => [
      'render element' => 'elements',
    ],
    'commerce_shipment_confirmation' => [
      'variables' => [
        'order_entity' => NULL,
        'shipment_entity' => NULL,
        'shipping_profile' => NULL,
        'tracking_code' => NULL,
      ],
    ],
  ];
}
<?php

namespace Drupal\commerce_shipping\Mail;

use Drupal\commerce\MailHandlerInterface;
use Drupal\commerce_shipping\Entity\ShipmentInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;

class ShipmentConfirmationMail implements ShipmentConfirmationMailInterface {

  use StringTranslationTrait;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The mail handler.
   *
   * @var \Drupal\commerce\MailHandlerInterface
   */
  protected $mailHandler;

  /**
   * Constructs a new ShipmentConfirmationMail object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\commerce\MailHandlerInterface $mail_handler
   *   The mail handler.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, MailHandlerInterface $mail_handler) {
    $this->entityTypeManager = $entity_type_manager;
    $this->mailHandler = $mail_handler;
  }

  /**
   * {@inheritdoc}
   */
  public function send(ShipmentInterface $shipment, $to = NULL, $bcc = NULL) {
    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = $shipment->getOrder();
    $to = isset($to) ? $to : $order->getEmail();
    if (!$to) {
      // The email should not be empty.
      return FALSE;
    }

    $subject = $this->formatPlural(
      $shipment->get('items')->count(),
      'An item for order #@number shipped!',
      'Items for your order #@number shipped!',
      ['@number' => $order->getOrderNumber()]
    );

    $profile_view_builder = $this->entityTypeManager->getViewBuilder('profile');
    $shipment_view_builder = $this->entityTypeManager->getViewBuilder('commerce_shipment');
    $body = [
      '#theme' => 'commerce_shipment_confirmation',
      '#order_entity' => $order,
      '#shipment_entity' => $shipment,
      '#shipping_profile' => $profile_view_builder->view($shipment->getShippingProfile()),
      '#tracking_code' => $shipment_view_builder->viewField($shipment->get('tracking_code'), 'default'),
    ];

    $params = [
      'id' => 'shipment_confirmation',
      'from' => $order->getStore()->getEmail(),
      'bcc' => $bcc,
      'order' => $order,
      'shipment' => $shipment,
    ];
    $customer = $order->getCustomer();
    if ($customer->isAuthenticated()) {
      $params['langcode'] = $customer->getPreferredLangcode();
    }

    return $this->mailHandler->sendMail($to, $subject, $body, $params);
  }

}
$url = "https://jsonplaceholder.typicode.com/posts";
$data = file_get_contents($url);
$characters = json_decode($data);
<?php

namespace Drupal\stormtextil_synchronization\Controller;

use Drupal\commerce_shipping\Entity\Shipment;
use Drupal\commerce_shipping\Entity\ShippingMethod;
use Drupal\commerce_shipping\ShipmentItem;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\physical\Weight;
use Drupal\physical\WeightUnit;
use Drupal\profile\Entity\Profile;
use EDI\Parser;
use Drupal\commerce_price\Price;
use Drupal\commerce_order\Entity\OrderItem;
use Drupal\commerce_order\Entity\Order;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class Synchronize Edifact Orders.
 *
 * @package Drupal\stormtextil_synchronization\Controller
 */
class SynchronizeEdifactOrders extends ControllerBase {

  /**
   * The time service.
   *
   * @var \Drupal\Component\Datetime\TimeInterface
   */
  protected $time;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $config;

  /**
   * Logger interface.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * Constructs Synchronize Edifact Orders.
   *
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The Time service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   * @param \Psr\Log\LoggerInterface $logger
   *   Logger interface.
   */
  public function __construct(TimeInterface $time, ConfigFactoryInterface $configFactory, LoggerInterface $logger) {
    $this->time = $time;
    $this->config = $configFactory;
    $this->logger = $logger;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('datetime.time'),
      $container->get('config.factory'),
      $container->get('logger.channel.default')
    );
  }

  /**
   * Parse the edi file and create an order.
   *
   * @return string[]|void
   *   Response.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   * @throws \Drupal\Core\TypedData\Exception\MissingDataException
   */
  public function parse() {
    // Login information.
    $login_data = $this->config->get('stormtextil_config.settings');
    $ftp_server = $login_data->get('edifact')['server'];
    $ftp_user = $login_data->get('edifact')['username'];
    $ftp_pass = $login_data->get('edifact')['password'];
    // Set up a connection or die.
    $ftp = ftp_connect($ftp_server) or die("Couldn't connect to $ftp_server");
    // Try to login.
    if (ftp_login($ftp, $ftp_user, $ftp_pass)) {
      echo "Connected as $ftp_user@$ftp_server\n";
    }
    else {
      echo "Couldn't connect as $ftp_user\n";
    }
    // Turn passive mode on,
    // e have to use passive mode because the,
    // running docker container is listening on a different port.
    ftp_set_option($ftp, FTP_USEPASVADDRESS, FALSE);
    ftp_pasv($ftp, TRUE);
    // Listing all companies in root folder.
    $companies = ftp_nlist($ftp, '/');
    foreach ($companies as $company) {
      // Check if this is a valid C5 ID.
      if (is_numeric(basename($company))) {
        $company_id = basename($company);
      }
      // Listing all files in stores directory.
      $files = ftp_nlist($ftp, './' . $company_id . '/archive/');
      foreach ($files as $file) {
        if ((preg_match('/^.*\.(edi)$/i', $file))) {
          // Edi file for proceeding the order.
          $ediFile = file_get_contents('ftp://' . $ftp_user . ':' . $ftp_pass . '@' . $ftp_server . '/'
            . $company_id . '/archive/' . basename($file));
          // Parsing the file.
          $parser = new Parser();
          $parsedEdiFile = $parser->loadString($ediFile);

          $lineItems = [];
          $orderItems = [];
          // Looping through all parsed EDI elements and taking
          // data for order information.
          foreach ($parsedEdiFile as $ediElement) {
            switch ($ediElement[0]) {
              // Delivery information.
              case 'NAD':
                if ($ediElement[1] == 'DP') {
                  $organization = $ediElement[3][0];
                  $address_line1 = $ediElement[3][1];
                  $postal_local = explode(" ", $ediElement[3][2]);
                  $postal_code = $postal_local[0];
                  $locality = $postal_local[1];
                  $country_code = $ediElement[3][3];
                }
                elseif ($ediElement[1] == 'BY') {
                  $billing_address = $ediElement[5];
                  $billing_city = $ediElement[6];
                  $billing_company = $ediElement[4];
                  $billing_zip_code = $ediElement[8];
                };
                break;

              // Name that we are going to use in shipment profile.
              case 'CTA':
                $name = explode(" ", $ediElement[2][1]);
                $given_name = $name[0];
                $family_name = $name[1];
                break;

              // Currency code.
              case 'CUX':
                $currency = $ediElement[1][1];
                break;

              // Tax percentage.
              case 'TAX':
                if (!isset($tax)) {
                  $tax = $ediElement[5][3] / 100;
                }
                break;

              // Name of shipping method.
              case 'ALC':
                $shipping_method_name = $ediElement[2];
                break;

              // Shipping price.
              case 'MOA':
                if ($ediElement[1][0] == '8') {
                  $shipping_price = $ediElement[1][1];
                }
                break;

              // Line item variation.
              case 'PIA':
                if ($ediElement[1] == '5') {
                  $sku = $ediElement[2][0];
                  $rawProductVariation = $this->entityTypeManager()
                    ->getStorage('commerce_product_variation')
                    ->loadByProperties([
                      'sku' => $sku,
                    ]);
                  $productVariation = reset($rawProductVariation);
                  $lineItems[$productVariation->getTitle()]['variation'] = $productVariation;
                }
                break;

              // Line item quantity.
              case 'QTY':
                $quantity = $ediElement[1][1];
                $lineItems[$productVariation->getTitle()]['quantity'] = $quantity;
                break;

              // Line item price.
              case 'PRI':
                if ($ediElement[1][0] == 'AAA') {
                  $price = $ediElement[1][1];
                  $lineItems[$productVariation->getTitle()]['price'] = $price;
                }
                break;

              // Number of line items.
              case 'CNT':
                $numberOfLineItems = $ediElement[1][1];
                break;
            }
          }

          // Creating order items.
          foreach ($lineItems as $lineItem) {
            $orderItem = OrderItem::create([
              'type' => 'default',
              'purchased_entity' => $lineItem['variation'],
              'quantity' => $lineItem['quantity'],
              'unit_price' => new Price($lineItem['price'], $currency),
              'overridden_unit_price' => TRUE,
            ]);
            $orderItem->save();
            $orderItems[] = $orderItem;
          }
          // Creating order.
          $order = Order::create([
            'type' => 'default',
            'mail' => $this->currentUser()->getEmail(),
            'uid' => $this->currentUser()->id(),
            'store_id' => 1,
            'order_items' => [$orderItems[0], $orderItems[1]],
            'placed' => $this->time->getCurrentTime(),
          ]);
          $order->save();
          // Creating shipment.
          if ($order->get('shipments')->count() == 0) {
            $first_shipment = Shipment::create([
              'type' => 'default',
              'order_id' => $order->id(),
              'title' => 'Shipment',
              'state' => 'ready',
            ]);
            $first_shipment->save();
          }
          // Caclculating weight for shipment.
          foreach ($orderItems as $order_item) {
            $quantity = $order_item->getQuantity();
            $purchased_entity = $order_item->getPurchasedEntity();

            if ($purchased_entity->get('weight')->isEmpty()) {
              $weight = new Weight(1, WeightUnit::GRAM);
            }
            else {
              $weight_item = $purchased_entity->get('weight')->first();
              $weight = $weight_item->toMeasurement();
            }
            // Creating shipment item.
            $shipment_item = new ShipmentItem([
              'order_item_id' => $order_item->id(),
              'title' => $purchased_entity->label(),
              'quantity' => $quantity,
              'weight' => $weight->multiply($quantity),
              'declared_value' => $order_item->getTotalPrice(),
            ]);
            $first_shipment->addItem($shipment_item);
          }
          // Creating shipping method.
          $shipping_method = ShippingMethod::create([
            'stores' => 1,
            'name' => $shipping_method_name,
            'plugin' => [
              'target_plugin_id' => 'flat_rate',
              'target_plugin_configuration' => [
                'rate_label' => 'Shipping GG',
                'rate_amount' => [
                  'number' => $shipping_price,
                  'currency_code' => $currency,
                ],
              ],
            ],
            'status' => TRUE,
            'weight' => 0,
          ]);
          $shipping_method->save();
          // Adding newly created shipment method to shipment.
          $first_shipment->setShippingMethod($shipping_method);
          // Adding amount to shipment.
          $shipping_method_plugin = $shipping_method->getPlugin();
          $shipping_rates = $shipping_method_plugin->calculateRates($first_shipment);
          $shipping_rate = reset($shipping_rates);
          $shipping_service = $shipping_rate->getService()->getId();
          $amount = reset($shipping_rates)->getAmount();
          $first_shipment->setAmount($amount);
          $first_shipment->save();

          $order->set('shipments', [$first_shipment]);
          $order->save();

          // Creating shipment profile using data from EDI file.
          $shipment_profile = Profile::create([
            'uid' => $order->getCustomerId(),
            'type' => 'customer',
          ]);
          $shipment_profile->address->given_name = $given_name;
          $shipment_profile->set('field_contact_person', implode(" ", $name));
          $shipment_profile->address->family_name = $family_name;
          $shipment_profile->address->organization = $organization;
          $shipment_profile->set('field_company', $organization);
          $shipment_profile->address->country_code = $country_code;
          $shipment_profile->set('field_new_country', $country_code);
          $shipment_profile->address->locality = $locality;
          $shipment_profile->set('field_city', $locality);
          $shipment_profile->address->postal_code = $postal_code;
          $shipment_profile->set('field_zip_code', $postal_code);
          $shipment_profile->address->address_line1 = $address_line1;
          $shipment_profile->set('field_address_1', $address_line1);
          $shipment_profile->save();
          $first_shipment->setShippingProfile($shipment_profile);
          $first_shipment->setShippingService($shipping_service);
          $first_shipment->save();
          $order->set('shipments', $first_shipment);
          // Create a billing profile.
          if (empty($order->getBillingProfile())) {
            $billing_profile = Profile::create([
              'type' => 'customer',
              'uid' => $order->getCustomerId(),
            ]);
            $billing_profile->save();
            $billing_profile->set('field_address_1', $billing_address);
            $billing_profile->set('field_city', $billing_city);
            $billing_profile->set('field_company', $billing_company);
            $billing_profile->set('field_zip_code', $billing_zip_code);
            $billing_profile->save();
            $order->setBillingProfile($billing_profile);
            $order->save();
          }
          // Including tax into price.
          $priceWithTax = $order->getTotalPrice()->getNumber() + ($order->getTotalPrice()->getNumber() * $tax);
          $order->set('total_price', new Price(round($priceWithTax, 2), $currency));
          $order->save();
          // Checking the number of line items.
          if ($numberOfLineItems == count($orderItems)) {
            $poruka = 'Order created.';
          }
          else {
            $poruka = 'Order was not created.';
          }
          // @todo Ovo će trebati da se otkomentariše u nekom momentu.
          // ftp_delete($ftp, $file);.
          return [
            '#markup' => $poruka,
          ];
        }
        else {
          // @todo Create a logic for putting wrong files in the error directory.
          $this->logger->error('Wrong file format');
        }
      }
    }
    // Closing ftp connection.
    ftp_close($ftp);
  }

}
$ediFile = file_get_contents('./sites/default/files/1509018E1-000523-1611970.EDI');
/**
 * Provides My Config Block.
 *
 * @Block(
 *   id = "config_block",
 *   admin_label = @Translation("My Config Block"),
 *   category = @Translation("My Config Block"),
 * )
 */
/*Ovaj kod možemo da pišemo u modules/module.module fajlu ili u themes/module.theme fajlu.
Prvo ide naziv modula (green_deal_core), zatim ide preprocess, i onda naziv template-a kojem hoćemo da prosledimo varijablu (commerce_product__teaser, ovaj template najčešće nalazimo u public_html->themes->custom->templates). Izvorni naziv template-a je sa crticama (-) ali mi to u hook moramo promeniti na underline (_).

Zatim upišemo $varibles['test'] i onda varijablu {{ test }} možemo da koristimo u tom template-u (commerce_product__teaser).

OBAVEZNO MORAMO DA FLAŠUJEMO KEŠ NAKON ŠTO NAPRAVIMO HOOK.
*/

function green_deal_core_preprocess_commerce_product__teaser(&$variables) {
  $variables['test'] = '123';
}
kazan_dizajner.admin_settings:
  path: '/kazan-dizajner/cenovnik'
  defaults:
    _form: '\Drupal\kazan_dizajner\Form\DesignerBlockSettingsForm'
    _title: 'Cenovnik kazana'
  requirements:
    _permission: 'administer kazan dizajner'

kazan_dizajner.send_mail_controller:
  path: '/kreiraj-svoj-kazan/izvestaj'
  defaults:
    _controller: '\Drupal\kazan_dizajner\Controller\SendMailController::sendmail'
    _title: 'Dizajn poslat'
  requirements:
    _role: 'authenticated'

kazan_dizajner.kazani_form:
  path: '/kazani_forma'
  defaults:
    _form: '\Drupal\kazan_dizajner\Form\KazaniForm'
    _title: 'Kazani forma'
  requirements:
    _permission: 'access content'
<?php

namespace Drupal\kazan_dizajner\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class KazaniForm extends FormBase {

  protected $cena;

  public function getFormId(): string
  {
    return 'kazani_form';
  }

  public function buildForm(array $form, FormStateInterface $form_state): array
  {
    $form['kazani_tipovi'] = [
      '#type' => 'radios',
      '#title' => '1. Izaberite model kazana koji želite da kreirate:',
      '#options' => [
        'prevrtac' => 'Kazani prevrtači',
        'praktik' => 'Kazani praktik',
        'profesionalni' => 'Kazani profesionalni',
      ],
    ];
    $form['kazani_prevrtaci_zapremina'] = [
      '#type' => 'radios',
      '#title' => '2. Izaberite zapreminu kotla:',
      '#options' => [
        '_prevrtac_40_litara' => '40 litara',
        '_prevrtac_60_litara' => '60 litara',
        '_prevrtac_80_litara' => '80 litara',
        '_prevrtac_100_litara' => '100 litara'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => ['value' => 'prevrtac']
        ]
      ],
      //TODO: Ne rade conditional fieldovi kada radi ajax
//      '#ajax' => [
//        'callback' => '::myAjaxCallback',
//        'wrapper' => 'edit-output',
//        'progress' => [
//          'type' => 'throbber',
//          'message' => $this->t('Verifying entry...'),
//        ],
//      ]
    ];
    $form['kazani_prevrtaci_debljina_dna'] = [
      '#type' => 'radios',
      '#title' => 'Izaberite debljinu dna kotla:',
      '#options' => [
        '_prevrtac_1_5_mm' => 'Dno kotla - 1.5 mm',
        '_prevrtac_2_mm' => 'Dno kotla - 2 mm',
        '_prevrtac_3_mmm' => 'Dno kotla - 3 mm',
        '_prevrtac_4_mm' => 'Dno kotla - 4 mm'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_prevrtaci_zapremina"]' => [
            ['value' => '_prevrtac_40_litara'],
            ['value' => '_prevrtac_60_litara'],
            ['value' => '_prevrtac_80_litara'],
            ['value' => '_prevrtac_100_litara'],
          ],
          ['input[name="kazani_tipovi"]' => ['value' => 'prevrtac']]
        ]
      ]
    ];
    $form['kazani_prevrtaci_cev'] = [
      '#type' => 'radios',
      '#title' => '3. Izaberite željenu dužinu i prečnik cevi/lule:',
      '#options' => [
        '_prevrtac_fi28x1500mm' => 'Cev/lula - fi 28x1500 mm (STANDARD)',
        '_prevrtac_fi28x2000mm' => 'Cev/lula - fi 28x2000 mm',
        '_prevrtac_fi28x2500mm' => 'Cev/lula - fi 28x2500 mm',
        '_prevrtac_fi28x3000mm' => 'Cev/lula - fi 28x3000 mm',
        '_prevrtac_fi28x3500mm' => 'Cev/lula - fi 28x3500 mm',
        '_prevrtac_fi28x4000mm' => 'Cev/lula - fi 28x4000 mm',
        '_prevrtac_fi40x2000mm' => 'Cev/lula - fi 40x2000 mm',
        '_prevrtac_fi40x2500mm' => 'Cev/lula - fi 40x2500 mm',
        '_prevrtac_fi40x3000mm' => 'Cev/lula - fi 40x3000 mm',
        '_prevrtac_fi40x3500mm' => 'Cev/lula - fi 40x3500 mm',
        '_prevrtac_fi40x4000mm' => 'Cev/lula - fi 40x4000 mm',
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => ['value' => 'prevrtac']
        ],
      ]
    ];
    $form['kazani_prevrtaci_hladnjak'] = [
      '#type' => 'radios',
      '#title' => '4. Izaberite zapreminu i model hladnjaka:',
      '#options' => [
        '_prevrtac_pocinkovani_od_330_litara' => 'Pocinkovani hladnjak od 330 litara (STANDARD)',
        '_praktik_prohromski_od_330_litara' => 'Prohromski hladnjak od 330 litara',
        '_prevrtac_pocinkovani_od_470_litara' => 'Pocinkovani hladnjak od 470 litara',
        '_prevrtac_prohromski_od_470_litara' => 'Prohromski hladnjak od 470 litara'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'prevrtac'],
          ]
        ],
      ]
    ];
    $form['hladnjak_prevrtaci_izmenjivac'] = [
      '#type' => 'radios',
      '#title' => 'Izmenjivač toplote u hladnjaku',
      '#options' => [
        '_prevrtac_spirala_5_navoja' => 'Spirala 5 navoja (STANDARD)',
        '_prevrtac_cilindar_kiler' => 'Doplata za cilindar/kiler'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'prevrtac'],
          ]
        ],
      ]
    ];
    $form['kazani_prevrtaci_mesalica'] = [
      '#type' => 'radios',
      '#title' => '5. Izaberite jednu od varijanti mešalice:',
      '#options' => [
        '_prevrtac_rucna' => 'Ručna mešalica (STANDARD)',
        '_prevrtac_elektricna' => 'Električna mešalica'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'prevrtac'],
          ]
        ],
      ]
    ];
    $form['dodatna_prevrtaci_oprema'] = [
      '#type' => 'checkboxes',
      '#title' => '6. Izaberite potrebnu dodatnu opremu:',
      '#options' => [
        '_prevrtac_alkoholmetar' => 'Alkoholmetar',
        '_prevrtac_sirometar' => 'Sirometar',
        '_prevrtac_plamenik' => 'Plamenik',
        '_prevrtac_levak' => 'Levak',
        '_prevrtac_menzura' => 'Menzura',
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'prevrtac'],
          ]
        ],
      ]
    ];
    // Kazani praktik.
    $form['kazani_praktik_zapremina'] = [
      '#type' => 'radios',
      '#title' => '2. Izaberite zapreminu kotla:',
      '#options' => [
        '_praktik_60_litara' => '60 litara',
        '_praktik_80_litara' => '80 litara',
        '_praktik_100_litara' => '100 litara'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => ['value' => 'praktik']
        ]
      ]
    ];
    $form['kazani_praktik_debljina_dna'] = [
      '#type' => 'radios',
      '#title' => 'Izaberite debljinu dna kotla:',
      '#options' => [
        '_praktik_1_5_mm' => 'Dno kotla - 1.5 mm',
        '_praktik_2_mm' => 'Dno kotla - 2 mm',
        '_praktik_3_mmm' => 'Dno kotla - 3 mm',
        '_praktik_4_mm' => 'Dno kotla - 4 mm'
      ],
      '#states' => [
        'visible' => [
          ':input[name="kazani_praktik_zapremina"]' => [
            ['value' => '_praktik_60_litara'],
            ['value' => '_praktik_80_litara'],
            ['value' => '_praktik_100_litara']
          ],
          [':input[name="kazani_tipovi"]' => ['value' => 'praktik']]
        ]
      ]
    ];
    $form['kazani_praktik_cev'] = [
      '#type' => 'radios',
      '#title' => '3. Izaberite željenu dužinu i prečnik cevi/lule:',
      '#options' => [
        '_praktik_fi40x2000mm' => 'Cev/lula - fi 40x2000 mm (STANDARD)',
        '_praktik_fi40x2500mm' => 'Cev/lula - fi 40x2500 mm',
        '_praktik_fi40x3000mm' => 'Cev/lula - fi 40x3000 mm',
        '_praktik_fi40x3500mm' => 'Cev/lula - fi 40x3500 mm',
        '_praktik_fi40x4000mm' => 'Cev/lula - fi 40x4000 mm',
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => ['value' => 'praktik']
        ],
      ]
    ];
    $form['kazani_praktik_hladnjak'] = [
      '#type' => 'radios',
      '#title' => '4. Izaberite zapreminu i model hladnjaka:',
      '#options' => [
        '_praktik_pocinkovani_od_330_litara' => 'Pocinkovani hladnjak od 330 litara (STANDARD)',
        '_praktik_prohromski_od_330_litara' => 'Prohromski hladnjak od 330 litara',
        '_praktik_pocinkovani_od_470_litara' => 'Pocinkovani hladnjak od 470 litara',
        '_praktik_prohromski_od_470_litara' => 'Prohromski hladnjak od 470 litara'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'praktik'],
          ]
        ],
      ]
    ];
    $form['hladnjak_praktik_izmenjivac'] = [
      '#type' => 'radios',
      '#title' => 'Izmenjivač toplote u hladnjaku',
      '#options' => [
        '_praktik_spirala_5_navoja' => 'Spirala 5 navoja (STANDARD)',
        '_praktik_cilindar_kiler' => 'Doplata za cilindar/kiler'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'praktik'],
          ]
        ],
      ]
    ];
    $form['kazani_praktik_mesalica'] = [
      '#type' => 'radios',
      '#title' => '5. Izaberite jednu od varijanti mešalice:',
      '#options' => [
        '_praktik_rucna' => 'Ručna mešalica (STANDARD)',
        '_praktik_elektricna' => 'Električna mešalica'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'praktik'],
          ]
        ],
      ]
    ];
    $form['dodatna_praktik_oprema'] = [
      '#type' => 'checkboxes',
      '#title' => '6. Izaberite potrebnu dodatnu opremu:',
      '#options' => [
        '_praktik_alkoholmetar' => 'Alkoholmetar',
        '_praktik_sirometar' => 'Sirometar',
        '_praktik_plamenik' => 'Plamenik',
        '_praktik_levak' => 'Levak',
        '_praktik_menzura' => 'Menzura',
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'praktik'],
          ]
        ],
      ]
    ];
    // Kazani profesionalni.
    $form['kazani_profesionalni_zapremina'] = [
      '#type' => 'radios',
      '#title' => '2. Izaberite zapreminu kotla:',
      '#options' => [
        '_profi_80_litara' => '80 litara',
        '_profi_100_litara' => '100 litara',
        '_profi_120_litara' => '120 litara',
        '_profi_160_litara' => '160 litara',
        '_profi_200_litara' => '200 litara',
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => ['value' => 'profesionalni']
        ]
      ]
    ];
    $form['kazani_profesionalni_debljina_dna'] = [
      '#type' => 'radios',
      '#title' => 'Izaberite debljinu dna kotla:',
      '#options' => [
        '_profi_1_5_mm' => 'Dno kotla - 1.5 mm (STANDARD)',
        '_profi_2_mm' => 'Dno kotla - 2 mm',
        '_profi_3_mmm' => 'Dno kotla - 3 mm',
        '_profi_4_mm' => 'Dno kotla - 4 mm',
        '_profi_5_mm' => 'Dno kotla - 5 mm',
      ],
      '#states' => [
        'visible' => [
          ':input[name="kazani_profesionalni_zapremina"]' => [
            ['value' => '_profi_80_litara'],
            ['value' => '_profi_100_litara'],
            ['value' => '_profi_120_litara'],
            ['value' => '_profi_160_litara'],
            ['value' => '_profi_200_litara'],
          ],
          [':input[name="kazani_tipovi"]' => ['value' => 'profesionalni']]
        ],
      ]
    ];
    $form['kazani_profesionalni_cev'] = [
      '#type' => 'radios',
      '#title' => '3. Izaberite željenu dužinu i prečnik cevi/lule:',
      '#options' => [
        '_profi_fi40x2000mm' => 'Cev/lula - fi 40x2000 mm (STANDARD)',
        '_profi_fi40x2500mm' => 'Cev/lula - fi 40x2500 mm',
        '_profi_fi40x3000mm' => 'Cev/lula - fi 40x3000 mm',
        '_profi_fi40x3500mm' => 'Cev/lula - fi 40x3500 mm',
        '_profi_fi40x4000mm' => 'Cev/lula - fi 40x4000 mm',
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => ['value' => 'profesionalni']
        ],
      ]
    ];
    $form['kazani_profesionalni_hladnjak'] = [
      '#type' => 'radios',
      '#title' => '4. Izaberite zapreminu i model hladnjaka:',
      '#options' => [
        '_profi_pocinkovani_od_330_litara' => 'Pocinkovani hladnjak od 330 litara (STANDARD)',
        '_profi_prohromski_od_330_litara' => 'Prohromski hladnjak od 330 litara',
        '_profi_pocinkovani_od_470_litara' => 'Pocinkovani hladnjak od 470 litara',
        '_profi_prohromski_od_470_litara' => 'Prohromski hladnjak od 470 litara'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'profesionalni']
          ]
        ],
      ]
    ];
    $form['hladnjak_profesionalni_izmenjivac'] = [
      '#type' => 'radios',
      '#title' => 'Izmenjivač toplote u hladnjaku',
      '#options' => [
        '_profi_spirala_5_navoja' => 'Spirala 5 navoja (STANDARD)',
        '_profi_cilindar_kiler' => 'Doplata za cilindar/kiler'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'profesionalni']
          ]
        ],
      ]
    ];
    $form['kazani_profesionalni_mesalica'] = [
      '#type' => 'radios',
      '#title' => '5. Izaberite jednu od varijanti mešalice:',
      '#options' => [
        '_profi_rucna' => 'Ručna mešalica (STANDARD)',
        '_profi_elektricna' => 'Električna mešalica'
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'profesionalni']
          ]
        ],
      ]
    ];
    $form['dodatna_profesionalni_oprema'] = [
      '#type' => 'checkboxes',
      '#title' => '6. Izaberite potrebnu dodatnu opremu:',
      '#options' => [
        '_profi_alkoholmetar' => 'Alkoholmetar',
        '_profi_sirometar' => 'Sirometar',
        '_profi_plamenik' => 'Plamenik',
        '_profi_levak' => 'Levak',
        '_profi_menzura' => 'Menzura',
      ],
      '#states' => [
        'visible' => [
          'input[name="kazani_tipovi"]' => [
            ['value' => 'profesionalni']
          ]
        ],
      ]
    ];
    $form['izracunaj_cenu'] = [
      '#type' => 'button',
      '#value' => 'Izracunaj cenu',
      '#ajax' => [
        'callback' => '::cene',
        'wrapper' => 'edit-output',
        'progress' => [
          'type' => 'throbber',
          'message' => $this->t('Verifying entry...'),
        ]
      ]
    ];
    // Order price.
    $form['cena'] = [
      '#type' => 'label',
      '#attributes' => ['id' => 'edit-output'],
      '#title' => 'Cena',
    ];
    // User information.
    $form['emailaddress'] = [
      '#type' => 'email',
      '#title' => 'E-mail (dobićete kopiju gore kreiranog kazana)*'
    ];
    $form['phone'] = [
      '#type' => 'tel',
      '#title' => 'Broj telefona*'
    ];
    $form['message'] = [
      '#type' => 'textarea',
      '#title' => 'Poruka*'
    ];
    $form['actions']['#type'] = 'actions';
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save'),
      '#button_type' => 'primary'
    ];

    return $form;
  }

  public static function cene(array &$form, FormStateInterface $form_state) {
    $config = \Drupal::config('kazan_dizajner.settings');
    $cena = '';
    $oprema_cena = '';
    // Fetching users input for acquiring each item price.
    if ($form_state->getUserInput()['kazani_tipovi'] == 'prevrtac') {
      $zapremina = $form_state->getUserInput()['kazani_prevrtaci_zapremina'];
      ($zapremina) ? $form_state->getUserInput()['kazani_prevrtaci_zapremina'] : '';
      $dno = $form_state->getUserInput()['kazani_prevrtaci_debljina_dna'];
      ($dno) ? $form_state->getUserInput()['kazani_prevrtaci_debljina_dna'] : '';
      $cev = $form_state->getUserInput()['kazani_prevrtaci_cev'];
      ($cev) ? $form_state->getUserInput()['kazani_prevrtaci_cev'] : '';
      $hladnjak = $form_state->getUserInput()['kazani_prevrtaci_hladnjak'];
      ($hladnjak) ? $form_state->getUserInput()['kazani_prevrtaci_hladnjak'] : '';
      $izmenjivac = $form_state->getUserInput()['hladnjak_prevrtaci_izmenjivac'];
      ($izmenjivac) ? $form_state->getUserInput()['hladnjak_prevrtaci_izmenjivac'] : '';
      $mesalica = $form_state->getUserInput()['kazani_prevrtaci_mesalica'];
      ($mesalica) ? $form_state->getUserInput()['kazani_prevrtaci_mesalica'] : '';
      $dodaci = $form_state->getUserInput()['dodatna_prevrtaci_oprema'];
      foreach ($dodaci as $dodatak) {
        if ($dodatak != NULL) {
          $oprema_cena += $config->get($dodatak);
        }
      }
    } else if ($form_state->getUserInput()['kazani_tipovi'] == 'praktik') {
      $zapremina = $form_state->getUserInput()['kazani_praktik_zapremina'];
      ($zapremina) ? $form_state->getUserInput()['kazani_prevrtaci_zapremina'] : '';
      $dno = $form_state->getUserInput()['kazani_praktik_debljina_dna'];
      ($dno) ? $form_state->getUserInput()['kazani_praktik_debljina_dna'] : '';
      $cev = $form_state->getUserInput()['kazani_praktik_cev'];
      ($cev) ? $form_state->getUserInput()['kazani_praktik_cev'] : '';
      $hladnjak = $form_state->getUserInput()['kazani_praktik_hladnjak'];
      ($hladnjak) ? $form_state->getUserInput()['kazani_praktik_hladnjak'] : '';
      $izmenjivac = $form_state->getUserInput()['hladnjak_praktik_izmenjivac'];
      ($izmenjivac) ? $form_state->getUserInput()['hladnjak_praktik_izmenjivac'] : '';
      $mesalica = $form_state->getUserInput()['kazani_praktik_mesalica'];
      ($mesalica) ? $form_state->getUserInput()['kazani_praktik_mesalica'] : '';
      $dodaci = $form_state->getUserInput()['dodatna_praktik_oprema'];
      foreach ($dodaci as $dodatak) {
        if ($dodatak != NULL) {
          $oprema_cena += $config->get($dodatak);
        }
      }
    } else {
      $zapremina = $form_state->getUserInput()['kazani_profesionalni_zapremina'];
      ($zapremina) ? $form_state->getUserInput()['kazani_profesionalni_zapremina'] : '';
      $dno = $form_state->getUserInput()['kazani_profesionalni_debljina_dna'];
      ($dno) ? $form_state->getUserInput()['kazani_profesionalni_debljina_dna'] : '';
      $cev = $form_state->getUserInput()['kazani_profesionalni_cev'];
      ($cev) ? $form_state->getUserInput()['kazani_profesionalni_cev'] : '';
      $hladnjak = $form_state->getUserInput()['kazani_profesionalni_hladnjak'];
      ($hladnjak) ? $form_state->getUserInput()['kazani_profesionalni_hladnjak'] : '';
      $izmenjivac = $form_state->getUserInput()['hladnjak_profesionalni_izmenjivac'];
      ($izmenjivac) ? $form_state->getUserInput()['hladnjak_profesionalni_izmenjivac'] : '';
      $mesalica = $form_state->getUserInput()['kazani_profesionalni_mesalica'];
      ($mesalica) ? $form_state->getUserInput()['kazani_profesionalni_mesalica'] : '';
      $dodaci = $form_state->getUserInput()['dodatna_profesionalni_oprema'];
      foreach ($dodaci as $dodatak) {
        if ($dodatak != NULL) {
          $oprema_cena += $config->get($dodatak);
        }
      }
    }
    //Calculating total order price.
    $artikli = [];
    array_push($artikli, $zapremina, $dno, $cev, $hladnjak, $izmenjivac, $mesalica);
    foreach($artikli as $artikal) {
      if ($artikal != NULL) {
        $cena += $config->get($artikal);
      }
    }
    $cena += $oprema_cena;

    $form['cena']['#title'] = 'Cena ovog kazana bi iznosila ' . $cena . ' RSD.';
    return $form['cena'];
  }

  public function submitForm(array &$form, FormStateInterface $form_state)
  {
    if ($form_state->getValue)

    $message =
      'Specifikacija kazana' . PHP_EOL . PHP_EOL
    . 'Email: ' . $form_state->getValue('emailaddress') . PHP_EOL
    . 'Telefon: ' . $form_state->getValue('phone') . PHP_EOL
    . 'Poruka: ' . $form_state->getValue('message') . PHP_EOL
    . 'Tip: ' . $form_state->getValue('kazani_tipovi') . PHP_EOL
    . 'Zapremina: ' . $form_state->getValue('');
    $mailManager = \Drupal::service('plugin.manager.mail');
    $module = 'kazan_dizajner';
    $key = 'mail_order';
    $to = $form_state->getValue('emailaddress');
    dsm($form_state->getValue('kazani_tipovi'));

  }
}
<?php

namespace Drupal\musin_core\Service;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;

class UserHelperService {


  /**
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;

  /**
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  public function __construct(AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager) {
    $this->currentUser = $current_user;
    $this->entityTypeManager = $entity_type_manager;
  }

  public static function getProfileCompleteness($user) {
    $field_weightings = [
      'field_first_name' => 10,
      'field_last_name' => 10,
      'field_city' => 10,
      'field_age' => 10,
      'user_picture' => 10,
      'field_cover_image' => 10,
      'field_genres' => 5,
      'field_instruments' => 5,
      'field_sample_tracks' => 5,
      'field_short_biography' => 5,
      'field_social_media_soundcloud' => 5,
      'field_social_media_spotify' => 5,
      'field_social_media_tiktok' => 5,
      'field_social_media_youtube' => 5,
    ];

    $completeness = 0;

    foreach ($field_weightings as $key => $value) {
      if ($user->hasField($key) && $user->get($key)->isEmpty() === FALSE) {
        $completeness = $completeness + $value;
      }
    }
    return $completeness;
  }
}
<?php

namespace Drupal\musin_core\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\musin_core\Service\UserHelperService;

class CompletenessController extends ControllerBase {

  protected $entityTypeManager;

  public function populateCompleteness()
  {
    $query = \Drupal::entityQuery('user');
    $uids = $query->execute();

    foreach ($uids as $key => $id) {
      $user = \Drupal::entityTypeManager()->getStorage('user')->load($id);
      $result = UserHelperService::getProfileCompleteness($user);
      $user->set('field_completeness', $result);
      $user->save();
    }
    return [];
  }
}
/**
 * Implements hook_entity_presave.
 */
function musin_core_entity_presave(EntityInterface $entity) {
  if ($entity instanceof \Drupal\user\UserInterface) {
    $completeness = \Drupal\musin_core\Service\UserHelperService::getProfileCompleteness($entity);
    $entity->set('field_completeness', $completeness);
    $entity->save();
  }
}
$media = \Drupal\file\Entity\File::load(2); //2 je target_id iz field_image (iz noda npr.).
dsm($media);
$user->set('field_mailchimp_subscription', ['subscribe' => "1"]);
$current_path = $this->request->getCurrentRequest()->headers->get('referer');
$path = explode('8000', $current_path);  
//8000 is just a part of a string, from where we are breaking the string.
$route_name = Url::fromUserInput($path[1])->getRouteName();
return $this->redirect($route_name, ['user' => $user->id()]);
name: Subscribe block
type: module
description: Define a custom block for applying for subscription.
core_version_requirement: ^8 || ^9
package: Custom
dependencies:
  - block
<?php

namespace Drupal\bacademy_core\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Url;
use Drupal\user\Entity\User;

class SubscribeController extends ControllerBase {

  public function __construct(EntityTypeManager $entityTypeManager) {
    $this->entityTypeManager = $entityTypeManager;
  }

  public function subscribe(int $id) {
    $user = $this->entityTypeManager->getStorage('user')->load($id);
    /** @var User $user */
    $subscribed = $user->get('field_mailchimp_subscription')[0]->get('subscribe')->getValue();
    if ($subscribed != "1") {
      $user->set('field_mailchimp_subscription', ['subscribe' => "1"] );
      $user->save();
      return Url::fromRoute('entity.user.canonical', ['user' => $user->id()])->toString();
    } else {
      return Url::fromRoute('entity.user.canonical', ['user' => $user->id()])->toString();
    }
  }
}
<?php

namespace Drupal\bacademy_core\Plugin\Block;

use Drupal\bacademy_core\Controller\SubscribeController;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
 * Provides a 'Subscribe' block.
 *
 * @Block(
 *   id = "subscribe_block",
 *   admin_label= @Translation("Subscribe"),
 *   category= @Translation("Subscribe"),
 * )
 */
class SubscribeBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   * Entity type manager.
   *
   * @var EntityTypeManager
   */
  protected $entityTypeManager;

  public function __construct(array $configuration, $plugin_id, $plugin_definition, AccountProxyInterface $current_user, EntityTypeManager $entityTypeManager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->currentUser = $current_user;
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition){
    return new static (
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('current_user'),
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritDoc}
   */
  public function build() {
    // Check if current user is subscribed.
    $user = $this->entityTypeManager
      ->getStorage('user')
      ->loadByProperties([
        'uid' => $this->currentUser->id(),
      ]);
    $user = reset($user);
    $subscribed = 0;
    if ($user->hasField('field_mailchimp_subscription')) {
      $subscribed = $user->get('field_mailchimp_subscription')[0]->get('subscribe')->getValue();
    }
    if ($subscribed == "1") {
      return [];
    } else {
      return [
        '#type' => 'inline_template',
        '#template' => "<div>
                        <p>Opt in and don't miss out on the latest from the Academy.</p>
                        <a href='{{ controller_link }}'>YES PLEASE</a>
                        <a href='#'>NO THANKS</a>
                      </div>",
        '#context' => [
          'controller_link' => Url::fromRoute('bacademy_core.subscription', ['id' => $this->currentUser->id()])->toString(),
        ],
      ];
    }
  }
}
//If we don't want to cache anonymus user choices or content
//than we add next line of code in mymodule.routing.yml file
//for the specified page

no_cache: 'TRUE'
    /** @var \Drupal\bacademy_cpd\Entity\CpdPoints $cpd_record */
    foreach ($cpd_records as $cpd_record) {
      $completed_node = $cpd_record->get('node')->entity;
      /** @var \Drupal\node\Entity\Node $completed_node */
      $completed_nodeID = $completed_node->get('nid')->value;
// clear that cache
composer create-project drupal/recommended-project myproject -n
cd myproject
lando init --source cwd --recipe drupal8 --webroot web --name myproject
lando start


composer require drush/drush drupal/admin_toolbar
drush si --db-url=mysql://drupal8:drupal8@database/drupal8 --account-pass=content -y
drush en admin_toolbar admin_toolbar_tools
drush uli -l http://myproject.lndo.site
function mytheme_preprocess_node(&$variables) {
  switch ($variables['node']->getType()) {
    case "video":
      // ...
    break;
    case "something_else":
      // ...
    break;
  }
}			
function events_preprocess_node(&$variables) {
  // Get route name.
  $routeName = \Drupal::routeMatch()->getRouteName();
  // Get entity.
  $node = &$variables['node'];
  // Check if it's an event.
  if ($node->getType() === 'event' && $node->hasField('field_place')) {
    // Get the place.
    $place = $node->get('field_place')->entity;
    // Check if place is NULL.
    if ($place) {
      if ($node->get('field_teaser_media')->isEmpty()) {
        // Get teaser.
        $variables['place_teaser_media'] = $place
          ->get('field_teaser_media')
          ->view($routeName === 'entity.node.canonical' ? 'default' : 'small_teaser_square');
      }
      // Get organization name from place.
      $variables['place_organization'] = $place
        ->get('field_address')[0]
        ->get('organization')->getValue();
    }
  }
}
global $language;
$lang = $language->language;
$base_node = node_load(XXXXX);

$translations = translation_node_get_translations($base_node->tnid);
$translated_node = (isset($translations[$lang])?node_load($translations[$lang]->nid):$base_node);
star

Mon Jun 13 2022 20:07:08 GMT+0000 (UTC)

#drupal #mysql
star

Mon Jun 13 2022 20:06:44 GMT+0000 (UTC)

#drupal #mysql
star

Mon Jun 13 2022 19:47:28 GMT+0000 (UTC)

#drupal #mysql
star

Mon Jun 13 2022 19:46:54 GMT+0000 (UTC)

#drupal #mysql
star

Thu May 26 2022 14:07:36 GMT+0000 (UTC)

#drupal #mysql
star

Wed May 25 2022 13:10:09 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Wed May 25 2022 13:08:21 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Sat May 21 2022 15:06:48 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Sat May 21 2022 15:06:05 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Thu May 19 2022 20:45:31 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Wed May 18 2022 13:49:18 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Wed May 18 2022 13:48:53 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Wed May 18 2022 13:48:20 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Fri May 13 2022 06:32:09 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Tue May 10 2022 20:18:41 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Tue May 10 2022 19:26:37 GMT+0000 (UTC)

#drupal #pseudo-field #form-render
star

Fri Mar 04 2022 18:43:33 GMT+0000 (UTC)

#drupal
star

Thu Jan 27 2022 18:38:45 GMT+0000 (UTC)

#drupal #php
star

Fri Jan 21 2022 14:47:55 GMT+0000 (UTC)

#drupal #php
star

Thu Jan 20 2022 14:57:39 GMT+0000 (UTC)

#drupal #php
star

Wed Jan 19 2022 14:52:39 GMT+0000 (UTC)

#drupal #php
star

Tue Jan 18 2022 08:17:48 GMT+0000 (UTC)

#drupal #php
star

Mon Jan 17 2022 21:39:57 GMT+0000 (UTC)

#drupal #php
star

Fri Jan 14 2022 11:26:54 GMT+0000 (UTC)

#drupal #php
star

Fri Jan 14 2022 08:50:22 GMT+0000 (UTC)

#drupal #php
star

Fri Jan 14 2022 08:49:31 GMT+0000 (UTC)

#drupal #php
star

Thu Jan 13 2022 20:52:16 GMT+0000 (UTC)

#drupal #php
star

Wed Jan 12 2022 14:52:58 GMT+0000 (UTC)

#drupal #php
star

Wed Jan 12 2022 14:52:18 GMT+0000 (UTC)

#drupal #php
star

Mon Jan 10 2022 12:32:25 GMT+0000 (UTC)

#drupal #php
star

Thu Jan 06 2022 14:52:48 GMT+0000 (UTC)

#drupal #php
star

Tue Jan 04 2022 19:59:01 GMT+0000 (UTC)

#drupal #php
star

Tue Jan 04 2022 15:37:21 GMT+0000 (UTC) https://colorfield.be/blog/lando-configuration-solr7-drupal8-search-api-umami-profile

#solr #drupal
star

Mon Dec 27 2021 14:57:51 GMT+0000 (UTC)

#drupal #php
star

Mon Dec 27 2021 14:57:06 GMT+0000 (UTC)

#drupal #php
star

Sun Dec 26 2021 17:24:00 GMT+0000 (UTC)

#drupal #php
star

Sun Dec 26 2021 17:23:20 GMT+0000 (UTC)

#drupal #php
star

Sun Dec 26 2021 17:17:51 GMT+0000 (UTC)

#drupal #php
star

Tue Dec 21 2021 20:33:20 GMT+0000 (UTC)

#drupal #php
star

Mon Dec 20 2021 12:19:02 GMT+0000 (UTC)

#drupal #php
star

Mon Dec 20 2021 12:17:31 GMT+0000 (UTC)

#drupal #php
star

Thu Dec 16 2021 14:52:00 GMT+0000 (UTC)

#drupal #php
star

Thu Dec 16 2021 14:51:34 GMT+0000 (UTC)

#drupal #php
star

Thu Dec 16 2021 14:51:00 GMT+0000 (UTC)

#drupal #php
star

Wed Dec 15 2021 14:54:12 GMT+0000 (UTC) https://medium.com/@askibinski/integrating-storybook-with-drupal-ddabfc6c2f9d

#drupal #twig #storybook
star

Wed Dec 15 2021 13:52:07 GMT+0000 (UTC)

#drupal #php
star

Sun Dec 12 2021 14:07:55 GMT+0000 (UTC)

#drupal #php
star

Wed Dec 08 2021 09:37:16 GMT+0000 (UTC) https://drupal.stackexchange.com/questions/239783/how-to-use-dependency-injection-for-plugins-blocks-drupalformbuilder-and

#drupal
star

Mon Dec 06 2021 20:54:35 GMT+0000 (UTC) https://www.drupal.org/project/drupal/issues/3099148

#php #drupal
star

Fri Dec 03 2021 12:23:07 GMT+0000 (UTC)

#php #drupal
star

Fri Sep 03 2021 09:25:59 GMT+0000 (UTC) https://api.drupal.org/api/drupal/modules%21translation%21translation.module/function/translation_node_get_translations/7.x

#drupal #drupal7 #node #translation #languages

Save snippets that work with our extensions

Available in the Chrome Web Store Get Firefox Add-on Get VS Code extension