arch-8.x-1.x-dev/modules/order/arch_order.tokens.inc
modules/order/arch_order.tokens.inc
<?php
/**
* @file
* Builds placeholder replacement tokens for order-related data.
*/
use Drupal\arch_order\Entity\OrderInterface;
use Drupal\arch_order\Plugin\Field\FieldType\OrderLineItemInterface;
use Drupal\arch_price\Price\PriceFactoryInterface;
use Drupal\arch_price\Price\PriceFormatterInterface;
use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\user\Entity\User;
/**
* Implements hook_token_info().
*/
function arch_order_token_info() {
$tokens = [];
// Order.
$tokens['types']['order'] = [
'name' => t('Orders', [], ['context' => 'arch_order']),
'description' => t('Tokens related to individual orders.', [], ['context' => 'arch_order']),
'needs-data' => 'order',
];
// Core tokens for orders.
$order['oid'] = [
'name' => t('Order ID', [], ['context' => 'arch_order']),
'description' => t('The unique ID of the order.', [], ['context' => 'arch_order']),
];
$order['vid'] = [
'name' => t('Revision ID'),
'description' => t("The unique ID of the order's latest revision.", [], ['context' => 'arch_order']),
];
$order['status'] = [
'name' => t('Order status', [], ['context' => 'arch_order']),
];
$order['status-name'] = [
'name' => t('Order status name', [], ['context' => 'arch_order']),
'description' => t('The human-readable name of the order status.', [], ['context' => 'arch_order']),
];
$order['langcode'] = [
'name' => t('Language code'),
'description' => t('The language code of the language the order is written in.', [], ['context' => 'arch_order']),
];
$order['url'] = [
'name' => t('URL'),
'description' => t('The URL of the order.', [], ['context' => 'arch_order']),
];
$order['edit-url'] = [
'name' => t('Edit URL'),
'description' => t("The URL of the order's edit page.", [], ['context' => 'arch_order']),
];
$order['order-number'] = [
'name' => t('Order number', [], ['context' => 'arch_order']),
'description' => t('The number of the order.', [], ['context' => 'arch_order']),
];
$order['payment-method'] = [
'name' => t('Payment method', [], ['context' => 'arch_order']),
'description' => t('Payment method', [], ['context' => 'arch_order']),
];
$order['shipping-method'] = [
'name' => t('Shipping method', [], ['context' => 'arch_order']),
'description' => t('Shipping method', [], ['context' => 'arch_order']),
];
$order['order-note'] = [
'name' => t('Order note', [], ['context' => 'arch_order']),
'description' => t('The note of the order.', [], ['context' => 'arch_order']),
];
$order['line-items-table'] = [
'name' => t('Line items (formatter)', [], ['context' => 'arch_order']),
'description' => t('Line items in table format.', [], ['context' => 'arch_order']),
];
// Chained tokens for orders.
$order['created'] = [
'name' => t('Date created', [], ['context' => 'arch_order']),
'type' => 'date',
];
$order['changed'] = [
'name' => t('Date changed', [], ['context' => 'arch_order']),
'description' => t('The date the order was most recently updated.', [], ['context' => 'arch_order']),
'type' => 'date',
];
$order['owner'] = [
'name' => t('Customer', [], ['context' => 'arch_order']),
'type' => 'user',
];
$tokens['tokens']['order'] = $order;
return $tokens;
}
/**
* Implements hook_tokens().
*/
function arch_order_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
$token_service = \Drupal::token();
/** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
$date_formatter = \Drupal::service('date.formatter');
$url_options = ['absolute' => TRUE];
if (isset($options['langcode'])) {
$url_options['language'] = \Drupal::languageManager()->getLanguage($options['langcode']);
$langcode = $options['langcode'];
}
else {
$langcode = LanguageInterface::LANGCODE_DEFAULT;
}
$replacements = [];
if ($type == 'order' && !empty($data['order'])) {
/** @var \Drupal\arch_order\Entity\OrderInterface $order */
$order = $data['order'];
foreach ($tokens as $name => $original) {
switch ($name) {
// Simple key values on the order.
case 'oid':
$replacements[$original] = $order->id();
break;
case 'vid':
$replacements[$original] = $order->getRevisionId();
break;
case 'status':
$replacements[$original] = $order->getStatus();
break;
case 'order-number':
$replacements[$original] = $order->get('order_number')->getString();
break;
case 'payment-method':
if ($order->getPaymentMethod()) {
$replacements[$original] = $order->getPaymentMethod()->getLabel();
}
if (
!$order->get('payment_method')->isEmpty()
&& \Drupal::hasService('plugin.manager.payment_method')
) {
$payment_method_id = $order->get('payment_method')->getString();
/** @var \Drupal\arch_payment\PaymentMethodManagerInterface $payment_method_manager */
$payment_method_manager = \Drupal::service('plugin.manager.payment_method');
$method = $payment_method_manager->getPaymentMethod($payment_method_id);
if (!empty($method)) {
$replacements[$original] = $method->getLabel();
}
}
break;
case 'shipping-method':
if ($order->getShippingMethod()) {
$replacements[$original] = $order->getShippingMethod()->getLabel();
}
if (
!$order->get('shipping_method')->isEmpty()
&& \Drupal::hasService('plugin.manager.shipping_method')
) {
$payment_method_id = $order->get('shipping_method')->getString();
/** @var \Drupal\arch_shipping\ShippingMethodManagerInterface $shipping_method_manager */
$shipping_method_manager = \Drupal::service('plugin.manager.shipping_method');
$method = $shipping_method_manager->getShippingMethod($payment_method_id);
if (!empty($method)) {
$replacements[$original] = $method->getLabel();
}
}
break;
case 'order-note':
$order_data = $order->getData();
$replacements[$original] = !empty($order_data['note']) ? $order_data['note'] : '';
break;
case 'line-items-table':
try {
$line_items_table = arch_order_tokens_line_item_table($order);
if (!empty($line_items_table)) {
$replacements[$original] = $line_items_table;
}
}
catch (\Exception $e) {
$replacements[$original] = '';
}
break;
case 'status-name':
$status_name = $order->getStatus()->getLabel();
$replacements[$original] = $status_name;
break;
case 'langcode':
$replacements[$original] = $order->language()->getId();
break;
case 'url':
$replacements[$original] = $order->toUrl('canonical', $url_options)->toString();
break;
case 'edit-url':
$replacements[$original] = $order->toUrl('edit-form', $url_options)->toString();
break;
// Default values for the chained tokens handled below.
case 'owner':
$account = $order->getOwner() ? $order->getOwner() : User::load(0);
$bubbleable_metadata->addCacheableDependency($account);
$replacements[$original] = $account->label();
break;
case 'created':
$date_format = DateFormat::load('medium');
$bubbleable_metadata->addCacheableDependency($date_format);
$replacements[$original] = $date_formatter->format($order->getCreatedTime(), 'medium', '', NULL, $langcode);
break;
case 'changed':
$date_format = DateFormat::load('medium');
$bubbleable_metadata->addCacheableDependency($date_format);
$replacements[$original] = $date_formatter->format($order->getChangedTime(), 'medium', '', NULL, $langcode);
break;
}
}
if ($owner_tokens = $token_service->findWithPrefix($tokens, 'owner')) {
$replacements += $token_service->generate('user', $owner_tokens, ['user' => $order->getOwner()], $options, $bubbleable_metadata);
}
if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) {
$replacements += $token_service->generate('date', $created_tokens, ['date' => $order->getCreatedTime()], $options, $bubbleable_metadata);
}
if ($changed_tokens = $token_service->findWithPrefix($tokens, 'changed')) {
$replacements += $token_service->generate('date', $changed_tokens, ['date' => $order->getChangedTime()], $options, $bubbleable_metadata);
}
}
return $replacements;
}
/**
* Gets a rendered order line items table.
*
* @param \Drupal\arch_order\Entity\OrderInterface $order
* Order object.
*
* @return string
* Rendered order line items table.
*
* @throws \Drupal\Core\TypedData\Exception\MissingDataException
*/
function arch_order_tokens_line_item_table(OrderInterface $order) {
if ($order->get('line_items')->isEmpty()) {
return '';
}
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
/** @var \Drupal\arch_price\Price\PriceFactoryInterface $price_factory */
$price_factory = \Drupal::service('price_factory');
/** @var \Drupal\arch_price\Price\PriceFormatterInterface $price_formatter */
$price_formatter = \Drupal::service('price_formatter');
$cell_style = 'padding:10px 20px';
$shipping = 0;
$discount = 0;
$paymentfee = 0;
$subtotal = 0;
$rows = [];
foreach ($order->get('line_items') as $line_item) {
/** @var \Drupal\arch_order\Plugin\Field\FieldType\OrderLineItemInterface $line_item */
if ($line_item->isShipping()) {
$shipping = (float) $line_item->get('calculated_gross')->getValue();
continue;
}
if ($line_item->isDiscount()) {
$discount = (float) $line_item->get('calculated_gross')->getValue();
continue;
}
if ($line_item->isPaymentFee()) {
$paymentfee = (float) $line_item->get('calculated_gross')->getValue();
continue;
}
/** @var \Drupal\arch_product\Entity\ProductInterface $product */
$product = $line_item->getProduct();
if (empty($product)) {
continue;
}
$subtotal += (float) $line_item->get('calculated_gross')->getValue() * (float) $line_item->getQuantity();
$formatted = arch_order_tokens__renderable_formatted_line_item_price($price_factory, $price_formatter, $order, $line_item);
$renderer->renderPlain($formatted);
$row = [
[
'data' => $product->label() . ' (' . $product->getSku() . ')',
'style' => $cell_style . ';text-align:left',
],
[
'data' => $line_item->getQuantity(),
'style' => $cell_style . ';text-align:right',
],
[
'data' => $formatted,
'style' => $cell_style . ';text-align:right',
],
];
$rows[] = [
'data' => $row,
'style' => 'border-top:1px solid #efefef',
];
}
$extra_rows = [
[
'label' => t('Shipping', [], ['context' => 'arch_order_token']),
'value' => $shipping,
],
[
'label' => t('Discount', [], ['context' => 'arch_order_token']),
'value' => $discount,
],
[
'label' => t('Payment fee', [], ['context' => 'arch_order_token']),
'value' => $paymentfee,
],
];
foreach ($extra_rows as $extra_row) {
if (empty($extra_row['value'])) {
continue;
}
$formatted = arch_order_tokens__renderable_formatted_price($price_factory, $price_formatter, $order, $extra_row['value']);
$renderer->renderPlain($formatted);
$row = [
[
'data' => $extra_row['label'],
'colspan' => 2,
'style' => $cell_style . ';text-align:right',
],
[
'data' => $formatted,
'style' => $cell_style . ';text-align:right',
],
];
$rows[] = $row;
}
$formatted = arch_order_tokens__renderable_formatted_price($price_factory, $price_formatter, $order, $subtotal);
$renderer->renderPlain($formatted);
$rows[] = [
'data' => [
[
'data' => t('Subtotal', [], ['context' => 'arch_order_token']),
'colspan' => 2,
'style' => $cell_style . ';text-align:right',
],
[
'data' => $formatted,
'style' => $cell_style . ';text-align:right;',
],
],
];
$formatted = arch_order_tokens__renderable_formatted_price($price_factory, $price_formatter, $order, (float) $order->get('grandtotal_gross')->getString());
$renderer->renderPlain($formatted);
$rows[] = [
[
'data' => t('Grand total', [], ['context' => 'arch_order_token']),
'colspan' => 2,
'style' => $cell_style . ';text-align:right;border-top:2px solid #efefef;font-weight:bold',
],
[
'data' => $formatted,
'style' => $cell_style . ';text-align:right;border-top:2px solid #efefef;font-weight:bold',
],
];
$table = [
'#type' => 'table',
'#header' => [
[
'data' => t('Product', [], ['context' => 'arch_order_token']),
'style' => $cell_style . ';text-align:left;border-bottom:2px solid #efefef',
],
[
'data' => t('Quantity', [], ['context' => 'arch_order_token']),
'style' => $cell_style . ';text-align:right;border-bottom:2px solid #efefef',
],
[
'data' => t('Subtotal', [], ['context' => 'arch_order_token']),
'style' => $cell_style . ';text-align:right;border-bottom:2px solid #efefef',
],
],
'#rows' => $rows,
'#attributes' => [
'style' => 'border-collapse:collapse',
],
];
$renderer->renderPlain($table);
return $table['#markup'];
}
/**
* Gets renderable formatted price from line item object.
*
* @param \Drupal\arch_price\Price\PriceFactoryInterface $price_factory
* Price factory service.
* @param \Drupal\arch_price\Price\PriceFormatterInterface $price_formatter
* Price formatter service.
* @param \Drupal\arch_order\Entity\OrderInterface $order
* Order object.
* @param \Drupal\arch_order\Plugin\Field\FieldType\OrderLineItemInterface $line_item
* Order line item object.
*
* @return array
* Renderable formatted price.
*
* @throws \Drupal\Core\TypedData\Exception\MissingDataException
*/
function arch_order_tokens__renderable_formatted_line_item_price(PriceFactoryInterface $price_factory, PriceFormatterInterface $price_formatter, OrderInterface $order, OrderLineItemInterface $line_item) {
$formatter_defaults = [
'vat_info' => FALSE,
'label' => FALSE,
'wrapper_element' => 'span',
];
$price_instance = $price_factory->getInstance([
'base' => 'gross',
'net' => $line_item->get('calculated_net')->getValue() * (float) $line_item->getQuantity(),
'gross' => $line_item->get('calculated_gross')->getValue() * (float) $line_item->getQuantity(),
'vat_rate' => $line_item->get('calculated_vat_rate')->getValue(),
'vat_category' => $line_item->get('calculated_vat_cat_name')->getValue(),
'vat_amount' => $line_item->get('calculated_vat_amount')->getValue() * (float) $line_item->getQuantity(),
'currency' => $order->get('currency')->getString(),
]);
$formatted = $price_formatter->buildFormatted($price_instance, PriceFormatterInterface::FORMAT_GROSS, $formatter_defaults);
return $formatted;
}
/**
* Gets renderable formatted price from a single float value.
*
* @param \Drupal\arch_price\Price\PriceFactoryInterface $price_factory
* Price factory service.
* @param \Drupal\arch_price\Price\PriceFormatterInterface $price_formatter
* Price formatter service.
* @param \Drupal\arch_order\Entity\OrderInterface $order
* Order object.
* @param float $price
* Price value.
*
* @return array
* Renderable formatted price.
*/
function arch_order_tokens__renderable_formatted_price(PriceFactoryInterface $price_factory, PriceFormatterInterface $price_formatter, OrderInterface $order, float $price) {
$formatter_defaults = [
'vat_info' => FALSE,
'label' => FALSE,
'wrapper_element' => 'span',
];
$price_instance = $price_factory->getInstance([
'base' => 'gross',
'net' => 0,
'gross' => $price,
'vat_rate' => 0,
'vat_category' => 'custom',
'vat_amount' => 0,
'currency' => $order->get('currency')->getString(),
]);
$formatted = $price_formatter->buildFormatted($price_instance, PriceFormatterInterface::FORMAT_GROSS, $formatter_defaults);
return $formatted;
}
