Commit b303f822 authored by jsacksick's avatar jsacksick

Issue #3171289 by jsacksick: Support specifying multiple customers.

parent a5ab38a0
......@@ -6,8 +6,11 @@
*/
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\commerce\CommerceContentEntityStorage;
use Drupal\commerce_pricelist\Entity\PriceList;
use Drupal\commerce_pricelist\Entity\PriceListItem;
use Drupal\commerce_pricelist\Event\PriceListEvent;
use Drupal\commerce_pricelist\Event\PriceListItemEvent;
/**
* Replace the 'customer_role' field with the 'customer_roles' field.
......@@ -61,13 +64,13 @@ function commerce_pricelist_update_8201() {
function commerce_pricelist_update_8202() {
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$entity_type = $definition_update_manager->getEntityType('commerce_pricelist');
$entity_type->setHandlerClass('event', \Drupal\commerce_pricelist\Event\PriceListEvent::class);
$entity_type->setHandlerClass('storage', \Drupal\commerce\CommerceContentEntityStorage::class);
$entity_type->setHandlerClass('event', PriceListEvent::class);
$entity_type->setHandlerClass('storage', CommerceContentEntityStorage::class);
$definition_update_manager->updateEntityType($entity_type);
$entity_type = $definition_update_manager->getEntityType('commerce_pricelist_item');
$entity_type->setHandlerClass('event', \Drupal\commerce_pricelist\Event\PriceListItemEvent::class);
$entity_type->setHandlerClass('storage', \Drupal\commerce\CommerceContentEntityStorage::class);
$entity_type->setHandlerClass('event', PriceListItemEvent::class);
$entity_type->setHandlerClass('storage', CommerceContentEntityStorage::class);
$definition_update_manager->updateEntityType($entity_type);
}
......@@ -123,3 +126,61 @@ function commerce_pricelist_update_8204() {
$last_installed_schema_repository->setLastInstalledDefinition($entity_type);
}
}
/**
* Replace the 'customer' field with the 'customers' field.
*/
function commerce_pricelist_update_8205() {
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
// Create the customers field.
$storage_definition = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Customers'))
->setDescription(t('The customers for which the price list is valid.'))
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
->setSetting('target_type', 'user')
->setDisplayOptions('form', [
'type' => 'entity_reference_autocomplete',
'settings' => [
'match_operator' => 'CONTAINS',
'size' => '60',
'placeholder' => '',
],
]);
$definition_update_manager->installFieldStorageDefinition('customers', 'commerce_pricelist', 'commerce_pricelist', $storage_definition);
// Seed the new field manually, because Drupal core doesn't support
// using setInitialValueFromField() on a multivalue field.
$database = \Drupal::database();
$customer_ids = $database->select('commerce_pricelist', 'cp')
->fields('cp', ['id', 'type', 'customer'])
->where('cp.customer IS NOT NULL')
->execute()
->fetchAllAssoc('id');
$insert_query = $database->insert('commerce_pricelist__customers')
->fields(['bundle', 'deleted', 'entity_id', 'revision_id', 'langcode', 'delta', 'customers_target_id']);
foreach ($customer_ids as $id => $data) {
$insert_query->values([$data->type, 0, $id, $id, 'und', 0, $data->customer]);
}
$insert_query->execute();
// Remove the customer field.
$storage_definition = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Customer'))
->setName('customer')
->setTargetEntityTypeId('commerce_pricelist')
->setDescription(t('The customer for which the price list is valid.'))
->setSetting('target_type', 'user')
->setSetting('handler', 'default')
->setDisplayOptions('form', [
'type' => 'entity_reference_autocomplete',
'settings' => [
'match_operator' => 'CONTAINS',
'size' => '60',
'autocomplete_type' => 'tags',
'placeholder' => '',
],
]);
$definition_update_manager->uninstallFieldStorageDefinition($storage_definition);
}
<?php declare(strict_types = 1);
<?php
namespace Drupal\commerce_pricelist\Controller;
......@@ -13,7 +13,7 @@ class PriceListController {
/**
* Provides the title callback for the price list items collection route.
*
* @param \Drupal\Core\Routing\RouteMatchInterface
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The route match.
*
* @return string
......
......@@ -127,14 +127,38 @@ class PriceList extends CommerceContentEntityBase implements PriceListInterface
* {@inheritdoc}
*/
public function getCustomer() {
return $this->get('customer')->entity;
if ($this->get('customers')->isEmpty()) {
return NULL;
}
return $this->get('customers')->get(0)->entity;
}
/**
* {@inheritdoc}
*/
public function getCustomers() {
$customers = [];
foreach ($this->get('customers') as $field_item) {
if ($field_item->isEmpty() || !$field_item->entity) {
continue;
}
$customers[] = $field_item->entity;
}
return $customers;
}
/**
* {@inheritdoc}
*/
public function setCustomer(UserInterface $user) {
$this->set('customer', $user);
return $this->setCustomers([$user]);
}
/**
* {@inheritdoc}
*/
public function setCustomers(array $users) {
$this->set('customers', $users);
return $this;
}
......@@ -142,14 +166,17 @@ class PriceList extends CommerceContentEntityBase implements PriceListInterface
* {@inheritdoc}
*/
public function getCustomerId() {
return $this->get('customer')->target_id;
if ($this->get('customers')->isEmpty()) {
return NULL;
}
return $this->get('customers')->get(0)->target_id;
}
/**
* {@inheritdoc}
*/
public function setCustomerId($uid) {
$this->set('customer', $uid);
$this->set('customers', ['target_id' => $uid]);
return $this;
}
......@@ -306,17 +333,17 @@ class PriceList extends CommerceContentEntityBase implements PriceListInterface
'weight' => 2,
]);
$fields['customer'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Customer'))
->setDescription(t('The customer for which the price list is valid.'))
$fields['customers'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Customers'))
->setDescription(t('The customers for which the price list is valid.'))
->setSetting('target_type', 'user')
->setSetting('handler', 'default')
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
->setDisplayOptions('form', [
'type' => 'entity_reference_autocomplete',
'settings' => [
'match_operator' => 'CONTAINS',
'size' => '60',
'autocomplete_type' => 'tags',
'placeholder' => '',
],
]);
......
......@@ -38,9 +38,23 @@ interface PriceListInterface extends ContentEntityInterface, EntityChangedInterf
* @return \Drupal\user\UserInterface|null
* The customer user entity, or NULL if the price list is not limited to a
* specific customer.
*
* @deprecated in commerce_pricelist:8.x-2.0 and is removed from
* commerce_pricelist:8.x-3.0. Use $this->getCustomers() instead.
*
* @see https://www.drupal.org/project/commerce_pricelist/issues/3171289
*/
public function getCustomer();
/**
* Gets the customers.
*
* @return \Drupal\user\UserInterface|null
* The customers user entities, or NULL if the price list is not limited to
* specific customers.
*/
public function getCustomers();
/**
* Sets the customer.
*
......@@ -48,15 +62,35 @@ interface PriceListInterface extends ContentEntityInterface, EntityChangedInterf
* The customer.
*
* @return $this
*
* @deprecated in commerce_pricelist:8.x-2.0 and is removed from
* commerce_pricelist:8.x-3.0. Use $this->setCustomers() instead.
*
* @see https://www.drupal.org/project/commerce_pricelist/issues/3171289
*/
public function setCustomer(UserInterface $user);
/**
* Sets the customers.
*
* @param \Drupal\user\UserInterface[] $users
* The customers.
*
* @return $this
*/
public function setCustomers(array $users);
/**
* Gets the customer ID.
*
* @return int|null
* The customer ID, or NULL if the price list is not limited to a specific
* customer.
*
* @deprecated in commerce_pricelist:8.x-2.0 and is removed from
* commerce_pricelist:8.x-3.0. Use $this->getCustomers() instead.
*
* @see https://www.drupal.org/project/commerce_pricelist/issues/3171289
*/
public function getCustomerId();
......@@ -67,6 +101,11 @@ interface PriceListInterface extends ContentEntityInterface, EntityChangedInterf
* The customer ID.
*
* @return $this
*
* @deprecated in commerce_pricelist:8.x-2.0 and is removed from
* commerce_pricelist:8.x-3.0. Use $this->setCustomers() instead.
*
* @see https://www.drupal.org/project/commerce_pricelist/issues/3171289
*/
public function setCustomerId($uid);
......
......@@ -74,8 +74,8 @@ class PriceListForm extends ContentEntityForm {
// Hide the customer/customer_roles fields behind a set of radios, to
// emphasize that they are mutually exclusive.
$default_value = 'everyone';
if ($price_list->getCustomerId()) {
$default_value = 'customer';
if (!$price_list->get('customers')->isEmpty()) {
$default_value = 'customers';
}
elseif ($price_list->getCustomerRoles()) {
$default_value = 'customer_roles';
......@@ -85,14 +85,14 @@ class PriceListForm extends ContentEntityForm {
'#title' => $this->t('Customer eligibility'),
'#options' => [
'everyone' => $this->t('Everyone'),
'customer' => $this->t('Specific customer'),
'customers' => $this->t('Specific customers'),
'customer_roles' => $this->t('Customer roles'),
],
'#default_value' => $default_value,
'#weight' => 10,
];
$form['customer']['widget'][0]['target_id']['#states']['visible'] = [
'input[name="customer_eligibility"]' => ['value' => 'customer'],
$form['customers']['#states']['visible'] = [
'input[name="customer_eligibility"]' => ['value' => 'customers'],
];
$form['customer_roles']['widget']['#states']['visible'] = [
'input[name="customer_eligibility"]' => ['value' => 'customer_roles'],
......@@ -112,7 +112,7 @@ class PriceListForm extends ContentEntityForm {
* Process callback: assigns new weights to customer fields.
*/
public static function modifyCustomerFieldWeights($element, FormStateInterface $form_state, $form) {
$element['customer']['#weight'] = 11;
$element['customers']['#weight'] = 11;
$element['customer_roles']['#weight'] = 11;
return $element;
......@@ -144,15 +144,15 @@ class PriceListForm extends ContentEntityForm {
$price_list = $this->entity;
// Don't persist customer values that are not going to be used.
$customer_eligibility = $form_state->getValue('customer_eligibility');
if ($customer_eligibility == 'everyone') {
$price_list->setCustomerId(NULL);
if ($customer_eligibility === 'everyone') {
$price_list->set('customers', NULL);
$price_list->setCustomerRoles([]);
}
elseif ($customer_eligibility == 'customer') {
elseif ($customer_eligibility === 'customers') {
$price_list->setCustomerRoles([]);
}
elseif ($customer_eligibility == 'customer_roles') {
$price_list->setCustomerId(NULL);
elseif ($customer_eligibility === 'customer_roles') {
$price_list->set('customers', NULL);
}
$price_list->save();
$this->postSave($price_list, $this->operation);
......
......@@ -170,8 +170,8 @@ class PriceListRepository implements PriceListRepositoryInterface {
->condition('type', $bundle)
->condition('stores', [$store_id], 'IN')
->condition($query->orConditionGroup()
->condition('customer', $customer_id)
->notExists('customer')
->condition('customers', $customer_id)
->notExists('customers')
)
->condition($query->orConditionGroup()
->condition('customer_roles', $context->getCustomer()->getRoles(), 'IN')
......
......@@ -46,15 +46,16 @@ class PriceListTest extends CommerceBrowserTestBase {
'customer_eligibility' => 'customer_roles',
"customer_roles[$role]" => $role,
// The customer should not be persisted due to the role being used.
'customer[0][target_id]' => $this->adminUser->label() . ' (' . $this->adminUser->id() . ')',
'customers[0][target_id]' => $this->adminUser->label() . ' (' . $this->adminUser->id() . ')',
], 'Save');
$this->assertSession()->pageTextContains('Saved the Black Friday 2018 price list.');
/** @var \Drupal\commerce_pricelist\Entity\PriceListInterface $price_list */
$price_list = PriceList::load(1);
$this->assertEquals('Black Friday 2018', $price_list->getName());
$this->assertEquals('2018-07-07 13:37:00', $price_list->getStartDate()->format('Y-m-d H:i:s'));
$this->assertEquals([$role], $price_list->getCustomerRoles());
$this->assertEmpty($price_list->getCustomerId());
$this->assertEmpty($price_list->getCustomers());
}
/**
......@@ -80,19 +81,21 @@ class PriceListTest extends CommerceBrowserTestBase {
'name[0][value]' => 'Random list',
'start_date[0][value][date]' => '2018-08-08',
'start_date[0][value][time]' => '13:37:15',
'customer_eligibility' => 'customer',
'customer[0][target_id]' => $this->adminUser->label() . ' (' . $this->adminUser->id() . ')',
'customer_eligibility' => 'customers',
'customers[0][target_id]' => $this->adminUser->label() . ' (' . $this->adminUser->id() . ')',
// The role should not be persisted due to the customer being used.
"customer_roles[$role]" => $role,
], 'Save');
$this->assertSession()->pageTextContains('Saved the Random list price list.');
\Drupal::service('entity_type.manager')->getStorage('commerce_pricelist')->resetCache([$price_list->id()]);
/** @var \Drupal\commerce_pricelist\Entity\PriceListInterface $price_list */
$price_list = PriceList::load(1);
$this->assertEquals('Random list', $price_list->getName());
$this->assertEquals('2018-08-08 13:37:15', $price_list->getStartDate()->format('Y-m-d H:i:s'));
$this->assertEmpty($price_list->getCustomerRoles());
$this->assertEquals($this->adminUser->id(), $price_list->getCustomerId());
$this->adminUser = $this->reloadEntity($this->adminUser);
$this->assertEquals([$this->adminUser], $price_list->getCustomers());
}
/**
......
......@@ -25,7 +25,9 @@ class PriceListTest extends PriceListKernelTestBase {
* @covers ::getStoreIds
* @covers ::setStoreIds
* @covers ::getCustomer
* @covers ::getCustomers
* @covers ::setCustomer
* @covers ::setCustomers
* @covers ::getCustomerId
* @covers ::setCustomerId
* @covers ::getCustomerRoles
......@@ -62,10 +64,12 @@ class PriceListTest extends PriceListKernelTestBase {
$price_list->setCustomer($this->user);
$this->assertEquals($this->user, $price_list->getCustomer());
$this->assertEquals($this->user->id(), $price_list->getCustomerId());
$price_list->set('customer', NULL);
$price_list->set('customers', NULL);
$price_list->setCustomerId($this->user->id());
$this->assertEquals($this->user->id(), $price_list->getCustomerId());
$this->assertEquals($this->user, $price_list->getCustomer());
$price_list->setCustomers([$this->user]);
$this->assertEquals([$this->user], $price_list->getCustomers());
$price_list->setCustomerRoles(['authenticated']);
$this->assertEquals(['authenticated'], $price_list->getCustomerRoles());
......
......@@ -128,7 +128,7 @@ class PriceListRepositoryTest extends PriceListKernelTestBase {
* @covers ::loadItem
* @covers ::loadItems
*/
public function testCustomer() {
public function testCustomers() {
$repository = $this->container->get('commerce_pricelist.repository');
$customer = $this->createUser();
$this->priceList->setCustomer($customer);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment