Commit 03a84591 authored by Michael Stenta's avatar Michael Stenta
Browse files

Issue #3324839: Refactor price quantity data architecture

parents 7183746a 7d47457f
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -64,15 +64,14 @@ process:
      plugin: create_quantity
      default_values:
        type: 'price'
        measure: 'value'
      values:
        uid: '@uid'
        created: '@created'
        changed: '@changed'
        value: field_farm_total_price
        value: field_farm_quantity_value
        units: '@_units'
        unit_quantity: field_farm_quantity_value
        unit_price: field_farm_unit_price
        total_price: field_farm_total_price
  # Purchase specific fields.
  invoice_number:
    plugin: get
+2 −3
Original line number Diff line number Diff line
@@ -64,15 +64,14 @@ process:
      plugin: create_quantity
      default_values:
        type: 'price'
        measure: 'value'
      values:
        uid: '@uid'
        created: '@created'
        changed: '@changed'
        value: field_farm_total_price
        value: field_farm_quantity_value
        units: '@_units'
        unit_quantity: field_farm_quantity_value
        unit_price: field_farm_unit_price
        total_price: field_farm_total_price
  # Sale specific fields.
  customer:
    plugin: get

farm_ledger.module

deleted100644 → 0
+0 −89
Original line number Diff line number Diff line
<?php

/**
 * @file
 * farmOS ledger module.
 */

use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_inline_entity_form_entity_form_alter().
 */
function farm_ledger_inline_entity_form_entity_form_alter(array &$entity_form, FormStateInterface &$form_state) {

  // Bail if not a price quantity inline entity form.
  if ($entity_form['#entity_type'] !== 'quantity' || $entity_form['#bundle'] !== 'price') {
    return;
  }

  // Hide the measure field.
  $entity_form['measure']['#access'] = FALSE;

  // Hide the value field. It is auto-populated from the unit_price and
  // unit_quantity fields when the quantity is saved.
  $entity_form['value']['#access'] = FALSE;

  // Hide inventory fields from the price quantity.
  foreach (['inventory_adjustment', 'inventory_asset'] as $inventory_field) {
    if (!empty($entity_form[$inventory_field])) {
      $entity_form[$inventory_field]['#access'] = FALSE;
    }
  }
}

/**
 * Prepares price quantities for display.
 *
 * Default template: quantity.html.twig.
 *
 * @param array $variables
 *   An associative array containing:
 *   - elements: An associative array containing the quantity information and
 *     any fields attached to the quantity. Properties used:
 *     - #quantity: A \Drupal\quantity\Entity\Quantity object. Quantity entity.
 *   - attributes: HTML attributes for the containing element.
 */
function farm_ledger_preprocess_quantity(array &$variables) {

  /** @var \Drupal\quantity\Entity\QuantityInterface $quantity */
  $quantity = $variables['elements']['#quantity'];

  // Only alter price quantities.
  if ($quantity->bundle() === 'price') {

    // Always hide the measure and price fields.
    unset($variables['content']['measure']);
    unset($variables['content']['unit_price']);
    unset($variables['content']['unit_quantity']);

    // Get the units.
    $units = 'N/A';
    if (!empty($variables['content']['units'])) {
      $units = $quantity->get('units')->entity->label();
    }
    // Ensure the total value uses the same units.
    $variables['content']['units'] = ['#markup' => $units];

    // Get the unit price.
    $unit_price = 'N/A';
    if (!$quantity->get('unit_price')->isEmpty()) {
      $unit_price = $quantity->get('unit_price')->fraction->toDecimal(0, TRUE);
    }

    // Get the unit quantity.
    $unit_quantity = 'N/A';
    if (!$quantity->get('unit_quantity')->isEmpty()) {
      $unit_quantity = $quantity->get('unit_quantity')->fraction->toDecimal(0, TRUE);
    }

    // Build the quantity price info.
    $price = [
      '#prefix' => '<span class="price">',
      '#suffix' => '</span>',
      '#markup' => '(' . t('Unit price: @unit_price @units, Unit quantity: @unit_quantity', ['@unit_price' => $unit_price, '@units' => $units, '@unit_quantity' => $unit_quantity]) . ')',
      '#weight' => 5,
    ];
    $variables['content']['price'] = $price;
  }
}
+77 −0
Original line number Diff line number Diff line
<?php

/**
 * @file
 * Post update hooks for the farm_ledger module.
 */

use Drupal\Core\Utility\UpdateException;
use Drupal\taxonomy\Entity\Term;

/**
 * Update price quantity data structure and migrate data.
 */
