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