From 5b56f33249a94c2876d4e411b3f2e01d0b8f6a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Ludvik?= Date: Wed, 28 Aug 2024 12:24:09 +0200 Subject: [PATCH] [shopsys] administrator now can see list of last ten orders on customer edit page (#3365) --- assets/js/admin/components/AdvancedSearch.js | 2 +- .../AdvancedSearchOperatorTranslation.php | 1 + .../AdvancedSearchOrderFilterTranslation.php | 2 + .../BillingAddressAndRelatedInfoFormType.php | 4 + .../User/CustomerUserUpdateFormType.php | 2 +- src/Form/OrderListType.php | 24 +++-- .../AdvancedSearchFilterInterface.php | 1 + .../OrderAdvancedSearchConfig.php | 4 + .../Filter/OrderCustomerIdFilter.php | 100 +++++++++++++++++ src/Model/Order/OrderFacade.php | 12 +++ src/Model/Order/OrderRepository.php | 22 ++++ src/Resources/translations/messages.cs.po | 15 ++- src/Resources/translations/messages.en.po | 15 ++- .../Admin/Form/orderlistFields.html.twig | 102 ++++++++++-------- 14 files changed, 246 insertions(+), 60 deletions(-) create mode 100644 src/Model/AdvancedSearchOrder/Filter/OrderCustomerIdFilter.php diff --git a/assets/js/admin/components/AdvancedSearch.js b/assets/js/admin/components/AdvancedSearch.js index dd526df792..47cfc3a2cc 100644 --- a/assets/js/admin/components/AdvancedSearch.js +++ b/assets/js/admin/components/AdvancedSearch.js @@ -70,7 +70,7 @@ export default class AdvancedSearch { } static updateValueByOperator ($rulesContainer, $rule, operator) { - $rule.find('.js-advanced-search-rule-value').toggle(operator !== 'notSet'); + $rule.find('.js-advanced-search-rule-value').toggle(operator !== 'notSet' && operator !== 'notRegistered'); } static init ($container) { diff --git a/src/Form/Admin/AdvancedSearch/AdvancedSearchOperatorTranslation.php b/src/Form/Admin/AdvancedSearch/AdvancedSearchOperatorTranslation.php index 6501825a5c..d11ccd0cfd 100644 --- a/src/Form/Admin/AdvancedSearch/AdvancedSearchOperatorTranslation.php +++ b/src/Form/Admin/AdvancedSearch/AdvancedSearchOperatorTranslation.php @@ -20,6 +20,7 @@ public function __construct() AdvancedSearchFilterInterface::OPERATOR_CONTAINS => t('include'), AdvancedSearchFilterInterface::OPERATOR_NOT_CONTAINS => t('doesn\'t include'), AdvancedSearchFilterInterface::OPERATOR_NOT_SET => t('not entered'), + AdvancedSearchFilterInterface::OPERATOR_NOT_REGISTERED => t('not registered customer'), AdvancedSearchFilterInterface::OPERATOR_IS => t('is'), AdvancedSearchFilterInterface::OPERATOR_IS_NOT => t('not'), AdvancedSearchFilterInterface::OPERATOR_BEFORE => t('before'), diff --git a/src/Form/Admin/AdvancedSearch/AdvancedSearchOrderFilterTranslation.php b/src/Form/Admin/AdvancedSearch/AdvancedSearchOrderFilterTranslation.php index 0c51945179..c4f18e0c1a 100644 --- a/src/Form/Admin/AdvancedSearch/AdvancedSearchOrderFilterTranslation.php +++ b/src/Form/Admin/AdvancedSearch/AdvancedSearchOrderFilterTranslation.php @@ -6,6 +6,7 @@ use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderCityFilter; use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderCreateDateFilter; +use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderCustomerIdFilter; use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderEmailFilter; use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderLastNameFilter; use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderNameFilter; @@ -33,5 +34,6 @@ public function __construct() $this->addFilterTranslation(OrderLastNameFilter::NAME, t('Customer last name')); $this->addFilterTranslation(OrderEmailFilter::NAME, t('Customer email address')); $this->addFilterTranslation(OrderCityFilter::NAME, t('Customer city')); + $this->addFilterTranslation(OrderCustomerIdFilter::NAME, t('Customer ID')); } } diff --git a/src/Form/Admin/Customer/BillingAddressAndRelatedInfoFormType.php b/src/Form/Admin/Customer/BillingAddressAndRelatedInfoFormType.php index 65961b4e69..59b6729baf 100644 --- a/src/Form/Admin/Customer/BillingAddressAndRelatedInfoFormType.php +++ b/src/Form/Admin/Customer/BillingAddressAndRelatedInfoFormType.php @@ -7,6 +7,7 @@ use Shopsys\FrameworkBundle\Form\Constraints\UniqueBillingAddress; use Shopsys\FrameworkBundle\Form\CustomerUserListType; use Shopsys\FrameworkBundle\Form\DeliveryAddressListType; +use Shopsys\FrameworkBundle\Form\OrderListType; use Shopsys\FrameworkBundle\Model\Customer\Customer; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -36,6 +37,9 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'allowAdd' => true, 'deleteConfirmMessage' => t('Do you really want to remove this delivery address?'), ]) + ->add('orders', OrderListType::class, [ + 'customer' => $options['customer'], + ]) ->add('save', SubmitType::class); } diff --git a/src/Form/Admin/Customer/User/CustomerUserUpdateFormType.php b/src/Form/Admin/Customer/User/CustomerUserUpdateFormType.php index 19cb8ef7e0..1180d8d974 100644 --- a/src/Form/Admin/Customer/User/CustomerUserUpdateFormType.php +++ b/src/Form/Admin/Customer/User/CustomerUserUpdateFormType.php @@ -62,7 +62,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'customerUser' => $options['customerUser'], ]); $builder->add('orders', OrderListType::class, [ - 'customerUser' => $options['customerUser'], + 'customer' => $options['customerUser']->getCustomer(), ]); } diff --git a/src/Form/OrderListType.php b/src/Form/OrderListType.php index cdd0ec749a..9cf5b6c1a3 100644 --- a/src/Form/OrderListType.php +++ b/src/Form/OrderListType.php @@ -4,7 +4,8 @@ namespace Shopsys\FrameworkBundle\Form; -use Shopsys\FrameworkBundle\Model\Customer\User\CustomerUser; +use Shopsys\FrameworkBundle\Model\Customer\Customer; +use Shopsys\FrameworkBundle\Model\Localization\Localization; use Shopsys\FrameworkBundle\Model\Order\OrderFacade; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormInterface; @@ -15,20 +16,25 @@ class OrderListType extends AbstractType { /** * @param \Shopsys\FrameworkBundle\Model\Order\OrderFacade $orderFacade + * @param \Shopsys\FrameworkBundle\Model\Localization\Localization $localization */ - public function __construct(private readonly OrderFacade $orderFacade) - { + public function __construct( + private readonly OrderFacade $orderFacade, + private readonly Localization $localization, + ) { } /** * @param \Symfony\Component\OptionsResolver\OptionsResolver $resolver */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired('customerUser') - ->setAllowedTypes('customerUser', CustomerUser::class) + $resolver->setRequired(['customer', 'limit']) + ->setAllowedTypes('customer', Customer::class) + ->setAllowedTypes('limit', 'int') ->setDefaults([ 'mapped' => false, + 'limit' => 10, ]); } @@ -37,10 +43,12 @@ public function configureOptions(OptionsResolver $resolver) * @param \Symfony\Component\Form\FormInterface $form * @param array $options */ - public function buildView(FormView $view, FormInterface $form, array $options) + public function buildView(FormView $view, FormInterface $form, array $options): void { parent::buildView($view, $form, $options); - $view->vars['orders'] = $this->orderFacade->getCustomerUserOrderList($options['customerUser']); + $view->vars['orders'] = $this->orderFacade->getLastCustomerOrdersByLimit($options['customer'], $options['limit'], $this->localization->getAdminLocale()); + $view->vars['customer'] = $options['customer']; + $view->vars['limit'] = $options['limit']; } } diff --git a/src/Model/AdvancedSearch/AdvancedSearchFilterInterface.php b/src/Model/AdvancedSearch/AdvancedSearchFilterInterface.php index 91c85941ae..1b27168c1b 100644 --- a/src/Model/AdvancedSearch/AdvancedSearchFilterInterface.php +++ b/src/Model/AdvancedSearch/AdvancedSearchFilterInterface.php @@ -11,6 +11,7 @@ interface AdvancedSearchFilterInterface public const OPERATOR_CONTAINS = 'contains'; public const OPERATOR_NOT_CONTAINS = 'notContains'; public const OPERATOR_NOT_SET = 'notSet'; + public const OPERATOR_NOT_REGISTERED = 'notRegistered'; public const OPERATOR_IS = 'is'; public const OPERATOR_IS_NOT = 'isNot'; public const OPERATOR_BEFORE = 'before'; diff --git a/src/Model/AdvancedSearch/OrderAdvancedSearchConfig.php b/src/Model/AdvancedSearch/OrderAdvancedSearchConfig.php index ed48677960..ba68ce1187 100644 --- a/src/Model/AdvancedSearch/OrderAdvancedSearchConfig.php +++ b/src/Model/AdvancedSearch/OrderAdvancedSearchConfig.php @@ -6,6 +6,7 @@ use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderCityFilter; use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderCreateDateFilter; +use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderCustomerIdFilter; use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderEmailFilter; use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderLastNameFilter; use Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderNameFilter; @@ -30,6 +31,7 @@ class OrderAdvancedSearchConfig extends AdvancedSearchConfig * @param \Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderLastNameFilter $orderLastNameFilter * @param \Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderEmailFilter $orderEmailFilter * @param \Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderCityFilter $orderCityFilter + * @param \Shopsys\FrameworkBundle\Model\AdvancedSearchOrder\Filter\OrderCustomerIdFilter $orderCustomerIdFilter * @throws \Shopsys\FrameworkBundle\Model\AdvancedSearch\Exception\AdvancedSearchFilterAlreadyExistsException */ public function __construct( @@ -44,6 +46,7 @@ public function __construct( OrderLastNameFilter $orderLastNameFilter, OrderEmailFilter $orderEmailFilter, OrderCityFilter $orderCityFilter, + OrderCustomerIdFilter $orderCustomerIdFilter, ) { parent::__construct(); @@ -58,5 +61,6 @@ public function __construct( $this->registerFilter($orderPhoneNumberFilter); $this->registerFilter($orderStreetFilter); $this->registerFilter($orderCityFilter); + $this->registerFilter($orderCustomerIdFilter); } } diff --git a/src/Model/AdvancedSearchOrder/Filter/OrderCustomerIdFilter.php b/src/Model/AdvancedSearchOrder/Filter/OrderCustomerIdFilter.php new file mode 100644 index 0000000000..49c0859f8a --- /dev/null +++ b/src/Model/AdvancedSearchOrder/Filter/OrderCustomerIdFilter.php @@ -0,0 +1,100 @@ + $ruleData) { + if ($ruleData->operator === self::OPERATOR_NOT_REGISTERED) { + $queryBuilder->andWhere('o.customer IS NULL'); + + continue; + } + + try { + $customer = $this->customerFacade->getById((int)$ruleData->value); + $customerIds[] = $customer->getId(); + } catch (CustomerNotFoundException) { + $this->flashBag->add( + FlashMessage::KEY_ERROR, + t( + 'Customer with ID %customerId% not found.', + ['%customerId%' => $ruleData->value], + ), + ); + } + } + + if (count($customerIds) === 0) { + return; + } + + $queryBuilder->andWhere('o.customer IN(:customer_id_filter)'); + $queryBuilder->setParameter('customer_id_filter', $customerIds); + } +} diff --git a/src/Model/Order/OrderFacade.php b/src/Model/Order/OrderFacade.php index e4c3bbb797..88c92d6eb2 100644 --- a/src/Model/Order/OrderFacade.php +++ b/src/Model/Order/OrderFacade.php @@ -11,6 +11,7 @@ use Shopsys\FrameworkBundle\Form\Admin\QuickSearch\QuickSearchFormData; use Shopsys\FrameworkBundle\Model\Administrator\Security\AdministratorFrontSecurityFacade; use Shopsys\FrameworkBundle\Model\Cart\CartFacade; +use Shopsys\FrameworkBundle\Model\Customer\Customer; use Shopsys\FrameworkBundle\Model\Customer\User\CurrentCustomerUser; use Shopsys\FrameworkBundle\Model\Customer\User\CustomerUser; use Shopsys\FrameworkBundle\Model\Customer\User\CustomerUserFacade; @@ -191,6 +192,17 @@ public function getCustomerUserOrderList(CustomerUser $customerUser): array return $this->orderRepository->getCustomerUserOrderList($customerUser); } + /** + * @param \Shopsys\FrameworkBundle\Model\Customer\Customer $customer + * @param int $limit + * @param string $locale + * @return \Shopsys\FrameworkBundle\Model\Order\Order[] + */ + public function getLastCustomerOrdersByLimit(Customer $customer, int $limit, string $locale): array + { + return $this->orderRepository->getLastCustomerOrdersByLimit($customer, $limit, $locale); + } + /** * @param string $email * @param int $domainId diff --git a/src/Model/Order/OrderRepository.php b/src/Model/Order/OrderRepository.php index 16313faa1b..d3e8c42780 100644 --- a/src/Model/Order/OrderRepository.php +++ b/src/Model/Order/OrderRepository.php @@ -10,6 +10,7 @@ use Doctrine\ORM\QueryBuilder; use Shopsys\FrameworkBundle\Component\String\DatabaseSearching; use Shopsys\FrameworkBundle\Form\Admin\QuickSearch\QuickSearchFormData; +use Shopsys\FrameworkBundle\Model\Customer\Customer; use Shopsys\FrameworkBundle\Model\Customer\User\CustomerUser; use Shopsys\FrameworkBundle\Model\Order\Exception\OrderNotFoundException; use Shopsys\FrameworkBundle\Model\Order\Listing\OrderListAdminRepository; @@ -182,6 +183,27 @@ public function getCustomerUserOrderList(CustomerUser $customerUser) ->getQuery()->execute(); } + /** + * @param \Shopsys\FrameworkBundle\Model\Customer\Customer $customer + * @param int $limit + * @param string $locale + * @return \Shopsys\FrameworkBundle\Model\Order\Order[] + */ + public function getLastCustomerOrdersByLimit(Customer $customer, int $limit, string $locale): array + { + return $this->createOrderQueryBuilder() + ->select('o, os, ost, c') + ->join('o.status', 'os') + ->join('os.translations', 'ost', Join::WITH, 'ost.locale = :locale') + ->join('o.currency', 'c') + ->andWhere('o.customer = :customer') + ->orderBy('o.createdAt', 'DESC') + ->setParameter('customer', $customer) + ->setParameter('locale', $locale) + ->setMaxResults($limit) + ->getQuery()->execute(); + } + /** * @param string $email * @param int $domainId diff --git a/src/Resources/translations/messages.cs.po b/src/Resources/translations/messages.cs.po index 63e699c62c..939e01f0b7 100644 --- a/src/Resources/translations/messages.cs.po +++ b/src/Resources/translations/messages.cs.po @@ -874,6 +874,9 @@ msgstr "Byl upraven zákazník {{ name }}{{ name }} deleted" msgstr "Zákazník {{ name }} byl smazán" +msgid "Customer ID" +msgstr "ID zákazníka" + msgid "Customer activation" msgstr "Aktivace zákazníka" @@ -904,9 +907,6 @@ msgstr "Příjmení zákazníka" msgid "Customer name" msgstr "Jméno zákazníka" -msgid "Customer orders" -msgstr "Objednávky zákazníka" - msgid "Customer phone number" msgstr "Telefonní číslo zákazníka" @@ -934,6 +934,9 @@ msgstr "Skupina práv" msgid "Customer users" msgstr "Uživatelé" +msgid "Customer with ID %customerId% not found." +msgstr "Zákazník s ID %customerId% nebyl nalezen." + msgid "Customers" msgstr "Zákazníci" @@ -1933,6 +1936,9 @@ msgstr "Jazykové konstanty - vše" msgid "Language constants - view" msgstr "Jazykové konstanty - zobrazení" +msgid "Last %limit% customer orders" +msgstr "Posledních %limit% objednávek zákazníka" + msgid "Last action time" msgstr "Čas poslední akce" @@ -3943,6 +3949,9 @@ msgstr "není" msgid "not entered" msgstr "není zadáno" +msgid "not registered customer" +msgstr "neregistrovaný zákazník" + msgid "numbers" msgstr "čísla" diff --git a/src/Resources/translations/messages.en.po b/src/Resources/translations/messages.en.po index cb3451b622..29e304fcb3 100644 --- a/src/Resources/translations/messages.en.po +++ b/src/Resources/translations/messages.en.po @@ -874,6 +874,9 @@ msgstr "" msgid "Customer {{ name }} deleted" msgstr "" +msgid "Customer ID" +msgstr "" + msgid "Customer activation" msgstr "" @@ -904,9 +907,6 @@ msgstr "" msgid "Customer name" msgstr "" -msgid "Customer orders" -msgstr "" - msgid "Customer phone number" msgstr "" @@ -934,6 +934,9 @@ msgstr "" msgid "Customer users" msgstr "" +msgid "Customer with ID %customerId% not found." +msgstr "" + msgid "Customers" msgstr "" @@ -1933,6 +1936,9 @@ msgstr "" msgid "Language constants - view" msgstr "" +msgid "Last %limit% customer orders" +msgstr "" + msgid "Last action time" msgstr "" @@ -3943,6 +3949,9 @@ msgstr "" msgid "not entered" msgstr "" +msgid "not registered customer" +msgstr "" + msgid "numbers" msgstr "" diff --git a/src/Resources/views/Admin/Form/orderlistFields.html.twig b/src/Resources/views/Admin/Form/orderlistFields.html.twig index 5e6b903031..32ddd347ec 100644 --- a/src/Resources/views/Admin/Form/orderlistFields.html.twig +++ b/src/Resources/views/Admin/Form/orderlistFields.html.twig @@ -1,53 +1,67 @@ {% block order_list_row %}
-

{{ 'Customer orders'|trans }}

- {% if orders|length == 0 %} -
- {{ 'Customer has no orders so far.'|trans }} +
+

{{ 'Last %limit% customer orders'|trans({'%limit%': limit}) }}

+ {% if orders|length > 0 %} + - {% else %} -
-
-
- - + {% endif %} + + + {% if orders|length == 0 %} +
+ {{ 'Customer has no orders so far.'|trans }} +
+ {% else %} +
+
+
+
+ + + + + + + + + + + + {% for order in orders %} - - - - - - + + + + + + - - - {% for order in orders %} - - - - - - - - - {% endfor %} - -
{{ 'Order number'|trans }}{{ 'Created on'|trans }}{{ 'Billing address'|trans }}{{ 'Delivery address'|trans }}{{ 'Total price including VAT'|trans }}{{ 'Status'|trans }}
{{ 'Order number'|trans }}{{ 'Created on'|trans }}{{ 'Billing address'|trans }}{{ 'Delivery address'|trans }}{{ 'Total price including VAT'|trans }}{{ 'Status'|trans }} + + {{ order.number }} + + + {{ order.createdAt|formatDateTime }} + + {{ order.street }}
+ {{ order.city }}, {{ order.postcode }} +
+ {{ order.deliveryStreet }}
+ {{ order.deliveryCity }}, {{ order.deliveryPostcode }} +
{{ order.totalPriceWithVat|priceWithCurrency(order.currency) }}{{ order.status.name }}
- - {{ order.number }} - - - {{ order.createdAt|formatDateTime }} - - {{ order.street }}
- {{ order.city }}, {{ order.postcode }} -
- {{ order.deliveryStreet }}
- {{ order.deliveryCity }}, {{ order.deliveryPostcode }} -
{{ order.totalPriceWithVat|priceWithCurrency(order.currency) }}{{ order.status.name }}
-
+ {% endfor %} + +
- {% endif %} +
+ {% endif %}
{% endblock %}