function farm_ledger_post_update_migrate_price_quantity_total_price(&$sandbox) {

  // This function will be run as a batch operation. On the first run, we will
  // make preparations. This logic should only run once.
  if (!isset($sandbox['current_quantity'])) {

    // Query the database for all price quantity IDs.
    $sandbox['price_quantity_ids'] = \Drupal::database()->query("SELECT id FROM {quantity} WHERE type = 'price'")->fetchCol();

    // Install the new total_price field.
    $update_manager = \Drupal::entityDefinitionUpdateManager();
    $options = [
      'type' => 'fraction',
      'label' => t('Total price'),
      'description' => t('The total price. If left blank, this will be automatically calculated.'),
      'weight' => [
        'form' => 12,
        'view' => 12,
      ],
    ];
    $field_definition = \Drupal::service('farm_field.factory')->bundleFieldDefinition($options);
    $update_manager->installFieldStorageDefinition('total_price', 'quantity', 'farm_ledger', $field_definition);

    // Track progress.
    $sandbox['current_quantity'] = 0;
    $sandbox['#finished'] = 0;
  }

  // Get the active database connection.
  $database = \Drupal::database();

  // Iterate through price quantities, 10 at a time.
  $quantity_count = count($sandbox['price_quantity_ids']);
  $end_quantity = $sandbox['current_quantity'] + 10;
  $end_quantity = $end_quantity > $quantity_count ? $quantity_count : $end_quantity;
  for ($i = $sandbox['current_quantity']; $i < $end_quantity; $i++) {

    // Iterate the global counter.
    $sandbox['current_quantity']++;

    // Get the quantity ID.
    $id = $sandbox['price_quantity_ids'][$i];

    // Migrate value to total_price, and unit_quantity to value. We use raw
    // database queries for this to avoid creating a new quantity revision,
    // because the old revision would have missing data.
    $database->query("INSERT INTO {quantity__total_price} (SELECT type as bundle, 0 as deleted, id as entity_id, revision_id, 'und' as langcode, 0 as delta, value__numerator as total_price_numerator, value__denominator as total_price_denominator FROM {quantity} WHERE id = :id)", [':id' => $id]);
    $database->query("INSERT INTO {quantity_revision__total_price} (SELECT type as bundle, 0 as deleted, id as entity_id, revision_id, 'und' as langcode, 0 as delta, value__numerator as total_price_numerator, value__denominator as total_price_denominator FROM {quantity} WHERE id = :id)", [':id' => $id]);
    $database->query("UPDATE {quantity} q SET value__numerator = (SELECT unit_quantity_numerator FROM {quantity__unit_quantity} uq WHERE uq.entity_id = q.id), value__denominator = (SELECT unit_quantity_denominator FROM {quantity__unit_quantity} uq WHERE uq.entity_id = q.id) WHERE q.id = :id", [':id' => $id]);
    $database->query("UPDATE {quantity_revision} qr SET value__numerator = (SELECT unit_quantity_numerator FROM {quantity_revision__unit_quantity} uq WHERE uq.entity_id = qr.id), value__denominator = (SELECT unit_quantity_denominator FROM {quantity_revision__unit_quantity} uq WHERE uq.entity_id = qr.id) WHERE qr.id = :id", [':id' => $id]);
  }

  // Update progress.
  $sandbox['#finished'] = $sandbox['current_quantity'] / count($sandbox['price_quantity_ids']);

  // When we are finished, delete the unit_quantity field.
  if ($sandbox['#finished'] == 1) {
    $update_manager = \Drupal::entityDefinitionUpdateManager();
    $storage_definition = $update_manager->getFieldStorageDefinition('unit_quantity', 'quantity');
    $update_manager->uninstallFieldStorageDefinition($storage_definition);
  }

  return NULL;
}
+7 −7
Original line number Diff line number Diff line
@@ -34,16 +34,16 @@ function farm_ledger_views_data_alter(array &$data) {
    ],
  ];

  // Create unit quantity field, filter, and sort using fraction decimal
  // Create total price field, filter, and sort using fraction decimal
  // handlers.
  $fraction_fields = [
    'numerator' => 'unit_quantity_numerator',
    'denominator' => 'unit_quantity_denominator',
    'numerator' => 'total_price_numerator',
    'denominator' => 'total_price_denominator',
  ];
  $data['quantity__unit_quantity']['unit_quantity_value'] = [
    'title' => t('Unit quantity'),
    'help' => t('Value of the unit quantity, in decimal format.'),
    'real field' => 'unit_quantity_numerator',
  $data['quantity__total_price']['total_price_value'] = [
    'title' => t('Total price'),
    'help' => t('Value of the total price, in decimal format.'),
    'real field' => 'total_price_numerator',
    'field' => [
      'id' => 'fraction',
      'additional fields' => $fraction_fields,
Loading