Spun off from #2847862: Views support for adjustments since this doesn't require schema changes.

See https://github.com/drupalcommerce/commerce/pull/622/files for the initial code.

Issue fork commerce-3011966

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

bojanz created an issue. See original summary.

bojanz’s picture

czigor’s picture

Some useful snippets for this issue:

$order->getItems()[1]->adjustments[2]->value;
\Drupal::service('plugin.manager.commerce_adjustment_type')->getDefinitions();

The current adjustment views field is broken since there's no field formatter for it to use.

The downside of implementing this as a field formatter (instead of a views handler) is that when displaying order adjustments we also want to see order_item level adjustments (i.e. use collectAdjustments() instead of getAdjustments()). It's quite unusual for a field formatter to display data from other fields.

On the the pro side (of implementing this as a field formatter) the current views field would be fixed. We could add a field formatter setting "Also include order-item adjustments".

mglaman’s picture

The downside of implementing this as a field formatter (instead of a views handler) is that when displaying order adjustments we also want to see order_item level adjustments. It's quite unusual for a field formatter to display data from other fields.

We have EntityAdjustableInterface , which gives us getAdjustments . In order to expose adjustments as a formatter, we would need to limit based on the implementation of this interface. OrderInterface gives us the collectAdjustments method.

So, it sounds like we almost need two formatters. We need the regular adjustment field formatter that calculates the results out of getAdjustments and a second one that considers and order's collected adjustments via collectAdjustments .

It feels improper to have the formatter check if the entity's interface implements EntityAdjustableInterface OR OrderInterface and deciding what to display (or configured to display).

introfini’s picture

Just as a quick fix for a project I'm working on, I did a very rudimentary views field plugin for getting the total order adjustments per type. (no filter). If anyone needs it as a quick fix also, just let me know.

jeff veit’s picture

Yes @introfini, I'm interested in that. I was about to do exactly that too.

introfini’s picture

@Jeff Veit here it is: https://www.dropbox.com/s/pp3mc6ftpj175ag/bloom_custom.zip?dl=0

Has I said it's very rough, but you get the idea.

jeff veit’s picture

Thanks very much. I started on mine last night, and this will definitely help @introfini.

bradhawkins’s picture

@introfini or @Jeff Veit do you still have a copy of that field plugin? The dropbox link seems to be broken.

markjsjordan’s picture

Also wondering about that field plugin link @introfini / @Jeff Veit

introfini’s picture

StatusFileSize
new125.87 KB
new84.11 KB

I apologize for the delayed response.

As I've previously stated, this can be greatly improved; it was only done as a temporary solution to my issue.

Add this to your custom module:

/**
 * Implements hook_views_data().
 */
function mymodule_views_data() {

  // Views field to display the order and order item adjustments.
  $data['order_adjustments_field']['table']['group'] = t('Global');
  $data['order_adjustments_field']['table']['join'] = [
    // Exist in all views.
    '#global' => [],
  ];
  $data['order_adjustments_field']['order_adjustments_field'] = [
    'title' => t('Order and Order Item Adjustments Field'),
    'help' => t('Views field that shows the order and order item adjustments.'),
    'field' => [
      'id' => 'order_adjustments_field',
      'float' => TRUE,
    ],
  ];

  return $data;
}

Add a views field plugin at mymodule/src/Plugin/views/field/OrderAdjustments.php


namespace Drupal\mymodule\Plugin\views\field;

use Drupal\commerce_order\Adjustment;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\field\NumericField;
use Drupal\views\ResultRow;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\commerce_price\Price;


/**
 * Field handler to display the order and order item adjustments.
 * See Drupal Commerce issue:
 * https://www.drupal.org/project/commerce/issues/3011966
 *
 * @ingroup views_field_handlers
 * @ViewsField("order_adjustments_field")
 */
class OrderAdjustments extends NumericField {

  protected $entityTypeManager;

  /**
   * Order Adjustments Field constructor.
   *
   * @param array $configuration
   * @param $plugin_id
   * @param $plugin_definition
   * @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManager $entityTypeManager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * Sets the initial Cumulative Field data at zero.
   */
  public function query() {
  }

