<?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;
}


