contacts_events-8.x-1.x-dev/src/Commands/PriceDebugCommands.php
src/Commands/PriceDebugCommands.php
<?php
namespace Drupal\contacts_events\Commands;
use CommerceGuys\Intl\Formatter\CurrencyFormatterInterface;
use Drupal\commerce_order\Entity\OrderItemInterface;
use Drupal\contacts_events\Entity\EventClassInterface;
use Drupal\contacts_events\Entity\SingleUsePurchasableEntityInterface;
use Drupal\contacts_events\PriceCalculator;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drush\Commands\DrushCommands;
use Symfony\Component\Console\Helper\Table;
/**
* Contacts Events debugging command file.
*/
class PriceDebugCommands extends DrushCommands {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The price calculator.
*
* @var \Drupal\contacts_events\PriceCalculator
*/
protected $calculator;
/**
* The currency formatter.
*
* @var \CommerceGuys\Intl\Formatter\CurrencyFormatterInterface
*/
protected $formatter;
/**
* DebugCommands constructor.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\contacts_events\PriceCalculator $calculator
* The price calculator.
* @param \CommerceGuys\Intl\Formatter\CurrencyFormatterInterface $formatter
* The currency formatter.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, PriceCalculator $calculator, CurrencyFormatterInterface $formatter) {
parent::__construct();
$this->entityTypeManager = $entity_type_manager;
$this->calculator = $calculator;
$this->formatter = $formatter;
}
/**
* Debug price recalculation for a booking.
*
* @param int $order_id
* The Order ID.
* @param array $options
* An associative array of options whose values come from cli, aliases,
* config, etc.
*
* @usage contacts_events-commandName 50
* Debug the price recalculation for booking 50.
*
* @command events:debug:recalc
*
* @return int
* Exit code.
*/
public function recalculate(int $order_id, array $options = ['option-name' => 'default']): int {
/** @var \Drupal\commerce_order\Entity\OrderInterface|null $order */
$order = $this->entityTypeManager
->getStorage('commerce_order')
->load($order_id);
if (!$order) {
$this->io()->error("Unable to load order {$order_id}.");
return 1;
}
$this->io()->title("Debugging price recalculation for {$order->label()} [$order_id]");
// Get the class and window labels.
$classes = array_map(function (EventClassInterface $class) {
return $class->label();
}, $this->entityTypeManager->getStorage('contacts_events_class')->loadMultiple());
$windows = [];
foreach ($order->get('event')->entity->get('booking_windows') as $window) {
$windows[$window->id] = $window->label;
}
// Build our table.
$table = new Table($this->io());
$table->setHeaders([
'Item ID',
'Type',
'Purchased Entity',
'Label',
'Status',
'Class before',
'Window before',
'Price before',
'Class after',
'Window after',
'Price after',
]);
// Loop over the items and add to the table.
foreach ($order->getItems() as $item) {
$row = [
'id' => $item->id(),
'type' => $item->bundle(),
'purchased' => $item->getPurchasedEntityId(),
'label' => $item->label(),
'state' => $item->hasField('state') ? $item->get('state')->first()->getLabel() : '',
'class_before' => '',
'window_before' => '',
'price_before' => '',
'class_after' => '',
'window_after' => '',
'price_after' => '',
];
$this->addItemMappingInfo($row, $item, 'before', $classes, $windows);
// Recalculate the item for the 'after' version.
$this->calculator->calculatePrice($item);
$this->addItemMappingInfo($row, $item, 'after', $classes, $windows);
$table->addRow($row);
}
$table->render();
return 0;
}
/**
* Add the mapping and price info for an item.
*
* @param array $row
* The row to add to.
* @param \Drupal\commerce_order\Entity\OrderItemInterface $item
* The order item.
* @param string $col_suffix
* The column suffix, either 'before' or 'after'.
* @param array $classes
* The map of class IDs to labels.
* @param array $windows
* The map of window IDs to labels.
*/
protected function addItemMappingInfo(array &$row, OrderItemInterface $item, string $col_suffix, array $classes, array $windows) {
// Get the mapping.
if ($purchased_entity = $item->get('purchased_entity')->entity) {
if ($purchased_entity instanceof SingleUsePurchasableEntityInterface) {
$mapping = $purchased_entity->getMappedPrice();
}
}
// Otherwise see if we can get it from the order item.
if (!isset($mapping) && $item->hasField('mapped_price')) {
$mapped_price_items = $item->get('mapped_price');
if ($mapped_price_items->count()) {
$mapping = $mapped_price_items->first()->getValue();
}
}
// If we have mapping, add the details.
if (isset($mapping)) {
$row["class_{$col_suffix}"] = $classes[$mapping['class']] ?? $mapping['class'];
if ($mapping['class_overridden']) {
$row["class_{$col_suffix}"] .= '*';
}
$row["window_{$col_suffix}"] = $windows[$mapping['booking_window']] ?? $mapping['booking_window'];
if ($mapping['booking_window_overridden']) {
$row["window_{$col_suffix}"] .= '*';
}
}
// If we have a price, add it to the row.
if ($price = $item->getTotalPrice()) {
$row["price_{$col_suffix}"] = $this->formatter->format($price->getNumber(), $price->getCurrencyCode());
}
}
}