  /**
   * {@inheritdoc}
   */
  protected function defineOptions() {
    $options = parent::defineOptions();
    $options['adjustment_type'] = ['default' => NULL];
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);
    $field_options = ['shipping' => 'Shipping', 'promotion' => 'Promotion'];
    $form['adjustment_type'] = [
      '#type' => 'radios',
      '#title' => t('Adjustment type'),
      '#options' => $field_options,
      '#default_value' => $this->options['adjustment_type'],
      '#description' => t('Select the order adjustment type.'),
      '#weight' => -10,
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function getValue(ResultRow $values, $field = NULL) {
    parent::getValue($values, $field);

    // The field selected in the options form.
    $adjustment_type = $this->options['adjustment_type'];

    $entity_type = $values->_entity->getEntityType()->id();

    if ($entity_type == 'commerce_order_item') {

      /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
      $order_item = $values->_entity;
      $order = $order_item->getOrder();
      $quantity = $values->_entity->getQuantity();
      $order_item_adjustments = $order_item->getAdjustments();
      $unit_price = $order_item->get('unit_price')->getValue()[0]['number'];
      $product_variation = $order_item->getPurchasedEntity();
      $original_unit_price = $product_variation->getprice()->getNumber();
      $original_total_line = $quantity * $original_unit_price;
      $line_total = $order_item->getTotalPrice()->getNumber();
      $adjusted_line_total = $order_item->getAdjustedTotalPrice()->getNumber();

      return $adjusted_line_total;
    }

    if ($entity_type == 'commerce_order') {


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

      $order_total_summary = \Drupal::service('commerce_order.order_total_summary');
      $order_totals = $order_total_summary->buildTotals($order);

      foreach ($order_totals['adjustments'] as $adjustment) {
        $adjustments[$adjustment['type']] = $adjustment['amount'];
      }


      if ($adjustment_type == 'shipping' && isset($adjustments['shipping'])) {
        $value = $adjustments['shipping']->getNumber();
      }
      elseif ($adjustment_type == 'promotion' && isset($adjustments['promotion'])) {
        $order_total = $order->getTotalPrice()->getNumber();
        $order_shipping = $adjustments['shipping']->getNumber();
        //Valor sem descontos
        $order_subtotal = $order_totals['subtotal']->getNumber();
        //valor total dos descontos
        $value = $order_subtotal - $order_total + $order_shipping;

        //fix rounding values float
        $value = (int) $value;
      }
      else {
        return;
      }

      return (float) $value;
    }
  }

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

}


Clear the cache and add the field to views:

/files/issues/2022-09-09/SCR-20220909-kbl.png


Select the adjustment you want to include in the total:

/files/issues/2022-09-09/SCR-20220909-kbl.png

tomtech’s picture

Version: 8.x-2.x-dev » 3.x-dev
Assigned: Unassigned » tomtech

tomtech’s picture

Status: Active » Needs review

MR created that implements two field formatters for adjustments.

One is separator based. The other displays as a table.

Configuration options include specifying the adjustment type(s) to include, whether to display the label(s) of the adjustments, and currency options.

We can consider the collectAdjustments as a followup enhancement.

jsacksick’s picture

Title: Add a views field that allows showing adjustments filtered by type » Define field formatters for adjustments
StatusFileSize
new20.81 KB

Thank you Tom for addressing this, retitling the issue.

Tested this manually, works great! Only one minor comment regarding the Adjustment types setting. Just wondering whether we should use the label simply? Or if we stick with the plural label, perhaps we should uppercase the first character using ucfirst?

I think everywhere else (e.g: when adding an adjustment from the order edit form) we simply use the label (which is singular).

Adjustment types

  • jsacksick committed ac36aed6 on 3.x authored by tomtech
    Issue #3011966 by tomtech, introfini, jsacksick, bojanz, jeff veit,...
jsacksick’s picture

Status: Needs review » Fixed

Ok, went with the label for consistency. We might need a followup to call collectAdjustments() as it looks kinda odd to only display order level adjustments (which normally only contains shipping, shipping taxes and eventually shipping promotions). Other than that, all other adjustments are added to order items.
But I'm fine with doing this as a followup, since this is already a big improvement as we don't have formatters for anything atm :).

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.