From dfd236fdce60b394ec4814e7b60921278b648b2b Mon Sep 17 00:00:00 2001 From: Peter Dulacka Date: Mon, 23 Dec 2019 11:43:24 +0100 Subject: [PATCH 1/8] Fixing czech translations, config sorting and charge before edge cases remp/novydenik#476 --- src/lang/products.cs_CZ.neon | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lang/products.cs_CZ.neon b/src/lang/products.cs_CZ.neon index b442860..45d08a8 100644 --- a/src/lang/products.cs_CZ.neon +++ b/src/lang/products.cs_CZ.neon @@ -42,7 +42,7 @@ data: sorting: Na první pozici description: např. Tento produkt je super ean: např. 8580000000000 - image_url: napr. http://dennikn.sk/images/shop.jpg + image_url: např. http://dennikn.sk/images/shop.jpg og_image_url: např. http://dennikn.sk/images/shop.jpg images: např. http://dennikn.sk/images/shop.jpg descriptions: @@ -259,7 +259,7 @@ frontend: pass_required: Položka Heslo je povinná. account_exists: 'Účet se zadaným emailem již existuje, prosím přihlaste se pomocí hesla' phone_number: 'Telefonní číslo (pomůže nám při doručování)' - phone_number_placeholder: 'Napr. 0908 123 456' + phone_number_placeholder: 'např. 0908 123 456' phone_number_required: 'Položka Telefonní číslo je povinná.' phone_number_min_length: 'Telefónne číslo musí mať aspon 6 znakov.' want_invoice: Chci fakturu @@ -338,7 +338,7 @@ config: category: Obchod shop_host: name: URL obchodu - description: 'URL obchodu (v případě, že běží na vlastní doméně; napr. obchod.crm.press)' + description: 'URL obchodu (v případě, že běží na vlastní doméně; např. obchod.crm.press)' shop_header_block: name: Kód v hlavičce pro obchod description: 'Libovolný kód (např. Google analytics nebo další), který se má vložit do hlavičky šablony obchodu' From 6feb4168ac9168bbd0f03aee5db283c545ba7649 Mon Sep 17 00:00:00 2001 From: Peter Dulacka Date: Fri, 27 Dec 2019 16:20:24 +0100 Subject: [PATCH 2/8] Adding exit codes to all commands due to change in Symfony Commands in symfony framework are now required to provide exit code in every `execute()` method. --- src/commands/CalculateAveragesCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/commands/CalculateAveragesCommand.php b/src/commands/CalculateAveragesCommand.php index 59287ac..ea31702 100644 --- a/src/commands/CalculateAveragesCommand.php +++ b/src/commands/CalculateAveragesCommand.php @@ -76,5 +76,7 @@ protected function execute(InputInterface $input, OutputInterface $output) ON DUPLICATE KEY UPDATE `updated_at`=NOW(), `value`=VALUES(value); SQL ); + + return 0; } } From f5ff9d25d7b349c7618a9aa745ec99417a76c7be Mon Sep 17 00:00:00 2001 From: Peter Dulacka Date: Fri, 27 Dec 2019 17:05:49 +0100 Subject: [PATCH 3/8] Fixing empty ebook providers - foreach should always receive array --- src/models/Ebook/EbookProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/Ebook/EbookProvider.php b/src/models/Ebook/EbookProvider.php index dad07f2..8ee6568 100644 --- a/src/models/Ebook/EbookProvider.php +++ b/src/models/Ebook/EbookProvider.php @@ -7,7 +7,7 @@ class EbookProvider { /** @var EbookProviderInterface[] */ - private $providers; + private $providers = []; public function register(EbookProviderInterface $ebookProvider) { From f810315ff751851d068598cf7a6bd307e3e38dc7 Mon Sep 17 00:00:00 2001 From: Peter Dulacka Date: Fri, 3 Jan 2020 10:31:53 +0100 Subject: [PATCH 4/8] Fixing incorrect count of sold products in product detail remp/crm#964 --- src/presenters/ProductsAdminPresenter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/presenters/ProductsAdminPresenter.php b/src/presenters/ProductsAdminPresenter.php index 1609dcd..9d4fbbe 100644 --- a/src/presenters/ProductsAdminPresenter.php +++ b/src/presenters/ProductsAdminPresenter.php @@ -2,11 +2,11 @@ namespace Crm\ProductsModule\Presenters; +use Crm\AdminModule\Presenters\AdminPresenter; use Crm\ApplicationModule\Components\Graphs\GoogleLineGraphGroupControlFactoryInterface; use Crm\ApplicationModule\Components\VisualPaginator; use Crm\ApplicationModule\Graphs\Criteria; use Crm\ApplicationModule\Graphs\GraphDataItem; -use Crm\AdminModule\Presenters\AdminPresenter; use Crm\PaymentsModule\Repository\PaymentItemsRepository; use Crm\PaymentsModule\Repository\PaymentsRepository; use Crm\ProductsModule\Forms\ProductsFormFactory; @@ -92,7 +92,7 @@ private function getProductSalesCount(IRow $product) return $this->paymentItemsRepository->getTable() ->where('product_id', $product->id) ->where('payment.status', PaymentsRepository::STATUS_PAID) - ->fetchField('COUNT(`count`)'); + ->fetchField('SUM(`count`)'); } public function renderUserList(int $id, string $type, float $fromLevel, float $toLevel = null) From 8aca22568c09784bd769295ac28476e234a2f7be Mon Sep 17 00:00:00 2001 From: Peter Dulacka Date: Fri, 3 Jan 2020 13:28:25 +0100 Subject: [PATCH 5/8] Fixing shop redirect resolver missing payment instance scenario --- .../ShopPaymentCompleteRedirectResolver.php | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/models/ShopPaymentCompleteRedirectResolver.php b/src/models/ShopPaymentCompleteRedirectResolver.php index 3856087..8f323e3 100644 --- a/src/models/ShopPaymentCompleteRedirectResolver.php +++ b/src/models/ShopPaymentCompleteRedirectResolver.php @@ -9,28 +9,34 @@ class ShopPaymentCompleteRedirectResolver implements PaymentCompleteRedirectReso { public function wantsToRedirect(?ActiveRow $payment, string $status): bool { - if ($payment && $status === self::PAID) { - return !empty($payment->related('order')->fetch()); - } - if ($status === self::ERROR) { - return !empty($payment->related('order')->fetch()); + if ($payment) { + if ($status === self::PAID) { + return !empty($payment->related('order')->fetch()); + } + if ($status === self::ERROR) { + return !empty($payment->related('order')->fetch()); + } } + return false; } public function redirectArgs(?ActiveRow $payment, string $status): array { - if ($payment && $status === self::PAID) { - return [ - ':Products:Shop:Success', - ['id' => $payment->variable_symbol], - ]; - } - if ($status === self::ERROR) { - return [ - ':Products:Shop:Error', - ]; + if ($payment) { + if ($status === self::PAID) { + return [ + ':Products:Shop:Success', + ['id' => $payment->variable_symbol], + ]; + } + if ($status === self::ERROR) { + return [ + ':Products:Shop:Error', + ]; + } } + throw new \Exception('unhandled status when requesting redirectArgs (did you check wantsToRedirect first?): ' . $status); } } From af814526515a53de93acafcbd9277f5b5cda8351 Mon Sep 17 00:00:00 2001 From: Peter Dulacka Date: Thu, 16 Jan 2020 10:11:10 +0100 Subject: [PATCH 6/8] Fixing missing sold products count if no product was sold yet --- src/presenters/ProductsAdminPresenter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/presenters/ProductsAdminPresenter.php b/src/presenters/ProductsAdminPresenter.php index 9d4fbbe..bb32bfc 100644 --- a/src/presenters/ProductsAdminPresenter.php +++ b/src/presenters/ProductsAdminPresenter.php @@ -92,7 +92,7 @@ private function getProductSalesCount(IRow $product) return $this->paymentItemsRepository->getTable() ->where('product_id', $product->id) ->where('payment.status', PaymentsRepository::STATUS_PAID) - ->fetchField('SUM(`count`)'); + ->fetchField('COALESCE(SUM(`count`), 0)'); } public function renderUserList(int $id, string $type, float $fromLevel, float $toLevel = null) From 703e1317a9476257d09c83e2567ce980bd1bca1c Mon Sep 17 00:00:00 2001 From: Peter Dulacka Date: Thu, 16 Jan 2020 15:16:24 +0100 Subject: [PATCH 7/8] Unifying file/filename usages to stay consistent within system remp/crm#890 --- src/events/PaymentStatusChangeHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/PaymentStatusChangeHandler.php b/src/events/PaymentStatusChangeHandler.php index bbb1ddb..77c3aab 100644 --- a/src/events/PaymentStatusChangeHandler.php +++ b/src/events/PaymentStatusChangeHandler.php @@ -150,7 +150,7 @@ private function attachAttachments(ActiveRow $payment, ActiveRow $order, &$templ $attachment = file_get_contents($attachmentName); if ($attachment !== false) { $attachments[] = [ - 'filename' => 'coupon.pdf', + 'file' => 'coupon.pdf', 'content' => $attachment, 'mime_type' => 'application/pdf', ]; From ef1587dfe02cdf2682429497b1b80cd1b2b2ff53 Mon Sep 17 00:00:00 2001 From: Dominik Skerhak Date: Thu, 16 Jan 2020 19:52:41 +0100 Subject: [PATCH 8/8] Add search/filter to product listing We have too many products now. Adding basic filter to ease searching of products. Will be extended when needed. - Searching text in columns `name`, `code`, `user_label`. - Searching number (int/float) in columns `price`, `catalog_price`. (This is working for both formats of decimal separator, so both '8,9' and '8.9' will search for same number.) remp/crm#985 --- src/lang/products.cs_CZ.neon | 3 ++ src/lang/products.en_US.neon | 4 ++ src/lang/products.sk_SK.neon | 4 ++ src/models/Repository/ProductsRepository.php | 27 +++++++++++- src/presenters/ProductsAdminPresenter.php | 45 ++++++++++++++++++-- src/templates/ProductsAdmin/default.latte | 7 ++- 6 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/lang/products.cs_CZ.neon b/src/lang/products.cs_CZ.neon index 45d08a8..5820689 100644 --- a/src/lang/products.cs_CZ.neon +++ b/src/lang/products.cs_CZ.neon @@ -80,6 +80,9 @@ admin: default: header: Produkty new: Vytvoriť produkt + admin_filter_form: + text: + placeholder: 'Název / Identifikátor / Veřejný popis / Cena' new: title: Nový produkt back: Spať na zoznam diff --git a/src/lang/products.en_US.neon b/src/lang/products.en_US.neon index 89e3323..d61cbbc 100644 --- a/src/lang/products.en_US.neon +++ b/src/lang/products.en_US.neon @@ -82,6 +82,10 @@ admin: default: header: Products new: Create product + admin_filter_form: + text: + placeholder: 'Name / Identifier / Label / Price' + new: title: New product back: Back to the list diff --git a/src/lang/products.sk_SK.neon b/src/lang/products.sk_SK.neon index bc7a57b..ca86db8 100644 --- a/src/lang/products.sk_SK.neon +++ b/src/lang/products.sk_SK.neon @@ -82,6 +82,10 @@ admin: default: header: Produkty new: Vytvoriť produkt + admin_filter_form: + text: + placeholder: 'Názov / Identifikátor / Verejný popis / Cena' + new: title: Nový produkt back: Spať na zoznam diff --git a/src/models/Repository/ProductsRepository.php b/src/models/Repository/ProductsRepository.php index 935d15a..b297c12 100644 --- a/src/models/Repository/ProductsRepository.php +++ b/src/models/Repository/ProductsRepository.php @@ -39,9 +39,32 @@ public function __construct( $this->productShopCountsDistribution = $productShopCountsDistribution; } - public function all() + public function all(string $search = null) { - return $this->getTable()->order('-sorting DESC, name ASC'); + $all = $this->getTable()->order('-sorting DESC, name ASC'); + + if (is_null($search) || empty(trim($search))) { + return $all; + } + + $searchText = "%{$search}%"; + $conditions = [ + 'name LIKE ?' => $searchText, + 'code LIKE ?' => $searchText, + 'user_label LIKE ?' => $searchText, + ]; + + // check if searched text is number (replace comma with period; otherwise is_numeric won't work) + $searchNum = str_replace(',', '.', $search); + if (is_numeric($searchNum)) { + $searchFloat = floatval($searchNum); + $conditions = array_merge($conditions, [ + 'price = ?' => $searchFloat, + 'catalog_price = ?' => $searchFloat, + ]); + } + + return $all->whereOr($conditions); } public function getByCode($code) diff --git a/src/presenters/ProductsAdminPresenter.php b/src/presenters/ProductsAdminPresenter.php index bb32bfc..d722d03 100644 --- a/src/presenters/ProductsAdminPresenter.php +++ b/src/presenters/ProductsAdminPresenter.php @@ -12,9 +12,11 @@ use Crm\ProductsModule\Forms\ProductsFormFactory; use Crm\ProductsModule\PaymentItem\ProductPaymentItem; use Crm\ProductsModule\Repository\ProductsRepository; +use Nette\Application\UI\Form; use Nette\Database\Table\ActiveRow; use Nette\Database\Table\IRow; use Nette\Http\Request; +use Tomaj\Form\Renderer\BootstrapInlineRenderer; class ProductsAdminPresenter extends AdminPresenter { @@ -39,11 +41,16 @@ public function __construct( $this->paymentItemsRepository = $paymentItemsRepository; } - public function renderDefault() + public function startup() { - $products = $this->productsRepository->all(); + parent::startup(); + $this->text = isset($this->params['text']) ? $this->params['text'] : null; + } - $filteredCount = $this->template->filteredCount = $products->count('*'); + public function renderDefault() + { + $products = $this->productsRepository->all($this->text); + $filteredCount = $products->count(); $vp = new VisualPaginator(); $this->addComponent($vp, 'products_vp'); @@ -53,6 +60,9 @@ public function renderDefault() $this->template->vp = $vp; $this->template->products = $products->limit($paginator->getLength(), $paginator->getOffset()); + + $this->template->allProductsCount = $this->productsRepository->all()->count(); + $this->template->filteredProductsCount = $filteredCount; } public function renderShow($id) @@ -168,4 +178,33 @@ protected function createComponentSaleGraph(GoogleLineGraphGroupControlFactoryIn return $control; } + + public function createComponentAdminFilterForm() + { + $form = new Form; + $form->setRenderer(new BootstrapInlineRenderer()); + $form->addText('text', $this->translator->translate('system.filter'), 50) + ->setAttribute('placeholder', $this->translator->translate('products.admin.products.default.admin_filter_form.text.placeholder')) + ->setAttribute('autofocus'); + + $form->addSubmit('send', $this->translator->translate('system.filter')) + ->getControlPrototype() + ->setName('button') + ->setHtml(' ' . $this->translator->translate('system.filter')); + $presenter = $this; + $form->addSubmit('cancel', $this->translator->translate('system.cancel_filter')) + ->onClick[] = function () use ($presenter) { + $presenter->redirect('ProductsAdmin:Default', ['text' => '']); + }; + + $form->setDefaults((array)$this->params); + + $form->onSuccess[] = [$this, 'adminFilterSubmited']; + return $form; + } + + public function adminFilterSubmited(Form $form, array $values) + { + $this->redirect('Default', $values); + } } diff --git a/src/templates/ProductsAdmin/default.latte b/src/templates/ProductsAdmin/default.latte index ff0fbeb..8ce934d 100644 --- a/src/templates/ProductsAdmin/default.latte +++ b/src/templates/ProductsAdmin/default.latte @@ -8,12 +8,17 @@

{_products.admin.products.default.header} - / {_system.total} {$filteredCount} + / {_system.total} {$allProductsCount} + {if $allProductsCount != $filteredProductsCount} + , {_system.filtered} {$filteredProductsCount} + {/if} {_products.admin.products.default.new}


+ {control adminFilterForm} +