diff --git a/CHANGE_LOG.txt b/CHANGE_LOG.txt
new file mode 100644
index 0000000..b8cbe60
--- /dev/null
+++ b/CHANGE_LOG.txt
@@ -0,0 +1,6 @@
+2.0.4 - Removed: country translations
+ - Added: Widget v6 support
+ - Added: possibility to choose from external pickup points
+ - Added: Journal 3 one page checkout support
+ - Added: support for entering decimal values in weight rules
+ - Added: OCMOD compatibility - installation using installer made possible
diff --git a/README.md b/README.md
index 76c725a..3ed7662 100644
--- a/README.md
+++ b/README.md
@@ -3,43 +3,9 @@
# Module for Opencart 3
## Download link
-[Download version 2.0.3](https://github.com/Zasilkovna/opencart3/archive/v2.0.3.zip)
+[Download version 2.0.4](https://github.com/Zasilkovna/opencart3/archive/v2.0.4.zip)
-### Installation
-1. Copy the **admin** and **catalog** directories from the archive to the root directory of your opencart store.
-2. Log in to Administration, go to Extensions »Extensions page and select the extension type **Shipping**.
-
-![screen1](https://raw.githubusercontent.com/Zasilkovna/opencart3/master/doc/img/01-extensions.png)
-
-3. Install the module by clicking the green (+) button.
-4. After installing the module, click the blue **edit** button.
-
-![screen2](https://raw.githubusercontent.com/Zasilkovna/opencart3/master/doc/img/02-extensions-zasilkovna.png)
-
-- On the General Module Configuration page, complete all fields
- - **API key** - you can find it in the [client section » Client support](https://client.packeta.com/en/support/)
- - **Max. weight** - for orders with a higher weight, the shipping method will not be offered in the shopping cart
- - **Default shipping cost** - basic shipping cost, you can define shipping prices for specific countries
- and weights below
- - **E-shop identifier** - identification of the sender which you have set in the client section of your [sender](https://client.packeta.com/en/senders/).
- - Enable or disable the module
-
-
-
-5. Next, add the transport rules by clicking on the "Edit" link. Enter the shipping cost and free shipping limit here
-for each country.
-
-
-
-6. Click the weight icon to enter the weighting rules for the selected country. Here you can select the shipping price
-for the selected weight range.
-
-
-
-7. The list of orders for which customers choose to transport via Packeta can be found in the main menu **Sales » Mail Order
-Orders**. Here you can export the marked orders to a csv file, which you then upload to the client section » [Parcels Import](https://client.packeta.com/en/packets-import/upload).
-
-### Informations about the module
+### Information about the module
#### Supported languages:
- czech
@@ -47,52 +13,23 @@ Orders**. Here you can export the marked orders to a csv file, which you then up
#### Supported versions:
- Opencart 3.0.0 and newer
+- php 5.6 - 7.x
#### Features provided:
-- Widget integration in eshop cart
-- Set different prices for different target countries
-- Setting prices according to weighting rules
-- Traffic tax and GEO zone settings
-- Free shipping from the specified price or weight of the order
-- Export shipments to a csv file that can be imported in the client section
+- widget v6 integration in the eshop cart
+- support for pickup points of external carriers
+- set different prices for different target countries
+- setting prices according to weighting rules
+- traffic tax and GEO zone settings
+- free shipping from the specified price or weight of the order
+- export shipments to a csv file that can be imported in the client section
+- Journal 3 one page checkout support
# Modul pro Opencart 3
### Stažení modulu
-[Aktuální verze 2.0.3](https://github.com/Zasilkovna/opencart3/archive/v2.0.3.zip)
-
-## Instalace
-1. Adresáře **admin** a **catalog** z archivu nakopírujte do kořenového adresáře vašeho obchodu opencart.
-2. Přihlašte se do administrace, přejděte na stránku Extensions » Extensions a vyberte typ rozšíření **Shipping**.
-
-
-
-3. Instalujte modul kliknutím na zelené tlačítko (+).
-4. Po nainstalování modulu klikněte na modré tlačítko **edit**
-
-
-
-Na stránce obecná konfigurace modulu vyplňte všechna pole:
-
-- **API klíč** - naleznete jej v [klientské sekci](https://client.packeta.com/cs/support/) » Klientská podpora
-- **Max. hmotnost** - u objednávek s větší hmotnostní nebude v košíku přepravní metoda Zásilkovna nabízena
-- **Výchozí cena dopravy** - základní cena dopravy, pro konkrétní země a hmotnosti můžete ceny dopravy definovat níže
-- **Identifikátor eshopu** - označení odesílatele které máte nastaveno v klientské sekci u vašeho [odesílatele](https://client.packeta.com/cs/senders/).
-- Povolte nebo zakažte modul
-
-
-
-5. Dále přidáme přepravní pravidla kliknutím na odkaz *Edit*. Pro jednotlivé země zde zadáte cenu přepravy a limit pro dopravu zdarma.
-
-
-
-6. Kliknutím na ikonu váhy zadáte váhová pravidla pro vybranou zemi. Můžete zde zvolit cenu přepravy pro zvolené váhové rozmezí.
-
-
+[Aktuální verze 2.0.4](https://github.com/Zasilkovna/opencart3/archive/v2.0.4.zip)
-Seznam objednávek u kterých si zákazníci zvolí dopravu přes Zásilkovnu najdete v hlavním menu **Sales » Zásilkovna Orders**.
-Zde můžete označené objednávky exportovat do csv souboru, který poté nahrajete do klientské sekce » [Import zásilek](https://client.packeta.com/cs/packets-import/upload).
-
### Informace o modulu
#### Podporované jazyky:
@@ -103,12 +40,15 @@ Zde můžete označené objednávky exportovat do csv souboru, který poté nahr
#### Podporované verze:
- Opencart 3.0.0 a novější
+- php 5.6 - 7.x
#### Poskytované funkce:
-- Integrace widgetu v košíku eshopu
-- Nastavení různé ceny pro různé cílové země
-- Nastavení cen podle váhových pravidel
-- Nastavení daně dopravy a GEO zóny
-- Doprava zdarma od zadané ceny nebo hmotnosti objednávky
-- Export zásilek do csv souboru, který lze importovat v [klientské sekci](https://client.packeta.com/)
+- integrace widgetu v6 v košíku eshopu
+- podpora výdejních míst externích dopravců
+- nastavení různé ceny pro různé cílové země
+- nastavení cen podle váhových pravidel
+- nastavení daně dopravy a GEO zóny
+- doprava zdarma od zadané ceny nebo hmotnosti objednávky
+- export zásilek do csv souboru, který lze importovat v [klientské sekci](https://client.packeta.com/)
+- podpora jednokrokového košíku Journal 3
diff --git a/catalog/controller/extension/module/zasilkovna.php b/catalog/controller/extension/module/zasilkovna.php
deleted file mode 100644
index 34e70ed..0000000
--- a/catalog/controller/extension/module/zasilkovna.php
+++ /dev/null
@@ -1,62 +0,0 @@
-load->model('extension/shipping/zasilkovna');
- $defaults = $this->model_extension_shipping_zasilkovna->loadSelectedBranch();
-
- $this->response->addHeader('Content-Type: application/json');
- $this->response->setOutput(json_encode($defaults));
- }
-
- /**
- * Loads properties of selected branch from session.
- *
- * @throws Exception
- */
- public function saveSelectedBranch() {
- $this->load->model('extension/shipping/zasilkovna');
- $this->model_extension_shipping_zasilkovna->saveSelectedBranch();
- }
-
- /**
- * Save additional order data to DB during "order confirm".
- * All required records with order data are created in DB during this step.
- * This method is called by "after" event on catalog/controller/checkout/confirm.
- *
- * @param string $route
- * @param array $args
- * @param int $output
- * @throws Exception
- */
- public function saveOrderData(&$route, &$args, &$output) {
- $this->load->model('extension/shipping/zasilkovna');
- $this->model_extension_shipping_zasilkovna->saveOrderData();
- }
-
- /**
- * Clean-up of additional order data in session when order is finished.
- * This method is called as "before" event on catalog/controller/checkout/success.
- *
- * @param string $route
- * @param array $args
- * @return void
- * @throws Exception
- */
- public function sessionCleanup(&$route, &$args) {
- $this->load->model('extension/shipping/zasilkovna');
- $this->model_extension_shipping_zasilkovna->sessionCleanup();
- }
-}
\ No newline at end of file
diff --git a/catalog/language/en-gb/extension/shipping/zasilkovna.php b/catalog/language/en-gb/extension/shipping/zasilkovna.php
deleted file mode 100644
index 4a305dc..0000000
--- a/catalog/language/en-gb/extension/shipping/zasilkovna.php
+++ /dev/null
@@ -1,13 +0,0 @@
-load->model(self::ROUTING_BASE_PATH);
- $this->model_extension_shipping_zasilkovna->createTablesAndEvents();
-
- // prefill default configuration items
- $defaultConfig = [
- 'shipping_zasilkovna_weight_max' => '5',
- 'shipping_zasilkovna_geo_zone_id' => '',
- 'shipping_zasilkovna_order_statuses' => [],
- 'shipping_zasilkovna_cash_on_delivery_methods' => []
- ];
- $this->load->model('setting/setting');
- $this->model_setting_setting->editSetting('shipping_zasilkovna', $defaultConfig);
-
- }
-
- /**
- * Entry point (main method) for plugin uninstalling.
- *
- * @throws Exception
- */
- public function uninstall() {
- $this->load->model(self::ROUTING_BASE_PATH);
- $this->model_extension_shipping_zasilkovna->deleteTablesAndEvents();
- }
-
- /**
- * Handler for main action of extension modul for Zasilkovna (main settings page).
- *
- * @throws Exception
- */
- public function index() {
- // save new values from POST request data to module settings
- if (($this->request->server['REQUEST_METHOD'] == 'POST') && ($this->checkPermissions())) {
- $this->load->language(self::ROUTING_BASE_PATH);
- $this->load->model('setting/setting');
- $this->model_setting_setting->editSetting('shipping_zasilkovna', $this->request->post);
- $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
- $this->response->redirect($this->createAdminLink('marketplace/extension', ['type' => 'shipping']));
- }
-
- // full initialization of page
- $data = $this->initPageData('', self::TEXT_TITLE_MAIN);
-
- // load data for list of weight rules
- $this->load->model(self::ROUTING_WEIGHT_RULES);
- $weightRules = $this->model_extension_shipping_zasilkovna_weight_rules->getAllRules();
- $usedCountries = array_keys($weightRules);
-
- // load data for list of shipping rules
- $this->load->model(self::ROUTING_SHIPPING_RULES);
- $shippingRules = $this->model_extension_shipping_zasilkovna_shipping_rules->getAllRules();
-
- // adding additional data for list of shipping rules
- foreach ($shippingRules as $ruleId => $ruleContent) {
- // name of country
- $shippingRules[$ruleId]['country_name'] = $this->language->get('country_' . $ruleContent['target_country']);
- // print message "not set" if default price or free shipping limit is not set
- if (empty($ruleContent['default_price'])) {
- $shippingRules[$ruleId]['default_price'] = $this->language->get('entry_sr_not_set');
- }
- if (empty($ruleContent['free_over_limit'])) {
- $shippingRules[$ruleId]['free_over_limit'] = $this->language->get('entry_sr_not_set');
- }
- // link to shipping rule editor
- $shippingRules[$ruleId][self::TEMPLATE_LINK_EDIT] = $this->createAdminLink(self::ACTION_SHIPPING_RULES_EDIT,
- [self::PARAM_RULE_ID => $ruleContent['rule_id']]);
- // link to list of weight rules
- $shippingRules[$ruleId]['link_weight_rules'] = $this->createAdminLink(self::ACTION_WEIGHT_RULES,
- [self::PARAM_COUNTRY => $ruleContent['target_country']]);
-
- if (in_array($ruleContent['target_country'], $usedCountries)) {
- $shippingRules[$ruleId]['weight_rules_description'] = $this->language->get('text_weight_rules_defined');
- $shippingRules[$ruleId]['weight_rules_tooltip'] = $this->language->get('help_weight_rules_change');
- }
- else {
- $shippingRules[$ruleId]['weight_rules_description'] = $this->language->get('text_weight_rules_missing');
- $shippingRules[$ruleId]['weight_rules_tooltip'] = $this->language->get('help_weight_rules_creation');
- }
- }
- $data['shipping_rules'] = $shippingRules;
- $data['link_shipping_rules'] = $this->createAdminLink(self::ACTION_SHIPPING_RULES);
-
- // adding additional data for displaying to user in list of weight rules
- foreach ($usedCountries as $countryCode) {
- $weightRules[$countryCode]['country_name'] = $this->language->get('country_' . $countryCode);
- $weightRules[$countryCode][self::TEMPLATE_LINK_EDIT] = $this->createAdminLink(self::ACTION_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]);
- }
- $data['weight_rules'] = $weightRules;
-
- $this->setGlobalConfigurationForm($data);
-
- $this->response->setOutput($this->load->view(self::ROUTING_BASE_PATH, $data));
- }
-
- /**
- * Set items of global configuration to template data.
- *
- * @throws Exception
- * @var array $data page template data
- */
- private function setGlobalConfigurationForm(&$data) {
- $data[self::TEMPLATE_LINK_FORM_ACTION] = $this->createAdminLink('');
- $data[self::TEMPLATE_LINK_CANCEL] = $this->createAdminLink('marketplace/extension', ['type' => 'shipping']);
-
- // loads list of secondary stores
- $this->load->model('setting/store');
- $secondaryStores = $this->model_setting_store->getStores();
-
- // loads values for global settings from POST request data or from module configuration
- $configurationItems = [
- 'shipping_zasilkovna_api_key',
- 'shipping_zasilkovna_tax_class_id',
- 'shipping_zasilkovna_weight_max',
- 'shipping_zasilkovna_default_free_shipping_limit',
- 'shipping_zasilkovna_default_shipping_price',
- 'shipping_zasilkovna_status',
- 'shipping_zasilkovna_sort_order',
- 'shipping_zasilkovna_geo_zone_id',
- 'shipping_zasilkovna_order_statuses',
- 'shipping_zasilkovna_cash_on_delivery_methods',
- 'shipping_zasilkovna_eshop_identifier_0' // default store always exists
- ];
-
- // adds form items for e-shop identifiers for secondary stores
- foreach ($secondaryStores as $storeProperties) {
- $configurationItems[] = 'shipping_zasilkovna_eshop_identifier_' . $storeProperties['store_id'];
- }
-
- foreach ($configurationItems as $itemName) {
- if (isset($this->request->post[$itemName])) {
- $data[$itemName] = $this->request->post[$itemName];
- }
- else {
- $data[$itemName] = $this->config->get($itemName);
- }
- }
-
- // loads list of tax classes and geo zones defined in administration
- $this->load->model('localisation/tax_class');
- $data['tax_classes'] = $this->model_localisation_tax_class->getTaxClasses();
- $this->load->model('localisation/geo_zone');
- $data['geo_zones'] = $this->model_localisation_geo_zone->getGeoZones();
-
- // loads list of defined order statuses
- $this->load->model('localisation/order_status');
- $data['eshop_order_statuses'] = $this->model_localisation_order_status->getOrderStatuses();
-
- // loads list of installed payment methods
- $this->load->model(self::ROUTING_BASE_PATH);
- $data['payment_methods'] = $this->model_extension_shipping_zasilkovna->getInstalledPaymentMethods();
-
- // creates list of store names for e-shop identifier items
- $data['store_list'] = [];
- $data['store_list'][] = [
- 'id' => 0,
- 'name' => $this->config->get('config_name'),
- 'identifier' => $data['shipping_zasilkovna_eshop_identifier_0']
- ];
- foreach ($secondaryStores as $storeProperies) {
- $data['store_list'][] = [
- 'id' => $storeProperties['store_id'],
- 'name' => $storeProperties['name'],
- 'identifier' => $data['shipping_zasilkovna_eshop_identifier_' . $storeProperties['store_id']]
- ];
- }
- }
-
- /**
- * Handler for show weight rules for given country.
- * @throws Exception
- */
- public function weight_rules() { // method name with underscore is required for correct routing
- $this->checkCountryCode();
- $countryCode = $this->request->get[self::PARAM_COUNTRY];
-
- $data = $this->initPageData(self::ACTION_WEIGHT_RULES, self::TEXT_TITLE_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]);
-
- $this->load->model(self::ROUTING_WEIGHT_RULES);
- $data[self::TEMPLATE_LINK_ADD] = $this->createAdminLink(self::ACTION_WEIGHT_RULES_ADD, [self::PARAM_COUNTRY => $countryCode]);
- $data[self::TEMPLATE_LINK_DELETE] = $this->createAdminLink(self::ACTION_WEIGHT_RULES_DELETE, [self::PARAM_COUNTRY => $countryCode]);
- $data[self::TEMPLATE_LINK_BACK] = $this->createAdminLink('');
- $data['text_country_name'] = $this->language->get('country_' . $countryCode);
-
- $weightRules = $this->model_extension_shipping_zasilkovna_weight_rules->getRulesForCountry($countryCode);
- foreach ($weightRules as $rule) {
- $data['weight_rules'][] = [
- 'rule_id' => $rule['rule_id'],
- 'min_weight' => $rule['min_weight'],
- 'max_weight' => $rule['max_weight'],
- 'price' => $rule['price'],
- self::TEMPLATE_LINK_EDIT => $this->createAdminLink(self::ACTION_WEIGHT_RULES_EDIT,
- [self::PARAM_COUNTRY => $countryCode, self::PARAM_RULE_ID => $rule['rule_id']])
- ];
- }
-
- $this->response->setOutput($this->load->view('extension/shipping/zasilkovna_weight_rules', $data));
- }
-
- /**
- * Handler for creation of new weight rule.
- * @throws Exception
- */
- public function weight_rules_add() { // method name with underscore is required for correct routing
- $this->checkCountryCode();
- $countryCode = $this->request->get[self::PARAM_COUNTRY];
-
- $data = $this->initPageData(self::ACTION_WEIGHT_RULES, self::TEXT_TITLE_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]);
-
- // check if http method is POST (save of data from form)
- if ($this->request->server['REQUEST_METHOD'] === 'POST') {
- $this->load->model(self::ROUTING_WEIGHT_RULES);
- $errorMessage = $this->model_extension_shipping_zasilkovna_weight_rules->addRule($this->request->post, $countryCode);
- if (empty($errorMessage)) {
- $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
- $this->response->redirect($this->createAdminLink(self::ACTION_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]));
- }
- else {
- $data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get($errorMessage);
- }
- }
-
- $this->setWeightRuleFormContent($data, $countryCode);
- }
-
- /**
- * Handler for edit of existing weight rule.
- * @throws Exception
- */
- public function weight_rules_edit() { // method name with underscore is required for correct routing
- $this->checkCountryCode();
-
- if (!isset($this->request->get['rule_id'])) {
- $this->load->language(self::ROUTING_BASE_PATH);
- $this->session->data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get('error_missing_param');
- $this->response->redirect($this->createAdminLink(''));
- }
-
- $countryCode = $this->request->get[self::PARAM_COUNTRY];
- $ruleId = $this->request->get[self::PARAM_RULE_ID];
-
- $data = $this->initPageData(self::ACTION_WEIGHT_RULES, self::TEXT_TITLE_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]);
-
- // check if http method is POST (save of data from form)
- if ($this->request->server['REQUEST_METHOD'] === 'POST') {
- $this->load->model(self::ROUTING_WEIGHT_RULES);
- $errorMessage = $this->model_extension_shipping_zasilkovna_weight_rules->editRule($ruleId, $this->request->post, $countryCode);
- if (empty($errorMessage)) {
- $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
- $this->response->redirect($this->createAdminLink(self::ACTION_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]));
- }
- else {
- $data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get($errorMessage);
- }
- }
-
- $this->setWeightRuleFormContent($data, $countryCode, $ruleId);
- }
-
- /**
- * Handler for delete of selected weight rules.
- *
- * @throws Exception
- */
- public function weight_rules_delete() { // method name with underscore is required for correct routing
- $this->checkCountryCode();
- $this->load->language(self::ROUTING_BASE_PATH);
- $countryCode = $this->request->get[self::PARAM_COUNTRY];
-
- if (!empty($this->request->post['selected'])) {
- $this->load->model(self::ROUTING_WEIGHT_RULES);
- $this->model_extension_shipping_zasilkovna_weight_rules->deleteRules($this->request->post['selected']);
- }
-
- $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
- $this->response->redirect($this->createAdminLink(self::ACTION_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]));
- }
-
- /**
- * Set of form content for weight rule editor. Common part for "add" and "edit" action.
- *
- * @throws Exception
- *
- * @var array $data data for page template
- * @var string $countryCode iso country code of target country
- * @var int $ruleId internal ID of processed rule (0 for adding a new rule)
- */
- private function setWeightRuleFormContent(array $data, $countryCode, $ruleId = 0) {
- $isEdit = ($ruleId !== 0);
-
- if ($this->request->server['REQUEST_METHOD'] === 'POST') { // load data from POST request
- $postData = $this->request->post;
- $data['min_weight'] = $postData['min_weight'];
- $data['max_weight'] = $postData['max_weight'];
- $data['price'] = $postData['price'];
- }
- else if ($isEdit) { // load data from DB
- $this->load->model(self::ROUTING_WEIGHT_RULES);
- $rowData = $this->model_extension_shipping_zasilkovna_weight_rules->getRule($ruleId);
- if (!empty($rowData)) {
- $data['min_weight'] = $rowData['min_weight'];
- $data['max_weight'] = $rowData['max_weight'];
- $data['price'] = $rowData['price'];
- }
- }
-
- $data['text_form_title'] = $this->language->get($isEdit ? 'text_edit_weight_rule' : 'text_new_weight_rule');
- if ($isEdit) {
- $data[self::TEMPLATE_LINK_FORM_ACTION] = $this->createAdminLink(self::ACTION_WEIGHT_RULES_EDIT,
- [self::PARAM_COUNTRY => $countryCode, self::PARAM_RULE_ID => $ruleId]);
- }
- else {
- $data[self::TEMPLATE_LINK_FORM_ACTION] = $this->createAdminLink(self::ACTION_WEIGHT_RULES_ADD, [self::PARAM_COUNTRY => $countryCode]);
- }
- $data[self::TEMPLATE_LINK_CANCEL] = $this->createAdminLink(self::ACTION_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]);
-
- $this->response->setOutput($this->load->view('extension/shipping/zasilkovna_weight_rules_form', $data));
- }
-
- /**
- * Handler for list of shipping rules for given country.
- * @throws Exception
- */
- public function shipping_rules() { // method name with underscore is required for correct routing
- $data = $this->initPageData(self::ACTION_WEIGHT_RULES, self::TEXT_TITLE_SHIPPING_RULES);
-
- $this->load->model(self::ROUTING_SHIPPING_RULES);
- $data[self::TEMPLATE_LINK_ADD] = $this->createAdminLink(self::ACTION_SHIPPING_RULES_ADD);
- $data[self::TEMPLATE_LINK_DELETE] = $this->createAdminLink(self::ACTION_SHIPPING_RULES_DELETE);
- $data[self::TEMPLATE_LINK_BACK] = $this->createAdminLink('');
-
- $shippingRules = $this->model_extension_shipping_zasilkovna_shipping_rules->getAllRules();
- foreach ($shippingRules as $rule) {
- $data['shipping_rules'][] = [
- 'rule_id' => $rule['rule_id'],
- 'target_country_name' => $this->language->get('country_' . $rule['target_country']),
- 'default_price' => (empty($rule['default_price']) ? $this->language->get('entry_sr_not_set') : $rule['default_price']) ,
- 'free_over_limit' => (empty($rule['free_over_limit']) ? $this->language->get('entry_sr_not_set') : $rule['free_over_limit']),
- 'is_enabled' => $rule['is_enabled'],
- self::TEMPLATE_LINK_EDIT => $this->createAdminLink(self::ACTION_SHIPPING_RULES_EDIT,
- [self::PARAM_RULE_ID => $rule['rule_id']])
- ];
- }
-
- $this->response->setOutput($this->load->view('extension/shipping/zasilkovna_shipping_rules_list', $data));
- }
-
- /**
- * Handler for creation of new shipping rule.
- * @throws Exception
- */
- public function shipping_rules_add() { // method name with underscore is required for correct routing
- $data = $this->initPageData(self::ACTION_SHIPPING_RULES, self::TEXT_TITLE_SHIPPING_RULES);
-
- // check if http method is POST (save of data from form)
- if ($this->request->server['REQUEST_METHOD'] === 'POST') {
- $this->load->model(self::ROUTING_SHIPPING_RULES);
- $errorMessage = $this->model_extension_shipping_zasilkovna_shipping_rules->checkRuleData($this->request->post);
- if (empty($errorMessage)) {
- $this->model_extension_shipping_zasilkovna_shipping_rules->addRule($this->request->post);
- $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
- $this->response->redirect($this->createAdminLink(self::ACTION_SHIPPING_RULES));
- }
- else {
- $data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get($errorMessage);
- }
- }
-
- $this->setShippingRuleFormContent($data);
- }
-
- /**
- * Handler for edit of existing shipping rule.
- * @throws Exception
- */
- public function shipping_rules_edit() { // method name with underscore is required for correct routing
- if (!isset($this->request->get[self::PARAM_RULE_ID])) {
- $this->load->language(self::ROUTING_BASE_PATH);
- $this->session->data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get('error_missing_param');
- $this->response->redirect($this->createAdminLink(''));
- }
-
- $ruleId = $this->request->get[self::PARAM_RULE_ID];
- $data = $this->initPageData(self::ACTION_SHIPPING_RULES, self::TEXT_TITLE_SHIPPING_RULES);
-
- // check if http method is POST (save of data from form)
- if ($this->request->server['REQUEST_METHOD'] === 'POST') {
- $this->load->model(self::ROUTING_SHIPPING_RULES);
- $errorMessage = $this->model_extension_shipping_zasilkovna_shipping_rules->editRule($ruleId, $this->request->post);
- if (empty($errorMessage)) {
- $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
- $this->response->redirect($this->createAdminLink(self::ACTION_SHIPPING_RULES));
- }
- else {
- $data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get($errorMessage);
- }
- }
-
- $this->setShippingRuleFormContent($data, $ruleId);
- }
-
- /**
- * Handler for delete of selected shipping rules.
- *
- * @throws Exception
- */
- public function shipping_rules_delete() { // method name with underscore is required for correct routing
- $this->load->language(self::ROUTING_BASE_PATH);
-
- if (!empty($this->request->post['selected'])) {
- $this->load->model(self::ROUTING_SHIPPING_RULES);
- $this->model_extension_shipping_zasilkovna_shipping_rules->deleteRules($this->request->post['selected']);
- }
-
- $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
- $this->response->redirect($this->createAdminLink(self::ACTION_SHIPPING_RULES));
- }
-
- /**
- * Set of form content for shipping rule editor. Common part for "add" and "edit" action.
- *
- * @throws Exception
- *
- * @var array $data data for page template
- * @var int $ruleId internal ID of processed rule (0 for adding a new rule)
- */
- private function setShippingRuleFormContent(array $data, $ruleId = 0) {
- $isEdit = ($ruleId !== 0);
-
- if ($this->request->server['REQUEST_METHOD'] === 'POST') { // load data from POST request
- $postData = $this->request->post;
- $data['target_country'] = $postData['target_country'];
- $data['default_price'] = $postData['default_price'];
- $data['free_over_limit'] = $postData['free_over_limit'];
- $data['is_enabled'] = $postData['is_enabled'];
- }
- else if ($isEdit) { // load data from DB
- $this->load->model(self::ROUTING_SHIPPING_RULES);
- $rowData = $this->model_extension_shipping_zasilkovna_shipping_rules->getRule($ruleId);
- if (!empty($rowData)) {
- $data['target_country'] = $rowData['target_country'];
- $data['default_price'] = $rowData['default_price'];
- $data['free_over_limit'] = $rowData['free_over_limit'];
- $data['is_enabled'] = $rowData['is_enabled'];
- }
- }
-
- // creation of localized list of allowed countries
- $countryList = [];
- foreach (self::ALLOWED_COUNTRIES as $countryCode) {
- $countryList[] = [
- 'code' => $countryCode,
- 'name' => $this->language->get('country_' . $countryCode)
- ];
- }
- $data['countries'] = $countryList;
-
- // set description text and links for form
- $data['text_form_title'] = $this->language->get($isEdit ? 'text_edit_shipping_rule' : 'text_new_shipping_rule');
- if ($isEdit) {
- $data[self::TEMPLATE_LINK_FORM_ACTION] = $this->createAdminLink(self::ACTION_SHIPPING_RULES_EDIT,
- [self::PARAM_RULE_ID => $ruleId]);
- }
- else {
- $data[self::TEMPLATE_LINK_FORM_ACTION] = $this->createAdminLink(self::ACTION_SHIPPING_RULES_ADD);
- }
- $data[self::TEMPLATE_LINK_CANCEL] = $this->createAdminLink(self::ACTION_SHIPPING_RULES);
-
- $this->response->setOutput($this->load->view('extension/shipping/zasilkovna_shipping_rules_form', $data));
- }
-
- /**
- * Extension of menu in administration. Adds new item with list of Zasilkovna orders to menu "Sales".
- * This method is called by "before" event on admin/view/common/column_left/before.
- *
- * @param string $route routing path of page
- * @param array $data template parameters
- * @param StdClass $template instance of page template
- * @throws Exception
- */
- public function adminMenuExtension(&$route, &$data, &$template) {
- if (!$this->user->hasPermission('access', self::ROUTING_BASE_PATH)) {
- return;
- }
-
- foreach ($data['menus'] as &$menu) {
- if ($menu['id'] != 'menu-sale') {
- continue;
- }
-
- // load translations for Zasilkovna to separate language context
- $this->load->language(self::ROUTING_BASE_PATH, 'zasilkovna');
-
- // creation of new menu item for Zasilkovna
- $newMenuItem = [
- 'name' => $this->language->get('zasilkovna')->get('text_menu_item'),
- 'href' => $this->createAdminLink(self::ACTION_ORDERS)
- ];
- array_push($menu['children'], $newMenuItem);
- }
- }
-
- /**
- * Handler for list of "Zasilkovna" orders.
- *
- * @throws Exception
- */
- public function orders() {
- $this->load->language(self::ROUTING_BASE_PATH);
- $this->load->model(self::ROUTING_ORDERS);
-
- // initialization of page data including setup of list parameters (filters, sorting, paging)
- $data = $this->initPageData(self::ACTION_ORDERS, self::TEXT_TTILE_ORDERS);
- $paramData = $this->model_extension_shipping_zasilkovna_orders->getUrlParameters();
-
- // load list of order statuses and creation of array for translate ID to status description
- $this->load->model('localisation/order_status');
- $orderStatusList = $this->model_localisation_order_status->getOrderStatuses();
- $data['order_statuses'] = $orderStatusList;
- $orderStatusDescriptions = [];
- foreach ($orderStatusList as $orderStatusItem) {
- $orderStatusDescriptions[$orderStatusItem['order_status_id']] = $orderStatusItem['name'];
- }
-
- // load list of payment methods considered as "cash on delivery"
- $codPaymentMethods = (array)$this->config->get('shipping_zasilkovna_cash_on_delivery_methods');
-
- // load count of orders and list of orders for current page
- $orderCount = $this->model_extension_shipping_zasilkovna_orders->getOrdersCount($paramData['filterData']);
- $dbOrderList = $this->model_extension_shipping_zasilkovna_orders->getOrders($paramData);
-
- // format list of orders for template
- foreach ($dbOrderList as $order) {
- $data['orders'][] = [
- 'order_id' => $order['order_id'],
- 'customer' => $order['customer'],
- 'order_status' => $orderStatusDescriptions[$order['order_status_id']],
- 'total' => $this->currency->format($order['total'], $order['currency_code'], $order['currency_value']),
- 'is_cod' => in_array($order['payment_code'], $codPaymentMethods),
- 'date_added' => date($this->language->get('date_format_short'), strtotime($order['date_added'])),
- 'branch_id' => $order['branch_id'],
- 'branch_name' => $order['branch_name'],
- 'exported' => !empty($order['exported']) ? date($this->language->get('date_format_short'), strtotime($order['exported'])) : ''
- ];
- }
-
- // to keep selected rows as selected
- if (isset($this->request->post['selected'])) {
- $data['selected'] = (array)$this->request->post['selected'];
- } else {
- $data['selected'] = array();
- }
-
- // creation set of links for CSV export actions
- $csvExportUrlParams = $paramData['filterData'];
- $csvExportUrlParams['sort'] = $paramData['sort'];
- $csvExportUrlParams['order'] = $paramData['order'];
- $data[self::TEMPLATE_LINK_EXPORT_SELECTED] = $this->createAdminLink(self::ACTION_ORDERS_EXPORT,
- array_merge($csvExportUrlParams, ['scope' => 'selected']));
- $data[self::TEMPLATE_LINK_EXPORT_ALL] = $this->createAdminLink(self::ACTION_ORDERS_EXPORT,
- array_merge($csvExportUrlParams, ['scope' => 'all']));
-
- // creation set of links to change grid sorting
- $sortingUrlParams = [];
- foreach ($paramData['filterData'] as $paramName => $paramValue) {
- if (!empty($paramValue)) {
- $sortingUrlParams[$paramName] = $paramValue;
- }
- }
- $sortingUrlParams['page'] = $paramData['page'];
- $sortingUrlParams['order'] = ($paramData['order'] == 'ASC') ? 'DESC' : 'ASC';
-
- $data['link_sorting_order_id'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'o.order_id']));
- $data['link_sorting_customer'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'customer']));
- $data['link_sorting_order_status_id'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'order_status_id']));
- $data['link_sorting_order_total'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'o.total']));
- $data['link_sorting_order_date'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'date_added']));
- $data['link_sorting_branch_name'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'oz.branch_name']));
- $data['link_sorting_exported'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'exported']));
-
- // current sorting properties
- $data['sort'] = $paramData['sort'];
- $data['order'] = $paramData['order'];
-
- // preparation of paging (switch between pages)
- $pagingUrlParameters = [];
- foreach ($paramData['filterData'] as $paramName => $paramValue) {
- if (!empty($paramValue)) {
- $pagingUrlParameters[$paramName] = $paramValue;
- }
- }
- $pagingUrlParameters['sort'] = $paramData['sort'];
- $pagingUrlParameters['order'] = $paramData['order'];
- $pagingUrlParameters['page'] = '{page}';
-
- $pageNumber = $paramData['page'];
- $pagination = new Pagination();
- $pagination->total = $orderCount;
- $pagination->page = $pageNumber;
- $pagination->limit = $this->config->get('config_limit_admin');
- $pagination->url = $this->createAdminLink(self::ACTION_ORDERS, $pagingUrlParameters);
- $data['pagination'] = $pagination->render();
-
- // preparation of paging (current page info)
- // string template: Showing %d to %d of %d (%d Pages)
- $data['results'] = sprintf($this->language->get('text_pagination'),
- ($orderCount) ? (($pageNumber - 1) * $this->config->get('config_limit_admin')) + 1 : 0,
- ((($pageNumber - 1) * $this->config->get('config_limit_admin')) > ($orderCount - $this->config->get('config_limit_admin'))) ? $orderCount : ((($pageNumber - 1) * $this->config->get('config_limit_admin')) + $this->config->get('config_limit_admin')),
- $orderCount,
- ceil($orderCount / $this->config->get('config_limit_admin')));
-
- // creation set of variables for default value of filters
- foreach ($paramData['filterData'] as $paramName => $paramValue) {
- $data[$paramName] = $paramValue;
- }
-
- // items of selectbox for type of export
- $data['export_types'] = [
- [ 'value' => 'not_exported', 'name' => $this->language->get('entry_ol_not_exported')],
- [ 'value' => 'exported', 'name' => $this->language->get('entry_ol_exported')],
- [ 'value' => 'all', 'name' => $this->language->get('entry_ol_all_records')]
- ];
-
- // add user token parameter for functionality of JS request (e.g. customer name autocomplete)
- $data['user_token'] = $this->session->data['user_token'];
-
- $this->response->setOutput($this->load->view('extension/shipping/zasilkovna_orders', $data));
- }
-
- /**
- * Handler for export orders to CSV (all or selected orders).
- *
- * @throws Exception
- */
- public function orders_export() { // method name with underscore is required for correct routing
- $this->load->language(self::ROUTING_BASE_PATH);
- $this->load->model(self::ROUTING_ORDERS);
-
- $paramData = $this->model_extension_shipping_zasilkovna_orders->getUrlParameters();
- $exportScope = $this->request->get['scope'];
- // all parameters except list of "row" checkboxes are part of form action (get parameters)
- $orderIdList = (isset($this->request->post['selected'])) ? $this->request->post['selected']: [];
-
- $this->load->model('setting/store');
- $csvRawData = $this->model_extension_shipping_zasilkovna_orders->getCsvExportData($paramData, $exportScope, $orderIdList);
-
- // open stdout as file and put content to it using native function for writing data in CSV format
- $fileHandle = fopen('php://output', 'wb');
- ob_start();
- // first two lines are fixed header of file
- fputcsv($fileHandle, ['version 5']);
- fputcsv($fileHandle, []);
-
- foreach ($csvRawData as $rawRecord) {
- fputcsv($fileHandle, $rawRecord);
- }
- $csvFileContent = ob_get_contents();
- ob_end_clean();
-
- // set http headers for "force download" and file type
- $this->response->addHeader('Content-Type: text/csv');
- $fileName = 'orders-' . date('Y-m-d-H-i-s') . '.csv';
- $this->response->addHeader('Content-Disposition: attachment; filename="' . $fileName . '"');
-
- // send content of csv file as output
- $this->response->setOutput($csvFileContent);
- }
-
- /**
- * Check if user has permission to change module settings.
- *
- * @return bool TRUE = success, FALSE = error
- */
- private function checkPermissions() {
- if (!$this->user->hasPermission('modify', self::ROUTING_BASE_PATH)) {
- $data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get('error_permission');
- return false;
- }
-
- return true;
- }
-
- /**
- * Check presence and content of url parameter for country.
- * If parameter is missing or invalid, redirect to main setting page is performed.
- *
- * @return void
- */
- private function checkCountryCode() {
- // check if code of target country is part of url
- if (empty($this->request->get[self::PARAM_COUNTRY])) {
- $this->load->language(self::ROUTING_BASE_PATH);
- $this->session->data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get('error_missing_param');
- $this->response->redirect($this->createAdminLink(''));
- }
-
- // check if specified country is allowed
- if (!in_array($this->request->get[self::PARAM_COUNTRY], self::ALLOWED_COUNTRIES)) {
- $this->load->language(self::ROUTING_BASE_PATH);
- $this->session->data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get('error_invalid_country');
- $this->response->redirect($this->createAdminLink(''));
- }
- }
-
- /**
- * Method for page initialization. Returns customized base content of template data.
- *
- * @param string $actionName internal name of module action
- * @param string $titleId language independent identifier of page title
- * @param array $urlParameters additional parameters to url
- * @return array initial version of template data
- */
- private function initPageData($actionName, $titleId, $urlParameters = []) {
- // load language file for module
- $this->load->language(self::ROUTING_BASE_PATH);
- // set page (document) title
- $this->document->setTitle($this->language->get($titleId));
-
- // creation of customized common part of template data
- $data = [
- // common parts of page (header, left column with system menu, footer)
- 'header' => $this->load->controller('common/header'),
- 'column_left' => $this->load->controller('common/column_left'),
- 'footer' => $this->load->controller('common/footer'),
- 'breadcrumbs' => [
- [
- 'text' => $this->language->get('text_home'),
- 'href' => $this->createAdminLink('common/dashboard')
- ],
- [
- 'text' => $this->language->get('text_shipping'),
- 'href' => $this->createAdminLink('marketplace/extension', ['type' => 'shipping'])
- ],
- [
- 'text' => $this->language->get(self::TEXT_TITLE_MAIN),
- 'href' => $this->createAdminLink('')
- ]
- ]
- ];
-
- // last part of "breadcrumbs" is added only for nonempty action name (pages of module)
- if (!empty($actionName)) {
- $data['breadcrumbs'][] = [
- 'text' => $this->language->get($titleId),
- 'href' => $this->createAdminLink($actionName, $urlParameters)
- ];
- }
-
- // check if some error/success message is stored in session and set it as template parameter
- if (isset($this->session->data[self::TEMPLATE_MESSAGE_SUCCESS])) {
- $data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS];
-
- unset($this->session->data[self::TEMPLATE_MESSAGE_SUCCESS]);
- }
- if (isset($this->session->data[self::TEMPLATE_MESSAGE_ERROR])) {
- $data[self::TEMPLATE_MESSAGE_ERROR] = $this->session->data[self::TEMPLATE_MESSAGE_ERROR];
-
- unset($this->session->data[self::TEMPLATE_MESSAGE_ERROR]);
- }
-
- return $data;
- }
-
- /**
- * Creates link to given action in administration including user token.
- *
- * @param string $actionName internal name of module action
- * @param array $urlParameters additional parameters to url
- * @return string
- */
- private function createAdminLink($actionName, $urlParameters = [])
- {
- // empty action name => main page of module
- if ('' == $actionName) {
- $actionName = self::ROUTING_BASE_PATH;
- }
-
- // action name without slash (/) => action of module
- if (strpos($actionName, '/') === false) {
- $actionName = self::ROUTING_BASE_PATH . '/' . $actionName;
- }
-
- // otherwise action name is absolute routing path => no change in action name
- // user token must be part of any administration link
- $urlParameters['user_token'] = $this->session->data['user_token'];
-
- return $this->url->link($actionName, $urlParameters, true);
- }
-
-}
+load->model(self::ROUTING_BASE_PATH);
+ $this->model_extension_shipping_zasilkovna->createTablesAndEvents();
+
+ // prefill default configuration items
+ $defaultConfig = [
+ 'shipping_zasilkovna_version' => self::VERSION,
+ 'shipping_zasilkovna_weight_max' => '5',
+ 'shipping_zasilkovna_geo_zone_id' => '',
+ 'shipping_zasilkovna_order_statuses' => [],
+ 'shipping_zasilkovna_cash_on_delivery_methods' => []
+ ];
+
+ $this->load->model('setting/setting');
+ $this->model_setting_setting->editSetting('shipping_zasilkovna', $defaultConfig);
+ }
+
+ /**
+ * @return array
+ */
+ private function getSettings()
+ {
+ $this->load->model('setting/setting');
+ return $this->model_setting_setting->getSetting('shipping_zasilkovna');
+ }
+
+ /**
+ * @return string|null
+ */
+ private function getSchemaVersion()
+ {
+ $this->load->model('setting/setting');
+ $existingSettings = $this->getSettings();
+ if ($existingSettings && $this->isInstalled()) {
+ if (!empty($existingSettings['shipping_zasilkovna_version'])) {
+ return $existingSettings['shipping_zasilkovna_version'];
+ }
+
+ return '2.0.3';
+ }
+
+ return null;
+ }
+
+ /** Does database version differ from code version? Downgrades not supported.
+ * @return bool
+ */
+ private function isVersionMismatch()
+ {
+ $version = $this->getSchemaVersion();
+ if ($version && version_compare($version, self::VERSION) < 0) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /** Returns name of extension as its known to OpenCart
+ * @return string
+ */
+ private function getExtensionName()
+ {
+ return basename(__FILE__, '.php');
+ }
+
+ /**
+ * @return bool
+ */
+ private function isInstalled()
+ {
+ $this->load->model('setting/extension');
+ $installed = $this->model_setting_extension->getInstalled('shipping');
+
+ $extensionName = $this->getExtensionName();
+ foreach ($installed as $installedExtensionName) {
+ if ($installedExtensionName === $extensionName) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Entry point (main method) for plugin uninstalling.
+ *
+ * @throws Exception
+ */
+ public function uninstall() {
+ // framework deletes shipping_zasilkovna settings before calling extension uninstall method
+ $this->load->model(self::ROUTING_BASE_PATH);
+ $this->model_extension_shipping_zasilkovna->deleteTablesAndEvents();
+ }
+
+ /**
+ * Plugin version upgrade. The need for an upgrade is checked each time the settings page is displayed.
+ */
+ public function upgrade()
+ {
+ $this->load->model(self::ROUTING_BASE_PATH);
+ $this->load->language('extension/shipping/zasilkovna');
+
+ try {
+ $this->model_extension_shipping_zasilkovna->upgradeSchema($this->getSchemaVersion());
+ } catch (ZasilkovnaUpgradeException $exception) {
+ $this->session->data['error_warning_multirow'] = [
+ $this->language->get('extension_upgrade_failed'),
+ $exception->getMessage(),
+ $this->language->get('please_see_log'),
+ $this->language->get('extension_may_not_work'),
+ $this->language->get('error_needs_to_be_resolved'),
+ ];
+ return;
+ }
+
+ $this->model_extension_shipping_zasilkovna->installEvents();
+
+ $this->load->model('setting/setting');
+ $settings = $this->model_setting_setting->getSetting('shipping_zasilkovna');
+ $settings['shipping_zasilkovna_version'] = self::VERSION;
+ $this->model_setting_setting->editSetting('shipping_zasilkovna', $settings);
+
+ $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] =
+ sprintf($this->language->get('extension_upgraded'), self::VERSION);
+ }
+
+ /**
+ * @return bool
+ */
+ private function isUpgradedNeeded()
+ {
+ return $this->isInstalled() && $this->isVersionMismatch();
+ }
+
+ /**
+ * Handler for main action of extension modul for Zasilkovna (main settings page).
+ *
+ * @throws Exception
+ */
+ public function index() {
+ if ($this->isUpgradedNeeded()) {
+ $this->upgrade();
+ }
+
+ // save new values from POST request data to module settings
+ if (($this->request->server['REQUEST_METHOD'] == 'POST') && ($this->checkPermissions())) {
+ $this->load->language(self::ROUTING_BASE_PATH);
+ $existingSettings = $this->getSettings();
+ $this->model_setting_setting->editSetting('shipping_zasilkovna', $this->request->post + $existingSettings);
+ $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
+ $this->response->redirect($this->createAdminLink('marketplace/extension', ['type' => 'shipping']));
+ }
+
+ // full initialization of page
+ $data = $this->initPageData('', self::TEXT_TITLE_MAIN);
+
+ // load data for list of weight rules
+ $this->load->model(self::ROUTING_WEIGHT_RULES);
+ $weightRules = $this->model_extension_shipping_zasilkovna_weight_rules->getAllRules();
+ $usedCountries = array_keys($weightRules);
+
+ // load data for list of shipping rules
+ $this->load->model(self::ROUTING_SHIPPING_RULES);
+ $shippingRules = $this->model_extension_shipping_zasilkovna_shipping_rules->getAllRules();
+
+ $this->load->model(self::ROUTING_COUNTRIES);
+ // adding additional data for list of shipping rules
+ foreach ($shippingRules as $ruleId => $ruleContent) {
+ // name of country
+ $shippingRules[$ruleId]['country_name'] = $this->model_extension_shipping_zasilkovna_countries->getCountryNameByIsoCode2($ruleContent['target_country']);
+
+ // print message "not set" if default price or free shipping limit is not set
+ if (empty($ruleContent['default_price'])) {
+ $shippingRules[$ruleId]['default_price'] = $this->language->get('entry_sr_not_set');
+ }
+ if (empty($ruleContent['free_over_limit'])) {
+ $shippingRules[$ruleId]['free_over_limit'] = $this->language->get('entry_sr_not_set');
+ }
+ // link to shipping rule editor
+ $shippingRules[$ruleId][self::TEMPLATE_LINK_EDIT] = $this->createAdminLink(self::ACTION_SHIPPING_RULES_EDIT,
+ [self::PARAM_RULE_ID => $ruleContent['rule_id']]);
+ // link to list of weight rules
+ $shippingRules[$ruleId]['link_weight_rules'] = $this->createAdminLink(self::ACTION_WEIGHT_RULES,
+ [self::PARAM_COUNTRY => $ruleContent['target_country']]);
+
+ if (in_array($ruleContent['target_country'], $usedCountries)) {
+ $shippingRules[$ruleId]['weight_rules_description'] = $this->language->get('text_weight_rules_defined');
+ $shippingRules[$ruleId]['weight_rules_tooltip'] = $this->language->get('help_weight_rules_change');
+ }
+ else {
+ $shippingRules[$ruleId]['weight_rules_description'] = $this->language->get('text_weight_rules_missing');
+ $shippingRules[$ruleId]['weight_rules_tooltip'] = $this->language->get('help_weight_rules_creation');
+ }
+ }
+ $data['shipping_rules'] = $shippingRules;
+ $data['link_shipping_rules'] = $this->createAdminLink(self::ACTION_SHIPPING_RULES);
+
+ // adding additional data for displaying to user in list of weight rules
+ foreach ($usedCountries as $countryCode) {
+ $weightRules[$countryCode]['country_name'] = $this->model_extension_shipping_zasilkovna_countries->getCountryNameByIsoCode2($countryCode);
+ $weightRules[$countryCode][self::TEMPLATE_LINK_EDIT] = $this->createAdminLink(self::ACTION_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]);
+ }
+ $data['weight_rules'] = $weightRules;
+
+ $this->setGlobalConfigurationForm($data);
+
+ $this->response->setOutput($this->load->view(self::ROUTING_BASE_PATH, $data));
+ }
+
+ /**
+ * Set items of global configuration to template data.
+ *
+ * @throws Exception
+ * @var array $data page template data
+ */
+ private function setGlobalConfigurationForm(&$data) {
+ $data[self::TEMPLATE_LINK_FORM_ACTION] = $this->createAdminLink('');
+ $data[self::TEMPLATE_LINK_CANCEL] = $this->createAdminLink('marketplace/extension', ['type' => 'shipping']);
+
+ // loads list of secondary stores
+ $this->load->model('setting/store');
+ $secondaryStores = $this->model_setting_store->getStores();
+
+ // loads values for global settings from POST request data or from module configuration
+ $configurationItems = [
+ 'shipping_zasilkovna_api_key',
+ 'shipping_zasilkovna_tax_class_id',
+ 'shipping_zasilkovna_weight_max',
+ 'shipping_zasilkovna_default_free_shipping_limit',
+ 'shipping_zasilkovna_default_shipping_price',
+ 'shipping_zasilkovna_status',
+ 'shipping_zasilkovna_sort_order',
+ 'shipping_zasilkovna_geo_zone_id',
+ 'shipping_zasilkovna_order_statuses',
+ 'shipping_zasilkovna_cash_on_delivery_methods',
+ 'shipping_zasilkovna_eshop_identifier_0' // default store always exists
+ ];
+
+ // adds form items for e-shop identifiers for secondary stores
+ foreach ($secondaryStores as $storeProperties) {
+ $configurationItems[] = 'shipping_zasilkovna_eshop_identifier_' . $storeProperties['store_id'];
+ }
+
+ foreach ($configurationItems as $itemName) {
+ if (isset($this->request->post[$itemName])) {
+ $data[$itemName] = $this->request->post[$itemName];
+ }
+ else {
+ $data[$itemName] = $this->config->get($itemName);
+ }
+ }
+
+ // loads list of tax classes and geo zones defined in administration
+ $this->load->model('localisation/tax_class');
+ $data['tax_classes'] = $this->model_localisation_tax_class->getTaxClasses();
+ $this->load->model('localisation/geo_zone');
+ $data['geo_zones'] = $this->model_localisation_geo_zone->getGeoZones();
+
+ // loads list of defined order statuses
+ $this->load->model('localisation/order_status');
+ $data['eshop_order_statuses'] = $this->model_localisation_order_status->getOrderStatuses();
+
+ // loads list of installed payment methods
+ $this->load->model(self::ROUTING_BASE_PATH);
+ $data['payment_methods'] = $this->model_extension_shipping_zasilkovna->getInstalledPaymentMethods();
+ $data['extension_version'] = self::VERSION;
+
+ // creates list of store names for e-shop identifier items
+ $data['store_list'] = [];
+ $data['store_list'][] = [
+ 'id' => 0,
+ 'name' => $this->config->get('config_name'),
+ 'identifier' => $data['shipping_zasilkovna_eshop_identifier_0']
+ ];
+ foreach ($secondaryStores as $storeProperies) {
+ $data['store_list'][] = [
+ 'id' => $storeProperties['store_id'],
+ 'name' => $storeProperties['name'],
+ 'identifier' => $data['shipping_zasilkovna_eshop_identifier_' . $storeProperties['store_id']]
+ ];
+ }
+ }
+
+ /**
+ * Handler for show weight rules for given country.
+ * @throws Exception
+ */
+ public function weight_rules() { // method name with underscore is required for correct routing
+ $this->checkCountryCode();
+ $countryCode = $this->request->get[self::PARAM_COUNTRY];
+
+ $data = $this->initPageData(self::ACTION_WEIGHT_RULES, self::TEXT_TITLE_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]);
+
+ $this->load->model(self::ROUTING_COUNTRIES);
+ $this->load->model(self::ROUTING_WEIGHT_RULES);
+ $data[self::TEMPLATE_LINK_ADD] = $this->createAdminLink(self::ACTION_WEIGHT_RULES_ADD, [self::PARAM_COUNTRY => $countryCode]);
+ $data[self::TEMPLATE_LINK_DELETE] = $this->createAdminLink(self::ACTION_WEIGHT_RULES_DELETE, [self::PARAM_COUNTRY => $countryCode]);
+ $data[self::TEMPLATE_LINK_BACK] = $this->createAdminLink('');
+ $data['text_country_name'] = $this->model_extension_shipping_zasilkovna_countries->getCountryNameByIsoCode2($countryCode);
+
+ $weightRules = $this->model_extension_shipping_zasilkovna_weight_rules->getRulesForCountry($countryCode);
+ foreach ($weightRules as $rule) {
+ $data['weight_rules'][] = [
+ 'rule_id' => $rule['rule_id'],
+ 'min_weight' => $rule['min_weight'],
+ 'max_weight' => $rule['max_weight'],
+ 'price' => $rule['price'],
+ self::TEMPLATE_LINK_EDIT => $this->createAdminLink(self::ACTION_WEIGHT_RULES_EDIT,
+ [self::PARAM_COUNTRY => $countryCode, self::PARAM_RULE_ID => $rule['rule_id']])
+ ];
+ }
+
+ $this->response->setOutput($this->load->view('extension/shipping/zasilkovna_weight_rules', $data));
+ }
+
+ /**
+ * Handler for creation of new weight rule.
+ * @throws Exception
+ */
+ public function weight_rules_add() { // method name with underscore is required for correct routing
+ $this->checkCountryCode();
+ $countryCode = $this->request->get[self::PARAM_COUNTRY];
+
+ $data = $this->initPageData(self::ACTION_WEIGHT_RULES, self::TEXT_TITLE_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]);
+
+ // check if http method is POST (save of data from form)
+ if ($this->request->server['REQUEST_METHOD'] === 'POST') {
+ $this->load->model(self::ROUTING_WEIGHT_RULES);
+ $errorMessage = $this->model_extension_shipping_zasilkovna_weight_rules->addRule($this->request->post, $countryCode);
+ if (empty($errorMessage)) {
+ $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
+ $this->response->redirect($this->createAdminLink(self::ACTION_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]));
+ }
+ else {
+ $data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get($errorMessage);
+ }
+ }
+
+ $this->setWeightRuleFormContent($data, $countryCode);
+ }
+
+ /**
+ * Handler for edit of existing weight rule.
+ * @throws Exception
+ */
+ public function weight_rules_edit() { // method name with underscore is required for correct routing
+ $this->checkCountryCode();
+
+ if (!isset($this->request->get['rule_id'])) {
+ $this->load->language(self::ROUTING_BASE_PATH);
+ $this->session->data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get('error_missing_param');
+ $this->response->redirect($this->createAdminLink(''));
+ }
+
+ $countryCode = $this->request->get[self::PARAM_COUNTRY];
+ $ruleId = $this->request->get[self::PARAM_RULE_ID];
+
+ $data = $this->initPageData(self::ACTION_WEIGHT_RULES, self::TEXT_TITLE_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]);
+
+ // check if http method is POST (save of data from form)
+ if ($this->request->server['REQUEST_METHOD'] === 'POST') {
+ $this->load->model(self::ROUTING_WEIGHT_RULES);
+ $errorMessage = $this->model_extension_shipping_zasilkovna_weight_rules->editRule($ruleId, $this->request->post, $countryCode);
+ if (empty($errorMessage)) {
+ $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
+ $this->response->redirect($this->createAdminLink(self::ACTION_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]));
+ }
+ else {
+ $data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get($errorMessage);
+ }
+ }
+
+ $this->setWeightRuleFormContent($data, $countryCode, $ruleId);
+ }
+
+ /**
+ * Handler for delete of selected weight rules.
+ *
+ * @throws Exception
+ */
+ public function weight_rules_delete() { // method name with underscore is required for correct routing
+ $this->checkCountryCode();
+ $this->load->language(self::ROUTING_BASE_PATH);
+ $countryCode = $this->request->get[self::PARAM_COUNTRY];
+
+ if (!empty($this->request->post['selected'])) {
+ $this->load->model(self::ROUTING_WEIGHT_RULES);
+ $this->model_extension_shipping_zasilkovna_weight_rules->deleteRules($this->request->post['selected']);
+ }
+
+ $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
+ $this->response->redirect($this->createAdminLink(self::ACTION_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]));
+ }
+
+ /**
+ * Set of form content for weight rule editor. Common part for "add" and "edit" action.
+ *
+ * @throws Exception
+ *
+ * @var array $data data for page template
+ * @var string $countryCode iso country code of target country
+ * @var int $ruleId internal ID of processed rule (0 for adding a new rule)
+ */
+ private function setWeightRuleFormContent(array $data, $countryCode, $ruleId = 0) {
+ $isEdit = ($ruleId !== 0);
+
+ if ($this->request->server['REQUEST_METHOD'] === 'POST') { // load data from POST request
+ $postData = $this->request->post;
+ $data['min_weight'] = $postData['min_weight'];
+ $data['max_weight'] = $postData['max_weight'];
+ $data['price'] = $postData['price'];
+ }
+ else if ($isEdit) { // load data from DB
+ $this->load->model(self::ROUTING_WEIGHT_RULES);
+ $rowData = $this->model_extension_shipping_zasilkovna_weight_rules->getRule($ruleId);
+ if (!empty($rowData)) {
+ $data['min_weight'] = $rowData['min_weight'];
+ $data['max_weight'] = $rowData['max_weight'];
+ $data['price'] = $rowData['price'];
+ }
+ }
+
+ $data['text_form_title'] = $this->language->get($isEdit ? 'text_edit_weight_rule' : 'text_new_weight_rule');
+ if ($isEdit) {
+ $data[self::TEMPLATE_LINK_FORM_ACTION] = $this->createAdminLink(self::ACTION_WEIGHT_RULES_EDIT,
+ [self::PARAM_COUNTRY => $countryCode, self::PARAM_RULE_ID => $ruleId]);
+ }
+ else {
+ $data[self::TEMPLATE_LINK_FORM_ACTION] = $this->createAdminLink(self::ACTION_WEIGHT_RULES_ADD, [self::PARAM_COUNTRY => $countryCode]);
+ }
+ $data[self::TEMPLATE_LINK_CANCEL] = $this->createAdminLink(self::ACTION_WEIGHT_RULES, [self::PARAM_COUNTRY => $countryCode]);
+
+ $this->response->setOutput($this->load->view('extension/shipping/zasilkovna_weight_rules_form', $data));
+ }
+
+ /**
+ * Handler for list of shipping rules for given country.
+ * @throws Exception
+ */
+ public function shipping_rules() { // method name with underscore is required for correct routing
+ $data = $this->initPageData(self::ACTION_WEIGHT_RULES, self::TEXT_TITLE_SHIPPING_RULES);
+
+ $this->load->model(self::ROUTING_SHIPPING_RULES);
+ $data[self::TEMPLATE_LINK_ADD] = $this->createAdminLink(self::ACTION_SHIPPING_RULES_ADD);
+ $data[self::TEMPLATE_LINK_DELETE] = $this->createAdminLink(self::ACTION_SHIPPING_RULES_DELETE);
+ $data[self::TEMPLATE_LINK_BACK] = $this->createAdminLink('');
+
+ $shippingRules = $this->model_extension_shipping_zasilkovna_shipping_rules->getAllRules();
+ foreach ($shippingRules as $rule) {
+ $this->load->model(self::ROUTING_COUNTRIES);
+ $data['shipping_rules'][] = [
+ 'rule_id' => $rule['rule_id'],
+ 'target_country_name' => $this->model_extension_shipping_zasilkovna_countries->getCountryNameByIsoCode2($rule['target_country']),
+ 'default_price' => (empty($rule['default_price']) ? $this->language->get('entry_sr_not_set') : $rule['default_price']) ,
+ 'free_over_limit' => (empty($rule['free_over_limit']) ? $this->language->get('entry_sr_not_set') : $rule['free_over_limit']),
+ 'is_enabled' => $rule['is_enabled'],
+ self::TEMPLATE_LINK_EDIT => $this->createAdminLink(self::ACTION_SHIPPING_RULES_EDIT,
+ [self::PARAM_RULE_ID => $rule['rule_id']])
+ ];
+ }
+
+ $this->response->setOutput($this->load->view('extension/shipping/zasilkovna_shipping_rules_list', $data));
+ }
+
+ /**
+ * Handler for creation of new shipping rule.
+ * @throws Exception
+ */
+ public function shipping_rules_add() { // method name with underscore is required for correct routing
+ $data = $this->initPageData(self::ACTION_SHIPPING_RULES, self::TEXT_TITLE_SHIPPING_RULES);
+
+ // check if http method is POST (save of data from form)
+ if ($this->request->server['REQUEST_METHOD'] === 'POST') {
+ $this->load->model(self::ROUTING_SHIPPING_RULES);
+ $errorMessage = $this->model_extension_shipping_zasilkovna_shipping_rules->checkRuleData($this->request->post);
+ if (empty($errorMessage)) {
+ $this->model_extension_shipping_zasilkovna_shipping_rules->addRule($this->request->post);
+ $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
+ $this->response->redirect($this->createAdminLink(self::ACTION_SHIPPING_RULES));
+ }
+ else {
+ $data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get($errorMessage);
+ }
+ }
+
+ $this->setShippingRuleFormContent($data);
+ }
+
+ /**
+ * Handler for edit of existing shipping rule.
+ * @throws Exception
+ */
+ public function shipping_rules_edit() { // method name with underscore is required for correct routing
+ if (!isset($this->request->get[self::PARAM_RULE_ID])) {
+ $this->load->language(self::ROUTING_BASE_PATH);
+ $this->session->data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get('error_missing_param');
+ $this->response->redirect($this->createAdminLink(''));
+ }
+
+ $ruleId = $this->request->get[self::PARAM_RULE_ID];
+ $data = $this->initPageData(self::ACTION_SHIPPING_RULES, self::TEXT_TITLE_SHIPPING_RULES);
+
+ // check if http method is POST (save of data from form)
+ if ($this->request->server['REQUEST_METHOD'] === 'POST') {
+ $this->load->model(self::ROUTING_SHIPPING_RULES);
+ $errorMessage = $this->model_extension_shipping_zasilkovna_shipping_rules->editRule($ruleId, $this->request->post);
+ if (empty($errorMessage)) {
+ $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
+ $this->response->redirect($this->createAdminLink(self::ACTION_SHIPPING_RULES));
+ }
+ else {
+ $data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get($errorMessage);
+ }
+ }
+
+ $this->setShippingRuleFormContent($data, $ruleId);
+ }
+
+ /**
+ * Handler for delete of selected shipping rules.
+ *
+ * @throws Exception
+ */
+ public function shipping_rules_delete() { // method name with underscore is required for correct routing
+ $this->load->language(self::ROUTING_BASE_PATH);
+
+ if (!empty($this->request->post['selected'])) {
+ $this->load->model(self::ROUTING_SHIPPING_RULES);
+ $this->model_extension_shipping_zasilkovna_shipping_rules->deleteRules($this->request->post['selected']);
+ }
+
+ $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->language->get('text_success');
+ $this->response->redirect($this->createAdminLink(self::ACTION_SHIPPING_RULES));
+ }
+
+ /**
+ * Set of form content for shipping rule editor. Common part for "add" and "edit" action.
+ *
+ * @throws Exception
+ *
+ * @var array $data data for page template
+ * @var int $ruleId internal ID of processed rule (0 for adding a new rule)
+ */
+ private function setShippingRuleFormContent(array $data, $ruleId = 0) {
+ $isEdit = ($ruleId !== 0);
+
+ if ($this->request->server['REQUEST_METHOD'] === 'POST') { // load data from POST request
+ $postData = $this->request->post;
+ $data['target_country'] = $postData['target_country'];
+ $data['default_price'] = $postData['default_price'];
+ $data['free_over_limit'] = $postData['free_over_limit'];
+ $data['is_enabled'] = $postData['is_enabled'];
+ }
+ else if ($isEdit) { // load data from DB
+ $this->load->model(self::ROUTING_SHIPPING_RULES);
+ $rowData = $this->model_extension_shipping_zasilkovna_shipping_rules->getRule($ruleId);
+ if (!empty($rowData)) {
+ $data['target_country'] = $rowData['target_country'];
+ $data['default_price'] = $rowData['default_price'];
+ $data['free_over_limit'] = $rowData['free_over_limit'];
+ $data['is_enabled'] = $rowData['is_enabled'];
+ }
+ }
+
+ // creation of localized list of allowed countries
+ $countryList = [];
+ $this->load->model('localisation/country');
+ $countries = $this->model_localisation_country->getCountries();
+
+ foreach ($countries as $country) {
+ $countryCode = strtolower($country['iso_code_2']);
+
+ $countryList[] = [
+ 'code' => $countryCode,
+ 'name' => $country['name']
+ ];
+ }
+ $data['countries'] = $countryList;
+
+ // set description text and links for form
+ $data['text_form_title'] = $this->language->get($isEdit ? 'text_edit_shipping_rule' : 'text_new_shipping_rule');
+ if ($isEdit) {
+ $data[self::TEMPLATE_LINK_FORM_ACTION] = $this->createAdminLink(self::ACTION_SHIPPING_RULES_EDIT,
+ [self::PARAM_RULE_ID => $ruleId]);
+ }
+ else {
+ $data[self::TEMPLATE_LINK_FORM_ACTION] = $this->createAdminLink(self::ACTION_SHIPPING_RULES_ADD);
+ }
+ $data[self::TEMPLATE_LINK_CANCEL] = $this->createAdminLink(self::ACTION_SHIPPING_RULES);
+
+ $this->response->setOutput($this->load->view('extension/shipping/zasilkovna_shipping_rules_form', $data));
+ }
+
+ /**
+ * Extension of menu in administration. Adds new item with list of Zasilkovna orders to menu "Sales".
+ * This method is called by "before" event on admin/view/common/column_left/before.
+ *
+ * @param string $route routing path of page
+ * @param array $data template parameters
+ * @param StdClass $template instance of page template
+ * @throws Exception
+ */
+ public function adminMenuExtension(&$route, &$data, &$template) {
+ if (!$this->user->hasPermission('access', self::ROUTING_BASE_PATH)) {
+ return;
+ }
+
+ foreach ($data['menus'] as &$menu) {
+ if ($menu['id'] != 'menu-sale') {
+ continue;
+ }
+
+ // load translations for Zasilkovna to separate language context
+ $this->load->language(self::ROUTING_BASE_PATH, 'zasilkovna');
+
+ // creation of new menu item for Zasilkovna
+ $newMenuItem = [
+ 'name' => $this->language->get('zasilkovna')->get('text_menu_item'),
+ 'href' => $this->createAdminLink(self::ACTION_ORDERS)
+ ];
+ array_push($menu['children'], $newMenuItem);
+ break;
+ }
+ }
+
+ /**
+ * Handler for list of "Zasilkovna" orders.
+ *
+ * @throws Exception
+ */
+ public function orders() {
+ $this->load->language(self::ROUTING_BASE_PATH);
+ $this->load->model(self::ROUTING_ORDERS);
+
+ // initialization of page data including setup of list parameters (filters, sorting, paging)
+ $data = $this->initPageData(self::ACTION_ORDERS, self::TEXT_TTILE_ORDERS);
+ $paramData = $this->model_extension_shipping_zasilkovna_orders->getUrlParameters();
+
+ // load list of order statuses and creation of array for translate ID to status description
+ $this->load->model('localisation/order_status');
+ $orderStatusList = $this->model_localisation_order_status->getOrderStatuses();
+ $data['order_statuses'] = $orderStatusList;
+ $orderStatusDescriptions = [];
+ foreach ($orderStatusList as $orderStatusItem) {
+ $orderStatusDescriptions[$orderStatusItem['order_status_id']] = $orderStatusItem['name'];
+ }
+
+ // load list of payment methods considered as "cash on delivery"
+ $codPaymentMethods = (array)$this->config->get('shipping_zasilkovna_cash_on_delivery_methods');
+
+ // load count of orders and list of orders for current page
+ $orderCount = $this->model_extension_shipping_zasilkovna_orders->getOrdersCount($paramData['filterData']);
+ $dbOrderList = $this->model_extension_shipping_zasilkovna_orders->getOrders($paramData);
+
+ // format list of orders for template
+ foreach ($dbOrderList as $order) {
+ $data['orders'][] = [
+ 'order_id' => $order['order_id'],
+ 'customer' => $order['customer'],
+ 'order_status' => isset($orderStatusDescriptions[$order['order_status_id']]) ? $orderStatusDescriptions[$order['order_status_id']] : '',
+ 'total' => $this->currency->format($order['total'], $order['currency_code'], $order['currency_value']),
+ 'is_cod' => in_array($order['payment_code'], $codPaymentMethods),
+ 'date_added' => date($this->language->get('date_format_short'), strtotime($order['date_added'])),
+ 'branch_id' => $order['branch_id'],
+ 'branch_name' => $order['branch_name'],
+ 'exported' => !empty($order['exported']) ? date($this->language->get('date_format_short'), strtotime($order['exported'])) : ''
+ ];
+ }
+
+ // to keep selected rows as selected
+ if (isset($this->request->post['selected'])) {
+ $data['selected'] = (array)$this->request->post['selected'];
+ } else {
+ $data['selected'] = array();
+ }
+
+ // creation set of links for CSV export actions
+ $csvExportUrlParams = $paramData['filterData'];
+ $csvExportUrlParams['sort'] = $paramData['sort'];
+ $csvExportUrlParams['order'] = $paramData['order'];
+ $data[self::TEMPLATE_LINK_EXPORT_SELECTED] = $this->createAdminLink(self::ACTION_ORDERS_EXPORT,
+ array_merge($csvExportUrlParams, ['scope' => 'selected']));
+ $data[self::TEMPLATE_LINK_EXPORT_ALL] = $this->createAdminLink(self::ACTION_ORDERS_EXPORT,
+ array_merge($csvExportUrlParams, ['scope' => 'all']));
+
+ // creation set of links to change grid sorting
+ $sortingUrlParams = [];
+ foreach ($paramData['filterData'] as $paramName => $paramValue) {
+ if (!empty($paramValue)) {
+ $sortingUrlParams[$paramName] = $paramValue;
+ }
+ }
+ $sortingUrlParams['page'] = $paramData['page'];
+ $sortingUrlParams['order'] = ($paramData['order'] == 'ASC') ? 'DESC' : 'ASC';
+
+ $data['link_sorting_order_id'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'o.order_id']));
+ $data['link_sorting_customer'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'customer']));
+ $data['link_sorting_order_status_id'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'order_status_id']));
+ $data['link_sorting_order_total'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'o.total']));
+ $data['link_sorting_order_date'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'date_added']));
+ $data['link_sorting_branch_name'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'oz.branch_name']));
+ $data['link_sorting_exported'] = $this->createAdminLink(self::ACTION_ORDERS, array_merge($sortingUrlParams, ['sort' => 'exported']));
+
+ // current sorting properties
+ $data['sort'] = $paramData['sort'];
+ $data['order'] = $paramData['order'];
+
+ // preparation of paging (switch between pages)
+ $pagingUrlParameters = [];
+ foreach ($paramData['filterData'] as $paramName => $paramValue) {
+ if (!empty($paramValue)) {
+ $pagingUrlParameters[$paramName] = $paramValue;
+ }
+ }
+ $pagingUrlParameters['sort'] = $paramData['sort'];
+ $pagingUrlParameters['order'] = $paramData['order'];
+ $pagingUrlParameters['page'] = '{page}';
+
+ $pageNumber = $paramData['page'];
+ $pagination = new Pagination();
+ $pagination->total = $orderCount;
+ $pagination->page = $pageNumber;
+ $pagination->limit = $this->config->get('config_limit_admin');
+ $pagination->url = $this->createAdminLink(self::ACTION_ORDERS, $pagingUrlParameters);
+ $data['pagination'] = $pagination->render();
+
+ // preparation of paging (current page info)
+ // string template: Showing %d to %d of %d (%d Pages)
+ $data['results'] = sprintf($this->language->get('text_pagination'),
+ ($orderCount) ? (($pageNumber - 1) * $this->config->get('config_limit_admin')) + 1 : 0,
+ ((($pageNumber - 1) * $this->config->get('config_limit_admin')) > ($orderCount - $this->config->get('config_limit_admin'))) ? $orderCount : ((($pageNumber - 1) * $this->config->get('config_limit_admin')) + $this->config->get('config_limit_admin')),
+ $orderCount,
+ ceil($orderCount / $this->config->get('config_limit_admin')));
+
+ // creation set of variables for default value of filters
+ foreach ($paramData['filterData'] as $paramName => $paramValue) {
+ $data[$paramName] = $paramValue;
+ }
+
+ // items of selectbox for type of export
+ $data['export_types'] = [
+ [ 'value' => 'not_exported', 'name' => $this->language->get('entry_ol_not_exported')],
+ [ 'value' => 'exported', 'name' => $this->language->get('entry_ol_exported')],
+ [ 'value' => 'all', 'name' => $this->language->get('entry_ol_all_records')]
+ ];
+
+ // add user token parameter for functionality of JS request (e.g. customer name autocomplete)
+ $data['user_token'] = $this->session->data['user_token'];
+
+ $this->response->setOutput($this->load->view('extension/shipping/zasilkovna_orders', $data));
+ }
+
+ /**
+ * Handler for export orders to CSV (all or selected orders).
+ *
+ * @throws Exception
+ */
+ public function orders_export() { // method name with underscore is required for correct routing
+ $this->load->language(self::ROUTING_BASE_PATH);
+ $this->load->model(self::ROUTING_ORDERS);
+
+ $paramData = $this->model_extension_shipping_zasilkovna_orders->getUrlParameters();
+ $exportScope = $this->request->get['scope'];
+ // all parameters except list of "row" checkboxes are part of form action (get parameters)
+ $orderIdList = (isset($this->request->post['selected'])) ? $this->request->post['selected']: [];
+
+ $this->load->model('setting/store');
+ $csvRawData = $this->model_extension_shipping_zasilkovna_orders->getCsvExportData($paramData, $exportScope, $orderIdList);
+
+ // open stdout as file and put content to it using native function for writing data in CSV format
+ $fileHandle = fopen('php://output', 'wb');
+ ob_start();
+ // first two lines are fixed header of file
+ fputcsv($fileHandle, ['version 5']);
+ fputcsv($fileHandle, []);
+
+ foreach ($csvRawData as $rawRecord) {
+ fputcsv($fileHandle, $rawRecord);
+ }
+ $csvFileContent = ob_get_contents();
+ ob_end_clean();
+
+ // set http headers for "force download" and file type
+ $this->response->addHeader('Content-Type: text/csv');
+ $fileName = 'orders-' . date('Y-m-d-H-i-s') . '.csv';
+ $this->response->addHeader('Content-Disposition: attachment; filename="' . $fileName . '"');
+
+ // send content of csv file as output
+ $this->response->setOutput($csvFileContent);
+ }
+
+ /**
+ * Check if user has permission to change module settings.
+ *
+ * @return bool TRUE = success, FALSE = error
+ */
+ private function checkPermissions() {
+ if (!$this->user->hasPermission('modify', self::ROUTING_BASE_PATH)) {
+ $data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get('error_permission');
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Check presence and content of url parameter for country.
+ * If parameter is missing or invalid, redirect to main setting page is performed.
+ *
+ * @return void
+ */
+ private function checkCountryCode() {
+ // check if code of target country is part of url
+ if (empty($this->request->get[self::PARAM_COUNTRY])) {
+ $this->load->language(self::ROUTING_BASE_PATH);
+ $this->session->data[self::TEMPLATE_MESSAGE_ERROR] = $this->language->get('error_missing_param');
+ $this->response->redirect($this->createAdminLink(''));
+ }
+ }
+
+ /**
+ * Method for page initialization. Returns customized base content of template data.
+ *
+ * @param string $actionName internal name of module action
+ * @param string $titleId language independent identifier of page title
+ * @param array $urlParameters additional parameters to url
+ * @return array initial version of template data
+ */
+ private function initPageData($actionName, $titleId, $urlParameters = []) {
+ // load language file for module
+ $this->load->language(self::ROUTING_BASE_PATH);
+ // set page (document) title
+ $this->document->setTitle($this->language->get($titleId));
+
+ // creation of customized common part of template data
+ $data = [
+ // common parts of page (header, left column with system menu, footer)
+ 'header' => $this->load->controller('common/header'),
+ 'column_left' => $this->load->controller('common/column_left'),
+ 'footer' => $this->load->controller('common/footer'),
+ 'breadcrumbs' => [
+ [
+ 'text' => $this->language->get('text_home'),
+ 'href' => $this->createAdminLink('common/dashboard')
+ ],
+ [
+ 'text' => $this->language->get('text_shipping'),
+ 'href' => $this->createAdminLink('marketplace/extension', ['type' => 'shipping'])
+ ],
+ [
+ 'text' => $this->language->get(self::TEXT_TITLE_MAIN),
+ 'href' => $this->createAdminLink('')
+ ]
+ ]
+ ];
+
+ // last part of "breadcrumbs" is added only for nonempty action name (pages of module)
+ if (!empty($actionName)) {
+ $data['breadcrumbs'][] = [
+ 'text' => $this->language->get($titleId),
+ 'href' => $this->createAdminLink($actionName, $urlParameters)
+ ];
+ }
+
+ // check if some error/success message is stored in session and set it as template parameter
+ if (isset($this->session->data[self::TEMPLATE_MESSAGE_SUCCESS])) {
+ $data[self::TEMPLATE_MESSAGE_SUCCESS] = $this->session->data[self::TEMPLATE_MESSAGE_SUCCESS];
+
+ unset($this->session->data[self::TEMPLATE_MESSAGE_SUCCESS]);
+ }
+ if (isset($this->session->data[self::TEMPLATE_MESSAGE_ERROR])) {
+ $data[self::TEMPLATE_MESSAGE_ERROR] = $this->session->data[self::TEMPLATE_MESSAGE_ERROR];
+
+ unset($this->session->data[self::TEMPLATE_MESSAGE_ERROR]);
+ }
+ if (isset($this->session->data['error_warning_multirow'])) {
+ $data['error_warning_multirow'] = $this->session->data['error_warning_multirow'];
+ unset($this->session->data['error_warning_multirow']);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Creates link to given action in administration including user token.
+ *
+ * @param string $actionName internal name of module action
+ * @param array $urlParameters additional parameters to url
+ * @return string
+ */
+ private function createAdminLink($actionName, $urlParameters = [])
+ {
+ // empty action name => main page of module
+ if ('' == $actionName) {
+ $actionName = self::ROUTING_BASE_PATH;
+ }
+
+ // action name without slash (/) => action of module
+ if (strpos($actionName, '/') === false) {
+ $actionName = self::ROUTING_BASE_PATH . '/' . $actionName;
+ }
+
+ // otherwise action name is absolute routing path => no change in action name
+ // user token must be part of any administration link
+ $urlParameters['user_token'] = $this->session->data['user_token'];
+
+ return $this->url->link($actionName, $urlParameters, true);
+ }
+
+}
+
+class ZasilkovnaUpgradeException extends Exception
+{
+}
diff --git a/admin/language/cs-cz/extension/shipping/zasilkovna.php b/upload/admin/language/cs-cz/extension/shipping/zasilkovna.php
similarity index 90%
rename from admin/language/cs-cz/extension/shipping/zasilkovna.php
rename to upload/admin/language/cs-cz/extension/shipping/zasilkovna.php
index a1727da..a423b28 100644
--- a/admin/language/cs-cz/extension/shipping/zasilkovna.php
+++ b/upload/admin/language/cs-cz/extension/shipping/zasilkovna.php
@@ -1,128 +1,130 @@
-db->query($sqlOrderTable);
-
- // new table for weight rules for countries
- $sqlWeightRulesTable = 'CREATE TABLE `' . DB_PREFIX . 'zasilkovna_weight_rules` (
- `rule_id` int(11) NOT NULL AUTO_INCREMENT,
- `target_country` varchar(5) NOT NULL COMMENT "iso code of target country",
- `min_weight` int(11) NOT NULL,
- `max_weight` int(11) NOT NULL,
- `price` float(12,2) NOT NULL COMMENT "price for given weight and shipping type",
- PRIMARY KEY (`rule_id`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8;';
- $this->db->query($sqlWeightRulesTable);
-
- // new table for list of shipping types in countries
- $sqlShippingRulesTable = 'CREATE TABLE `' . DB_PREFIX . 'zasilkovna_shipping_rules` (
- `rule_id` int(11) NOT NULL AUTO_INCREMENT,
- `target_country` varchar(5) NOT NULL COMMENT "iso code of target country",
- `default_price` float(12,2) NOT NULL COMMENT "default shipping price for given country",
- `free_over_limit` float(12,2) COMMENT "limit for free of charge shipping",
- `is_enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT "flag if shipping type is enabled",
- PRIMARY KEY (`rule_id`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8;';
- $this->db->query($sqlShippingRulesTable);
-
- // new events for processing additional data
- // source and target must be in the same part of e-shop (catalog or admin)
- $this->load->model('setting/event');
-
- $events = [
- 'catalog/controller/checkout/confirm/after' => 'extension/module/zasilkovna/saveOrderData',
- 'catalog/controller/checkout/success/before' => 'extension/module/zasilkovna/sessionCleanup',
- 'admin/view/common/column_left/before' => 'extension/shipping/zasilkovna/adminMenuExtension'
- ];
-
- foreach ($events as $trigger => $action) {
- $this->model_setting_event->addEvent(self::EVENT_CODE, $trigger, $action, 1, 0);
- }
- }
-
- /**
- * Cleanup during plugin uninstall. Deletes additional DB tables and removes registered events.
- *
- * @throws Exception
- */
- public function deleteTablesAndEvents() {
- // drop additional tables for extension module
- $tableNames = ['zasilkovna_weight_rules', 'zasilkovna_shipping_rules', 'zasilkovna_orders'];
- foreach ($tableNames as $shortTableName) {
- $sql = 'DROP TABLE `' . DB_PREFIX . $shortTableName . '`;';
- $this->db->query($sql);
- }
- // remove events registered for "zasilkovna" plugin
- $this->load->model('setting/event');
- $this->model_setting_event->deleteEventByCode(self::EVENT_CODE);
- }
-
- /**
- * Load list of payment methods including description name of method.
- * If description name is not found, internal method name is returned.
- *
- * @return array list of payment methods
- * @throws Exception
- */
- public function getInstalledPaymentMethods() {
- // load internal names of installed payment methods
- $this->load->model('setting/extension');
- $paymentCodeList = $this->model_setting_extension->getInstalled('payment');
-
- // Get description name of payment methods.
- // It must implemented inline because there is no model method for it.
- // Based on implementation in method getList in class ControllerExtensionExtensionPayment
- $paymentMethods = [];
- foreach ($paymentCodeList as $paymentCode) {
- // check if main file of extension exists
- $mainFilePath = DIR_APPLICATION . 'controller/extension/payment/' . $paymentCode . '.php';
- if (!file_exists($mainFilePath)) {
- continue; // extension is registered as installed, but file is missing
- }
-
- // load description name of payment method from language file of extension
- $this->load->language('extension/payment/' . $paymentCode, 'extension');
- $extensionName = $this->language->get('extension')->get('heading_title');
-
- $paymentMethods[] = [
- 'code' => $paymentCode,
- 'name' => $extensionName
- ];
- }
-
- return $paymentMethods;
- }
-}
\ No newline at end of file
+db->query($sqlOrderTable);
+
+ // new table for weight rules for countries
+ $sqlWeightRulesTable = 'CREATE TABLE `' . DB_PREFIX . 'zasilkovna_weight_rules` (
+ `rule_id` int(11) NOT NULL AUTO_INCREMENT,
+ `target_country` varchar(5) NOT NULL COMMENT "iso code of target country",
+ `min_weight` decimal(10,2) NOT NULL DEFAULT 0,
+ `max_weight` decimal(10,2) NOT NULL DEFAULT 0,
+ `price` float(12,2) NOT NULL COMMENT "price for given weight and shipping type",
+ PRIMARY KEY (`rule_id`)
+ ) ENGINE=MyISAM DEFAULT CHARSET=utf8;';
+ $this->db->query($sqlWeightRulesTable);
+
+ // new table for list of shipping types in countries
+ $sqlShippingRulesTable = 'CREATE TABLE `' . DB_PREFIX . 'zasilkovna_shipping_rules` (
+ `rule_id` int(11) NOT NULL AUTO_INCREMENT,
+ `target_country` varchar(5) NOT NULL COMMENT "iso code of target country",
+ `default_price` float(12,2) NOT NULL COMMENT "default shipping price for given country",
+ `free_over_limit` float(12,2) COMMENT "limit for free of charge shipping",
+ `is_enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT "flag if shipping type is enabled",
+ PRIMARY KEY (`rule_id`)
+ ) ENGINE=MyISAM DEFAULT CHARSET=utf8;';
+ $this->db->query($sqlShippingRulesTable);
+
+ $this->installEvents();
+ }
+
+ /**
+ * Alters database schema
+ * @param string $oldVersion version before upgrade
+ * @throws ZasilkovnaUpgradeException
+ */
+ public function upgradeSchema($oldVersion)
+ {
+ $queries = [];
+
+ if ($oldVersion && version_compare($oldVersion, '2.0.4') < 0) {
+ $queries[] = "ALTER TABLE `" . DB_PREFIX . "zasilkovna_orders`
+ ADD COLUMN `carrier_pickup_point` VARCHAR(40) NULL
+ COMMENT 'Code of selected carrier pickup point related to branch_id' AFTER `branch_name`;";
+ $queries[] = "ALTER TABLE `" . DB_PREFIX . "zasilkovna_orders`
+ ADD COLUMN `is_carrier` TINYINT(1) NOT NULL DEFAULT 0
+ COMMENT 'Tells if branch_id is carrier' AFTER `carrier_pickup_point`;";
+ $queries[] = "ALTER TABLE `" . DB_PREFIX . "zasilkovna_weight_rules`
+ CHANGE `min_weight` `min_weight` decimal(10,2) NOT NULL DEFAULT 0;";
+ $queries[] = "ALTER TABLE `" . DB_PREFIX . "zasilkovna_weight_rules`
+ CHANGE `max_weight` `max_weight` decimal(10,2) NOT NULL DEFAULT 0;";
+ }
+
+ foreach ($queries as $query) {
+ try {
+ $this->db->query($query);
+ } catch (Exception $exception) {
+ $this->log->write('Exception "' . $exception->getMessage() . '" was thrown during execution of SQL query: ' . $query);
+ throw new ZasilkovnaUpgradeException($exception->getMessage());
+ }
+ }
+ }
+
+ public function installEvents()
+ {
+ // new events for processing additional data
+ // source and target must be in the same part of e-shop (catalog or admin)
+ $this->load->model('setting/event');
+
+ // add new cart here 1/3
+ $events = [
+ 'catalog/controller/checkout/confirm/after' => 'extension/module/zasilkovna/saveOrderData',
+ 'catalog/controller/checkout/success/before' => 'extension/module/zasilkovna/sessionCleanup',
+ 'catalog/controller/checkout/checkout/before' => 'extension/module/zasilkovna/addStyleAndScript',
+ 'catalog/controller/checkout/shipping_address/save/before' => 'extension/module/zasilkovna/sessionCheckOnShippingChange',
+ 'catalog/controller/checkout/guest_shipping/save/before' => 'extension/module/zasilkovna/sessionCheckOnShippingChangeGuest',
+ 'catalog/controller/checkout/guest/save/before' => 'extension/module/zasilkovna/sessionCheckOnShippingChangeGuest',
+ 'catalog/controller/journal3/checkout/save/before' => 'extension/module/zasilkovna/journal3CheckoutSave',
+ 'catalog/controller/journal3/checkout/save/after' => 'extension/module/zasilkovna/saveOrderData',
+ 'admin/view/common/column_left/before' => 'extension/shipping/zasilkovna/adminMenuExtension'
+ ];
+
+ $this->model_setting_event->deleteEventByCode(self::EVENT_CODE);
+ foreach ($events as $trigger => $action) {
+ $this->model_setting_event->addEvent(self::EVENT_CODE, $trigger, $action, 1, 0);
+ }
+ }
+
+ /**
+ * Cleanup during plugin uninstall. Deletes additional DB tables and removes registered events.
+ *
+ * @throws Exception
+ */
+ public function deleteTablesAndEvents() {
+ // drop additional tables for extension module
+ $tableNames = ['zasilkovna_weight_rules', 'zasilkovna_shipping_rules', 'zasilkovna_orders'];
+ foreach ($tableNames as $shortTableName) {
+ $sql = 'DROP TABLE `' . DB_PREFIX . $shortTableName . '`;';
+ $this->db->query($sql);
+ }
+ // remove events registered for "zasilkovna" plugin
+ $this->load->model('setting/event');
+ $this->model_setting_event->deleteEventByCode(self::EVENT_CODE);
+ }
+
+ /**
+ * Load list of payment methods including description name of method.
+ * If description name is not found, internal method name is returned.
+ *
+ * @return array list of payment methods
+ * @throws Exception
+ */
+ public function getInstalledPaymentMethods() {
+ // load internal names of installed payment methods
+ $this->load->model('setting/extension');
+ $paymentCodeList = $this->model_setting_extension->getInstalled('payment');
+
+ // Get description name of payment methods.
+ // It must implemented inline because there is no model method for it.
+ // Based on implementation in method getList in class ControllerExtensionExtensionPayment
+ $paymentMethods = [];
+ foreach ($paymentCodeList as $paymentCode) {
+ // check if main file of extension exists
+ $mainFilePath = DIR_APPLICATION . 'controller/extension/payment/' . $paymentCode . '.php';
+ if (!file_exists($mainFilePath)) {
+ continue; // extension is registered as installed, but file is missing
+ }
+
+ // load description name of payment method from language file of extension
+ $this->load->language('extension/payment/' . $paymentCode, 'extension');
+ $extensionName = $this->language->get('extension')->get('heading_title');
+
+ $paymentMethods[] = [
+ 'code' => $paymentCode,
+ 'name' => $extensionName
+ ];
+ }
+
+ return $paymentMethods;
+ }
+}
diff --git a/admin/model/extension/shipping/zasilkovna_common.php b/upload/admin/model/extension/shipping/zasilkovna_common.php
similarity index 79%
rename from admin/model/extension/shipping/zasilkovna_common.php
rename to upload/admin/model/extension/shipping/zasilkovna_common.php
index ba390a7..6051aa1 100644
--- a/admin/model/extension/shipping/zasilkovna_common.php
+++ b/upload/admin/model/extension/shipping/zasilkovna_common.php
@@ -1,27 +1,23 @@
-db->query("SELECT * FROM " . DB_PREFIX . "country WHERE iso_code_2 = '" . $this->db->escape($code) . "'");
+
+ if (empty($query)) {
+ return null;
+ }
+
+ return $query->row;
+ }
+
+ /**
+ * @param $code
+ * @return string|null
+ */
+ public function getCountryNameByIsoCode2($code)
+ {
+ if (empty($code)) {
+ return null;
+ }
+
+ $country = $this->getCountryByIsoCode2(strtoupper((string) $code));
+ if ($country) {
+ return $country['name'];
+ }
+
+ return $code;
+ }
+}
diff --git a/admin/model/extension/shipping/zasilkovna_orders.php b/upload/admin/model/extension/shipping/zasilkovna_orders.php
similarity index 97%
rename from admin/model/extension/shipping/zasilkovna_orders.php
rename to upload/admin/model/extension/shipping/zasilkovna_orders.php
index 2f7abfa..efdd161 100644
--- a/admin/model/extension/shipping/zasilkovna_orders.php
+++ b/upload/admin/model/extension/shipping/zasilkovna_orders.php
@@ -1,344 +1,345 @@
-request->get[$filterParamName])) {
- $filterData[$filterParamName] = $this->request->get[$filterParamName];
- }
- else {
- $filterData[$filterParamName] = '';
- }
- }
- // overwrite default value of "exported" parameter to "not exported"
- if (empty($filterData[self::FILTER_EXPORTED])) {
- $filterData[self::FILTER_EXPORTED] = 'not_exported';
- }
-
- $allowedSortColumns = ['o.order_id', 'customer', 'order_status_id', 'o.total', 'date_added', 'oz.branch_name', 'exported'];
- if (!empty($this->request->get[self::PARAM_SORT_COLUMN]) && in_array($this->request->get[self::PARAM_SORT_COLUMN], $allowedSortColumns)) {
- $sortColumn = $this->request->get[self::PARAM_SORT_COLUMN];
- }
- else {
- $sortColumn = 'o.order_id';
- }
-
- $allowedSortDirections = ['ASC', 'DESC'];
- if (!empty($this->request->get[self::PARAM_SORT_DIRECTION]) && in_array($this->request->get[self::PARAM_SORT_DIRECTION], $allowedSortDirections)) {
- $sortDirection = $this->request->get[self::PARAM_SORT_DIRECTION];
- }
- else {
- $sortDirection = 'DESC';
- }
-
- if (!empty($this->request->get[self::PARAM_PAGE_NUMBER])) {
- $pageNumber = (int) $this->request->get[self::PARAM_PAGE_NUMBER];
- if ($pageNumber <= 0) {
- $pageNumber = 1;
- }
- }
- else {
- $pageNumber = 1;
- }
-
- $paramData = [
- 'filterData' => $filterData,
- self::PARAM_SORT_COLUMN => $sortColumn,
- self::PARAM_SORT_DIRECTION => $sortDirection,
- self::PARAM_PAGE_NUMBER => $pageNumber
- ];
-
- return $paramData;
- }
-
- /**
- * Creates additional sql conditions for list of orders.
- *
- * @param array $filterData filter parameters
- * @return string
- */
- private function createFilterConditions(array $filterData) {
- $sqlConditions = '';
-
- // filter by selected order statuses selected in global configuration
- $orderStatuses = $this->config->get('shipping_zasilkovna_order_statuses');
- if (!empty($orderStatuses)) {
- $orderStatusesString = '';
- foreach ($orderStatuses as $status) {
- $orderStatusesString .= (int) $status . ', ';
- }
- $orderStatusesString = substr($orderStatusesString, 0, -2);
- $sqlConditions .= ' AND o.order_status_id IN (' . $orderStatusesString . ')';
- }
-
- if (!empty($filterData[self::FILTER_ORDER_ID])) {
- $sqlConditions .= ' AND o.order_id=' . (int) $filterData[self::FILTER_ORDER_ID];
- }
-
- if (!empty($filterData[self::FILTER_CUSTOMER])) {
- $sqlConditions .= ' AND CONCAT(o.firstname, " ", o.lastname) LIKE "%' . $this->db->escape($filterData[self::FILTER_CUSTOMER]) . '%"';
- }
-
- if (!empty($filterData[self::FILTER_ORDER_DATE_FROM])) {
- $sqlConditions .= ' AND o.date_added >= "' . $this->db->escape($filterData[self::FILTER_ORDER_DATE_FROM]) . '"';
- }
- if (!empty($filterData[self::FILTER_ORDER_DATE_TO])) {
- $sqlConditions .= ' AND o.date_added <= "' . $this->db->escape($filterData[self::FILTER_ORDER_DATE_TO]) . ' 23:59:59"';
- }
-
- if (!empty($filterData[self::FILTER_BRANCH_NAME])) {
- $sqlConditions .= ' AND oz.branch_name like "%' . $filterData[self::FILTER_BRANCH_NAME] . '%"';
- }
-
- if (!empty($filterData[self::FILTER_EXPORT_DATE_FROM])) {
- $sqlConditions .= ' AND oz.exported >= "' . $this->db->escape($filterData[self::FILTER_EXPORT_DATE_FROM]) . '"';
- }
- if (!empty($filterData[self::FILTER_EXPORT_DATE_TO])) {
- $sqlConditions .= ' AND oz.exported <= "' . $this->db->escape($filterData[self::FILTER_EXPORT_DATE_TO]) . ' 23:59:59"';
- }
-
- if (!empty($filterData[self::FILTER_EXPORTED])) {
- switch ($filterData[self::FILTER_EXPORTED]) {
- case 'exported':
- $sqlConditions .= ' AND oz.exported IS NOT NULL';
- break;
- case 'not_exported':
- $sqlConditions .= ' AND oz.exported IS NULL';
- break;
- default: // value "all" and other values
- break;
- }
- }
-
- // remove first "AND" from begin of conditions
- $sqlConditions = substr($sqlConditions, 4);
-
- return $sqlConditions;
- }
-
- /**
- * Returns counts of "Zasilkovna" orders according to current filters.
- *
- * @param array $filterData filter parameters
- * @return int count of orders
- */
- public function getOrdersCount(array $filterData) {
- $sqlConditions = $this->createFilterConditions($filterData);
- $sqlQueryTemplate = 'SELECT count(*) AS `total` FROM `%s` `o` JOIN `%s` `oz` ON (`oz`.`order_id` = `o`.`order_id`) WHERE %s;';
- $sqlQuery = sprintf($sqlQueryTemplate, self::BASE_ORDER_TABLE_NAME, self::TABLE_NAME, $sqlConditions);
-
- /** @var StdClass $queryResult */
- $queryResult = $this->db->query($sqlQuery);
- return (int) $queryResult->row['total'];
- }
-
- /**
- * Returns list of "Zasilkovna" orders including additional data according to current filters.
- *
- * @param array $paramData url parameters
- * @return array list of orders
- */
- public function getOrders(array $paramData) {
- $sqlConditions = $this->createFilterConditions($paramData['filterData']);
- $pageSize = $this->config->get('config_limit_admin');
- $queryOffset = ($paramData[self::PARAM_PAGE_NUMBER] - 1) * $pageSize;
-
- $sqlQueryTemplate = 'SELECT `o`.`order_id`, CONCAT(o.firstname, " ", o.lastname) AS customer, o.order_status_id, '
- . ' `o`.`date_added`, `o`.`payment_code`, `o`.`total`, `o`.`currency_code`, `o`.`currency_value`, `oz`.`branch_id`, `oz`.`branch_name`, `oz`.`exported`'
- . ' FROM `%s` `o` JOIN `%s` `oz` ON (`oz`.`order_id` = `o`.`order_id`) WHERE %s'
- // add sorting and paging parts (variables with column name and direction is already sanitized in getUrlParameters())
- . ' ORDER BY %s %s LIMIT %s, %s';
- $sqlQuery = sprintf($sqlQueryTemplate, self::BASE_ORDER_TABLE_NAME, self::TABLE_NAME, $sqlConditions,
- $paramData[self::PARAM_SORT_COLUMN], $paramData[self::PARAM_SORT_DIRECTION],
- (int) $queryOffset, (int) $pageSize);
-
- /** @var StdClass $queryResult */
- $queryResult = $this->db->query($sqlQuery);
- return $queryResult->rows;
- }
-
- /**
- * Returns raw data for CSV export of orders.
- *
- * @param array $paramData url parameters for order list (filter parameters)
- * @param string $scope of export (all or selected record)
- * @param array $orderIdList array of selected order IDs
- * @return array raw data for CSV export
- */
- public function getCsvExportData(array $paramData, $scope, $orderIdList = []) {
- // load list of payment method considered as "cash on delivery"
- $codPaymentMethod = $this->config->get('shipping_zasilkovna_cash_on_delivery_methods');
-
- // load list of e-shop identifiers from module settings
- $eshopIdentifierList = $this->getEshopIdentifiers();
-
- // load list of orders including additional order data including filters used in order grid
- $filterConditions = $this->createFilterConditions($paramData['filterData']);
- $scopeCondition = '';
- if ('selected' === $scope && !empty($orderIdList)) {
- // function implode cannot be used because of possible sql injection
- $orderIdListString = '';
- foreach ($orderIdList as $orderId) {
- $orderIdListString .= (int) $orderId . ',';
- }
- $orderIdListString = substr($orderIdListString, 0 , -1);
-
- $scopeCondition = ' `o`.`order_id` IN (' . $orderIdListString . ') AND ';
- }
-
- $sqlQueryTemplate = 'SELECT `o`.`order_id`, `o`.`store_id`, `o`.`shipping_firstname`, `o`.`shipping_lastname`, `o`.`shipping_company`,'
- . ' `o`.`email`, `o`.`telephone`, `o`.`currency_code`, `o`.`currency_value`, `o`.`total`, `oz`.`total_weight`, `oz`.`branch_id`,'
- . ' `o`.`shipping_address_1`, `o`.`shipping_city`, `o`.`shipping_postcode`, `o`.`payment_code` '
- . ' FROM `%s` `o` JOIN `%s` `oz` ON (`oz`.`order_id` = `o`.`order_id`) WHERE %s %s'
- // add sorting parts (variables with column name and direction is already sanitized in getUrlParameters())
- . ' ORDER BY %s %s';
-
- $sqlQuery = sprintf($sqlQueryTemplate, self::BASE_ORDER_TABLE_NAME, self::TABLE_NAME, $scopeCondition,
- $filterConditions, $paramData[self::PARAM_SORT_COLUMN], $paramData[self::PARAM_SORT_DIRECTION]);
-
- /** @var StdClass $queryResult */
- $queryResult = $this->db->query($sqlQuery);
-
- // format data for CSV export
- $csvRawData = [];
- $exportedOrders = [];
- foreach ($queryResult->rows as $dbRow) {
- // Parts of order price:
- // order.total - total amount of order in main store currency
- // order.currency_code - iso code of target currency
- // order.currency_value - ratio between main store currency and target currency
- $priceInTargetCurrency = $this->currency->format($dbRow['total'], $dbRow['currency_code'], $dbRow['currency_value'], false);
-
- // set value of "cash on delivery" according to payment method
- if (in_array($dbRow['payment_code'], $codPaymentMethod)) {
- $cod = $priceInTargetCurrency;
- }
- else {
- $cod = '';
- }
-
- $eshopIdentifier = (isset($eshopIdentifierList[$dbRow['store_id']])) ? $eshopIdentifierList[$dbRow['store_id']] : '';
-
- $csvRawData[] = [
- 'Reserved' => '',
- 'OrderNumber' => $dbRow['order_id'],
- 'Name' => $dbRow['shipping_firstname'],
- 'Surname' => $dbRow['shipping_lastname'],
- 'Company' => $dbRow['shipping_company'],
- 'E-mail' => $dbRow['email'],
- 'Phone' => $dbRow['telephone'],
- 'COD' => $cod,
- 'Currency' => $dbRow['currency_code'],
- 'Value' => (double) $priceInTargetCurrency,
- 'Weight' => $dbRow['total_weight'],
- 'Pickupoint' => $dbRow['branch_id'],
- 'SenderLabel' => $eshopIdentifier,
- 'AdultContent' => '',
- 'DelayedDelivery' => '',
- // street number contains also house number, e-shop doesn't have separate items for street and house number
- 'Street' => $dbRow['shipping_address_1'],
- 'House Number' => '',
- 'City' => $dbRow['shipping_city'],
- 'ZIP' => $dbRow['shipping_postcode'],
- 'CarrierPickup' => '',
- 'Width' => '',
- 'Height' => '',
- 'Depth' => '',
- ];
-
- $exportedOrders[] = $dbRow['order_id'];
- }
-
- // mark all exported records as exported (set current date and time)
- if (!empty($exportedOrders)) {
- $sqlQueryTemplate = 'UPDATE `%s` SET `exported` = NOW() WHERE `order_id` IN (%s);';
- // direct use of implode method is possible because order ID is received from DB record
- $sqlQuery = sprintf($sqlQueryTemplate, self::TABLE_NAME, implode(',', $exportedOrders));
- $this->db->query($sqlQuery);
- }
-
- return $csvRawData;
- }
-
- /**
- * Returns list of e-shop identifiers for defined stores.
- *
- * @return array list of e-shop identifiers from settings
- */
- private function getEshopIdentifiers() {
- $result = [
- 0 => $this->config->get('shipping_zasilkovna_eshop_identifier_0')
- ];
-
- $storeList = $this->model_setting_store->getStores();
- foreach ($storeList as $storeItem) {
- $configItemName = 'shipping_zasilkovna_eshop_identifier_' . $storeItem['store_id'];
- $result[$storeItem['store_id']] = $this->config->get($configItemName);
- }
-
- return $result;
- }
-
-}
\ No newline at end of file
+request->get[$filterParamName])) {
+ $filterData[$filterParamName] = $this->request->get[$filterParamName];
+ }
+ else {
+ $filterData[$filterParamName] = '';
+ }
+ }
+ // overwrite default value of "exported" parameter to "not exported"
+ if (empty($filterData[self::FILTER_EXPORTED])) {
+ $filterData[self::FILTER_EXPORTED] = 'not_exported';
+ }
+
+ $allowedSortColumns = ['o.order_id', 'customer', 'order_status_id', 'o.total', 'date_added', 'oz.branch_name', 'exported'];
+ if (!empty($this->request->get[self::PARAM_SORT_COLUMN]) && in_array($this->request->get[self::PARAM_SORT_COLUMN], $allowedSortColumns)) {
+ $sortColumn = $this->request->get[self::PARAM_SORT_COLUMN];
+ }
+ else {
+ $sortColumn = 'o.order_id';
+ }
+
+ $allowedSortDirections = ['ASC', 'DESC'];
+ if (!empty($this->request->get[self::PARAM_SORT_DIRECTION]) && in_array($this->request->get[self::PARAM_SORT_DIRECTION], $allowedSortDirections)) {
+ $sortDirection = $this->request->get[self::PARAM_SORT_DIRECTION];
+ }
+ else {
+ $sortDirection = 'DESC';
+ }
+
+ if (!empty($this->request->get[self::PARAM_PAGE_NUMBER])) {
+ $pageNumber = (int) $this->request->get[self::PARAM_PAGE_NUMBER];
+ if ($pageNumber <= 0) {
+ $pageNumber = 1;
+ }
+ }
+ else {
+ $pageNumber = 1;
+ }
+
+ $paramData = [
+ 'filterData' => $filterData,
+ self::PARAM_SORT_COLUMN => $sortColumn,
+ self::PARAM_SORT_DIRECTION => $sortDirection,
+ self::PARAM_PAGE_NUMBER => $pageNumber
+ ];
+
+ return $paramData;
+ }
+
+ /**
+ * Creates additional sql conditions for list of orders.
+ *
+ * @param array $filterData filter parameters
+ * @return string
+ */
+ private function createFilterConditions(array $filterData) {
+ $sqlConditions = '';
+
+ // filter by selected order statuses selected in global configuration
+ $orderStatuses = $this->config->get('shipping_zasilkovna_order_statuses');
+ if (!empty($orderStatuses)) {
+ $orderStatusesString = '';
+ foreach ($orderStatuses as $status) {
+ $orderStatusesString .= (int) $status . ', ';
+ }
+ $orderStatusesString = substr($orderStatusesString, 0, -2);
+ $sqlConditions .= ' AND o.order_status_id IN (' . $orderStatusesString . ')';
+ }
+
+ if (!empty($filterData[self::FILTER_ORDER_ID])) {
+ $sqlConditions .= ' AND o.order_id=' . (int) $filterData[self::FILTER_ORDER_ID];
+ }
+
+ if (!empty($filterData[self::FILTER_CUSTOMER])) {
+ $sqlConditions .= ' AND CONCAT(o.firstname, " ", o.lastname) LIKE "%' . $this->db->escape($filterData[self::FILTER_CUSTOMER]) . '%"';
+ }
+
+ if (!empty($filterData[self::FILTER_ORDER_DATE_FROM])) {
+ $sqlConditions .= ' AND o.date_added >= "' . $this->db->escape($filterData[self::FILTER_ORDER_DATE_FROM]) . '"';
+ }
+ if (!empty($filterData[self::FILTER_ORDER_DATE_TO])) {
+ $sqlConditions .= ' AND o.date_added <= "' . $this->db->escape($filterData[self::FILTER_ORDER_DATE_TO]) . ' 23:59:59"';
+ }
+
+ if (!empty($filterData[self::FILTER_BRANCH_NAME])) {
+ $sqlConditions .= ' AND oz.branch_name like "%' . $filterData[self::FILTER_BRANCH_NAME] . '%"';
+ }
+
+ if (!empty($filterData[self::FILTER_EXPORT_DATE_FROM])) {
+ $sqlConditions .= ' AND oz.exported >= "' . $this->db->escape($filterData[self::FILTER_EXPORT_DATE_FROM]) . '"';
+ }
+ if (!empty($filterData[self::FILTER_EXPORT_DATE_TO])) {
+ $sqlConditions .= ' AND oz.exported <= "' . $this->db->escape($filterData[self::FILTER_EXPORT_DATE_TO]) . ' 23:59:59"';
+ }
+
+ if (!empty($filterData[self::FILTER_EXPORTED])) {
+ switch ($filterData[self::FILTER_EXPORTED]) {
+ case 'exported':
+ $sqlConditions .= ' AND oz.exported IS NOT NULL';
+ break;
+ case 'not_exported':
+ $sqlConditions .= ' AND oz.exported IS NULL';
+ break;
+ default: // value "all" and other values
+ break;
+ }
+ }
+
+ // remove first "AND" from begin of conditions
+ $sqlConditions = substr($sqlConditions, 4);
+
+ return $sqlConditions;
+ }
+
+ /**
+ * Returns counts of "Zasilkovna" orders according to current filters.
+ *
+ * @param array $filterData filter parameters
+ * @return int count of orders
+ */
+ public function getOrdersCount(array $filterData) {
+ $sqlConditions = $this->createFilterConditions($filterData);
+ $sqlQueryTemplate = 'SELECT count(*) AS `total` FROM `%s` `o` JOIN `%s` `oz` ON (`oz`.`order_id` = `o`.`order_id`) WHERE %s;';
+ $sqlQuery = sprintf($sqlQueryTemplate, self::BASE_ORDER_TABLE_NAME, self::TABLE_NAME, $sqlConditions);
+
+ /** @var StdClass $queryResult */
+ $queryResult = $this->db->query($sqlQuery);
+ return (int) $queryResult->row['total'];
+ }
+
+ /**
+ * Returns list of "Zasilkovna" orders including additional data according to current filters.
+ *
+ * @param array $paramData url parameters
+ * @return array list of orders
+ */
+ public function getOrders(array $paramData) {
+ $sqlConditions = $this->createFilterConditions($paramData['filterData']);
+ $pageSize = $this->config->get('config_limit_admin');
+ $queryOffset = ($paramData[self::PARAM_PAGE_NUMBER] - 1) * $pageSize;
+
+ $sqlQueryTemplate = 'SELECT `o`.`order_id`, CONCAT(o.firstname, " ", o.lastname) AS customer, o.order_status_id, '
+ . ' `o`.`date_added`, `o`.`payment_code`, `o`.`total`, `o`.`currency_code`, `o`.`currency_value`, `oz`.`branch_id`, `oz`.`branch_name`, `oz`.`exported`'
+ . ' FROM `%s` `o` JOIN `%s` `oz` ON (`oz`.`order_id` = `o`.`order_id`) WHERE %s'
+ // add sorting and paging parts (variables with column name and direction is already sanitized in getUrlParameters())
+ . ' ORDER BY %s %s LIMIT %s, %s';
+ $sqlQuery = sprintf($sqlQueryTemplate, self::BASE_ORDER_TABLE_NAME, self::TABLE_NAME, $sqlConditions,
+ $paramData[self::PARAM_SORT_COLUMN], $paramData[self::PARAM_SORT_DIRECTION],
+ (int) $queryOffset, (int) $pageSize);
+
+ /** @var StdClass $queryResult */
+ $queryResult = $this->db->query($sqlQuery);
+ return $queryResult->rows;
+ }
+
+ /**
+ * Returns raw data for CSV export of orders.
+ *
+ * @param array $paramData url parameters for order list (filter parameters)
+ * @param string $scope of export (all or selected record)
+ * @param array $orderIdList array of selected order IDs
+ * @return array raw data for CSV export
+ */
+ public function getCsvExportData(array $paramData, $scope, $orderIdList = []) {
+ // load list of payment method considered as "cash on delivery"
+ $codPaymentMethod = $this->config->get('shipping_zasilkovna_cash_on_delivery_methods');
+
+ // load list of e-shop identifiers from module settings
+ $eshopIdentifierList = $this->getEshopIdentifiers();
+
+ // load list of orders including additional order data including filters used in order grid
+ $filterConditions = $this->createFilterConditions($paramData['filterData']);
+ $scopeCondition = '';
+ if ('selected' === $scope && !empty($orderIdList)) {
+ // function implode cannot be used because of possible sql injection
+ $orderIdListString = '';
+ foreach ($orderIdList as $orderId) {
+ $orderIdListString .= (int) $orderId . ',';
+ }
+ $orderIdListString = substr($orderIdListString, 0 , -1);
+
+ $scopeCondition = ' `o`.`order_id` IN (' . $orderIdListString . ') AND ';
+ }
+
+ $sqlQueryTemplate = 'SELECT `o`.`order_id`, `o`.`store_id`, `o`.`shipping_firstname`, `o`.`shipping_lastname`, `o`.`shipping_company`,'
+ . ' `o`.`email`, `o`.`telephone`, `o`.`currency_code`, `o`.`currency_value`, `o`.`total`, `oz`.`total_weight`, `oz`.`branch_id`,'
+ . ' `oz`.`carrier_pickup_point`,'
+ . ' `o`.`shipping_address_1`, `o`.`shipping_city`, `o`.`shipping_postcode`, `o`.`payment_code` '
+ . ' FROM `%s` `o` JOIN `%s` `oz` ON (`oz`.`order_id` = `o`.`order_id`) WHERE %s %s'
+ // add sorting parts (variables with column name and direction is already sanitized in getUrlParameters())
+ . ' ORDER BY %s %s';
+
+ $sqlQuery = sprintf($sqlQueryTemplate, self::BASE_ORDER_TABLE_NAME, self::TABLE_NAME, $scopeCondition,
+ $filterConditions, $paramData[self::PARAM_SORT_COLUMN], $paramData[self::PARAM_SORT_DIRECTION]);
+
+ /** @var StdClass $queryResult */
+ $queryResult = $this->db->query($sqlQuery);
+
+ // format data for CSV export
+ $csvRawData = [];
+ $exportedOrders = [];
+ foreach ($queryResult->rows as $dbRow) {
+ // Parts of order price:
+ // order.total - total amount of order in main store currency
+ // order.currency_code - iso code of target currency
+ // order.currency_value - ratio between main store currency and target currency
+ $priceInTargetCurrency = $this->currency->format($dbRow['total'], $dbRow['currency_code'], $dbRow['currency_value'], false);
+
+ // set value of "cash on delivery" according to payment method
+ if (in_array($dbRow['payment_code'], $codPaymentMethod)) {
+ $cod = $priceInTargetCurrency;
+ }
+ else {
+ $cod = '';
+ }
+
+ $eshopIdentifier = (isset($eshopIdentifierList[$dbRow['store_id']])) ? $eshopIdentifierList[$dbRow['store_id']] : '';
+
+ $csvRawData[] = [
+ 'Reserved' => '',
+ 'OrderNumber' => $dbRow['order_id'],
+ 'Name' => $dbRow['shipping_firstname'],
+ 'Surname' => $dbRow['shipping_lastname'],
+ 'Company' => $dbRow['shipping_company'],
+ 'E-mail' => $dbRow['email'],
+ 'Phone' => $dbRow['telephone'],
+ 'COD' => $cod,
+ 'Currency' => $dbRow['currency_code'],
+ 'Value' => (double) $priceInTargetCurrency,
+ 'Weight' => $dbRow['total_weight'],
+ 'Pickupoint' => $dbRow['branch_id'],
+ 'SenderLabel' => $eshopIdentifier,
+ 'AdultContent' => '',
+ 'DelayedDelivery' => '',
+ // street number contains also house number, e-shop doesn't have separate items for street and house number
+ 'Street' => $dbRow['shipping_address_1'],
+ 'House Number' => '',
+ 'City' => $dbRow['shipping_city'],
+ 'ZIP' => $dbRow['shipping_postcode'],
+ 'CarrierPickup' => (string) $dbRow['carrier_pickup_point'],
+ 'Width' => '',
+ 'Height' => '',
+ 'Depth' => '',
+ ];
+
+ $exportedOrders[] = $dbRow['order_id'];
+ }
+
+ // mark all exported records as exported (set current date and time)
+ if (!empty($exportedOrders)) {
+ $sqlQueryTemplate = 'UPDATE `%s` SET `exported` = NOW() WHERE `order_id` IN (%s);';
+ // direct use of implode method is possible because order ID is received from DB record
+ $sqlQuery = sprintf($sqlQueryTemplate, self::TABLE_NAME, implode(',', $exportedOrders));
+ $this->db->query($sqlQuery);
+ }
+
+ return $csvRawData;
+ }
+
+ /**
+ * Returns list of e-shop identifiers for defined stores.
+ *
+ * @return array list of e-shop identifiers from settings
+ */
+ private function getEshopIdentifiers() {
+ $result = [
+ 0 => $this->config->get('shipping_zasilkovna_eshop_identifier_0')
+ ];
+
+ $storeList = $this->model_setting_store->getStores();
+ foreach ($storeList as $storeItem) {
+ $configItemName = 'shipping_zasilkovna_eshop_identifier_' . $storeItem['store_id'];
+ $result[$storeItem['store_id']] = $this->config->get($configItemName);
+ }
+
+ return $result;
+ }
+
+}
diff --git a/admin/model/extension/shipping/zasilkovna_shipping_rules.php b/upload/admin/model/extension/shipping/zasilkovna_shipping_rules.php
similarity index 93%
rename from admin/model/extension/shipping/zasilkovna_shipping_rules.php
rename to upload/admin/model/extension/shipping/zasilkovna_shipping_rules.php
index ffc0d7e..bce79a3 100644
--- a/admin/model/extension/shipping/zasilkovna_shipping_rules.php
+++ b/upload/admin/model/extension/shipping/zasilkovna_shipping_rules.php
@@ -1,175 +1,171 @@
-db->query($sqlQuery);
-
- return $queryResult->rows;
- }
-
- /**
- * Get content of rule.
- *
- * @param $ruleId int internal rule ID
- * @return array content of rule
- */
- public function getRule($ruleId) {
- $sqlQuery = sprintf('SELECT * FROM %s WHERE `rule_id` = %s', self::TABLE_NAME, (int) $ruleId);
- /** @var StdClass $queryResult */
- $queryResult = $this->db->query($sqlQuery);
-
- return $queryResult->row;
- }
-
- /**
- * Creates a new weight rule for country.
- *
- * @param array $ruleData data of new rule from POST parameters
- * @return string identifier of error message, empty if no error occurred
- */
- public function addRule(array $ruleData) {
- $checkErrorMessage = $this->checkRuleData($ruleData);
- if (!empty($checkErrorMessage)) {
- return $checkErrorMessage;
- }
-
- $sqlQuery = sprintf('INSERT INTO `%s` (`target_country`, `default_price`, `free_over_limit`, `is_enabled`) VALUES ("%s", "%.2f","%.2f", %s);',
- self::TABLE_NAME, $this->db->escape($ruleData[self::COLUMN_TARGET_COUNTRY]), (float) $ruleData[self::COLUMN_DEFAULT_PRICE],
- (float) $ruleData[self::COLUMN_FREE_OVER_LIMIT], (int) $ruleData[self::COLUMN_IS_ENABLED]);
- $this->db->query($sqlQuery);
-
- return '';
- }
-
- /**
- * Edit an existing rule for country.
- *
- * @param int $ruleId internal ID of changed rule
- * @param array $ruleData data of new rule from POST parameters
- * @return string identifier of error message, empty if no error occurred
- */
- public function editRule($ruleId, array $ruleData) {
- $errorMessage = $this->checkRuleData($ruleData, $ruleId);
- if (!empty($errorMessage)) {
- return $errorMessage;
- }
-
- $sqlQuery = sprintf('UPDATE `%s` SET `target_country`= "%s", `default_price` = "%.2f", `free_over_limit` = "%.2f", `is_enabled` = %s WHERE `rule_id` = %s',
- self::TABLE_NAME, $this->db->escape($ruleData[self::COLUMN_TARGET_COUNTRY]), (float) $ruleData[self::COLUMN_DEFAULT_PRICE],
- (float) $ruleData[self::COLUMN_FREE_OVER_LIMIT], (int) $ruleData[self::COLUMN_IS_ENABLED], (int) $ruleId);
- $this->db->query($sqlQuery);
-
- return '';
- }
-
- /**
- * Check content of weight rule data.
- *
- * @param array $ruleData data of new rule from POST parameters
- * @param int $ruleToIgnore ID of ignored rule (for change of rule)
- *
- * @return string identifier of error message, empty if no error occurred
- */
- public function checkRuleData(array $ruleData, $ruleToIgnore = 0) {
- // check if user has rights to modify setting
- if (!$this->user->hasPermission('modify', 'extension/shipping/zasilkovna')) {
- return self::ERROR_PERMISSION;
- }
-
- // check if defined country is allowed
- $country = $ruleData[self::COLUMN_TARGET_COUNTRY];
- if (!in_array($country, self::ALLOWED_COUNTRIES)) {
- return self::ERROR_INVALID_COUNTRY;
- }
-
- // check if defined price is valid positive integer number
- // both items are optional and can be empty
- if (!empty($ruleData[self::COLUMN_DEFAULT_PRICE])) {
- $defaultPrice = (int) $ruleData[self::COLUMN_DEFAULT_PRICE];
- if ($defaultPrice <= 0) {
- return self::ERROR_INVALID_PRICE;
- }
- }
-
- if (!empty($ruleData[self::COLUMN_FREE_OVER_LIMIT])) {
- $freeOverLimit = (int) $ruleData[self::COLUMN_FREE_OVER_LIMIT];
- if ($freeOverLimit <= 0) {
- return self::ERROR_INVALID_PRICE;
- }
- }
-
- // check if rule is rule for this country is already defined
- $sqlQuery = sprintf('SELECT * FROM `%s` WHERE `target_country`="%s"',
- self::TABLE_NAME, $this->db->escape($country));
- if ($ruleToIgnore > 0) {
- $sqlQuery .= ' AND `rule_id` <> ' . $ruleToIgnore;
- }
- /** @var StdClass $sqlResult */
- $sqlResult = $this->db->query($sqlQuery);
- if ($sqlResult->num_rows > 0) {
- return self::ERROR_DUPLICATE_COUNTRY_RULE;
- }
-
- return ''; // no error
- }
-
- /**
- * Delete an existing rules for country. All selected rules will be deleted.
- *
- * @param array $ruleIdList list of internal rule IDs
- * @return string identifier of error message, empty if no error occurred
- */
- public function deleteRules(array $ruleIdList) {
- // check if user has rights to modify setting
- if (!$this->user->hasPermission('modify', 'extension/shipping/zasilkovna')) {
- return self::ERROR_PERMISSION;
- }
-
- if (empty($ruleIdList)) { // check if list of rules to delete is not empty
- return '';
- }
-
- // convert array of rule IDs to list for sql command (including conversion to int)
- $sqlList = '';
- foreach ($ruleIdList as $ruleId) {
- $sqlList .= (int) $ruleId . ',';
- }
- $sqlList = substr($sqlList, 0, -1);
-
- $sqlQuery = sprintf('DELETE FROM %s WHERE `rule_id` IN (%s);', self::TABLE_NAME, $sqlList);
- $this->db->query($sqlQuery);
-
- return '';
- }
-
-}
\ No newline at end of file
+db->query($sqlQuery);
+
+ return $queryResult->rows;
+ }
+
+ /**
+ * Get content of rule.
+ *
+ * @param $ruleId int internal rule ID
+ * @return array content of rule
+ */
+ public function getRule($ruleId) {
+ $sqlQuery = sprintf('SELECT * FROM %s WHERE `rule_id` = %s', self::TABLE_NAME, (int) $ruleId);
+ /** @var StdClass $queryResult */
+ $queryResult = $this->db->query($sqlQuery);
+
+ return $queryResult->row;
+ }
+
+ /**
+ * Creates a new weight rule for country.
+ *
+ * @param array $ruleData data of new rule from POST parameters
+ * @return string identifier of error message, empty if no error occurred
+ */
+ public function addRule(array $ruleData) {
+ $checkErrorMessage = $this->checkRuleData($ruleData);
+ if (!empty($checkErrorMessage)) {
+ return $checkErrorMessage;
+ }
+
+ $sqlQuery = sprintf('INSERT INTO `%s` (`target_country`, `default_price`, `free_over_limit`, `is_enabled`) VALUES ("%s", "%.2f","%.2f", %s);',
+ self::TABLE_NAME, $this->db->escape($ruleData[self::COLUMN_TARGET_COUNTRY]), (float) $ruleData[self::COLUMN_DEFAULT_PRICE],
+ (float) $ruleData[self::COLUMN_FREE_OVER_LIMIT], (int) $ruleData[self::COLUMN_IS_ENABLED]);
+ $this->db->query($sqlQuery);
+
+ return '';
+ }
+
+ /**
+ * Edit an existing rule for country.
+ *
+ * @param int $ruleId internal ID of changed rule
+ * @param array $ruleData data of new rule from POST parameters
+ * @return string identifier of error message, empty if no error occurred
+ */
+ public function editRule($ruleId, array $ruleData) {
+ $errorMessage = $this->checkRuleData($ruleData, $ruleId);
+ if (!empty($errorMessage)) {
+ return $errorMessage;
+ }
+
+ $sqlQuery = sprintf('UPDATE `%s` SET `target_country`= "%s", `default_price` = "%.2f", `free_over_limit` = "%.2f", `is_enabled` = %s WHERE `rule_id` = %s',
+ self::TABLE_NAME, $this->db->escape($ruleData[self::COLUMN_TARGET_COUNTRY]), (float) $ruleData[self::COLUMN_DEFAULT_PRICE],
+ (float) $ruleData[self::COLUMN_FREE_OVER_LIMIT], (int) $ruleData[self::COLUMN_IS_ENABLED], (int) $ruleId);
+ $this->db->query($sqlQuery);
+
+ return '';
+ }
+
+ /**
+ * Check content of weight rule data.
+ *
+ * @param array $ruleData data of new rule from POST parameters
+ * @param int $ruleToIgnore ID of ignored rule (for change of rule)
+ *
+ * @return string identifier of error message, empty if no error occurred
+ */
+ public function checkRuleData(array $ruleData, $ruleToIgnore = 0) {
+ // check if user has rights to modify setting
+ if (!$this->user->hasPermission('modify', 'extension/shipping/zasilkovna')) {
+ return self::ERROR_PERMISSION;
+ }
+
+ // check if defined price is valid positive integer number
+ // both items are optional and can be empty
+ if (!empty($ruleData[self::COLUMN_DEFAULT_PRICE])) {
+ $defaultPrice = (int) $ruleData[self::COLUMN_DEFAULT_PRICE];
+ if ($defaultPrice <= 0) {
+ return self::ERROR_INVALID_PRICE;
+ }
+ }
+
+ if (!empty($ruleData[self::COLUMN_FREE_OVER_LIMIT])) {
+ $freeOverLimit = (int) $ruleData[self::COLUMN_FREE_OVER_LIMIT];
+ if ($freeOverLimit <= 0) {
+ return self::ERROR_INVALID_PRICE;
+ }
+ }
+
+ $country = $ruleData[self::COLUMN_TARGET_COUNTRY];
+
+ // check if rule is rule for this country is already defined
+ $sqlQuery = sprintf('SELECT * FROM `%s` WHERE `target_country`="%s"',
+ self::TABLE_NAME, $this->db->escape($country));
+ if ($ruleToIgnore > 0) {
+ $sqlQuery .= ' AND `rule_id` <> ' . $ruleToIgnore;
+ }
+ /** @var StdClass $sqlResult */
+ $sqlResult = $this->db->query($sqlQuery);
+ if ($sqlResult->num_rows > 0) {
+ return self::ERROR_DUPLICATE_COUNTRY_RULE;
+ }
+
+ return ''; // no error
+ }
+
+ /**
+ * Delete an existing rules for country. All selected rules will be deleted.
+ *
+ * @param array $ruleIdList list of internal rule IDs
+ * @return string identifier of error message, empty if no error occurred
+ */
+ public function deleteRules(array $ruleIdList) {
+ // check if user has rights to modify setting
+ if (!$this->user->hasPermission('modify', 'extension/shipping/zasilkovna')) {
+ return self::ERROR_PERMISSION;
+ }
+
+ if (empty($ruleIdList)) { // check if list of rules to delete is not empty
+ return '';
+ }
+
+ // convert array of rule IDs to list for sql command (including conversion to int)
+ $sqlList = '';
+ foreach ($ruleIdList as $ruleId) {
+ $sqlList .= (int) $ruleId . ',';
+ }
+ $sqlList = substr($sqlList, 0, -1);
+
+ $sqlQuery = sprintf('DELETE FROM %s WHERE `rule_id` IN (%s);', self::TABLE_NAME, $sqlList);
+ $this->db->query($sqlQuery);
+
+ return '';
+ }
+
+}
diff --git a/admin/model/extension/shipping/zasilkovna_weight_rules.php b/upload/admin/model/extension/shipping/zasilkovna_weight_rules.php
similarity index 87%
rename from admin/model/extension/shipping/zasilkovna_weight_rules.php
rename to upload/admin/model/extension/shipping/zasilkovna_weight_rules.php
index f9eaa15..957c7a5 100644
--- a/admin/model/extension/shipping/zasilkovna_weight_rules.php
+++ b/upload/admin/model/extension/shipping/zasilkovna_weight_rules.php
@@ -1,208 +1,210 @@
-= min_weight, < max_weight) */
- const COLUMN_PRICE = 'price';
-
- /** @var string country code for "other" countries */
- const COUNTRY_OTHER = 'other';
-
- /**
- * Returns list of rules for all countries.
- * First level is country code. Second level is list of rules for country.
- *
- * @return array list of rules
- */
- public function getAllRules() {
- $sqlQuery = sprintf('SELECT * FROM `%s` ORDER BY `target_country`, `min_weight`',self::TABLE_NAME);
- /** @var StdClass $queryResult */
- $queryResult = $this->db->query($sqlQuery);
-
- // conversion of flat list to two-dimensional array with rules for "other" countries as last item
- $result = [];
- $otherCountries = [];
- foreach ($queryResult->rows as $dbRow) {
- if (self::COUNTRY_OTHER === $dbRow[self::COLUMN_TARGET_COUNTRY]) {
- $otherCountries[] = $dbRow;
- }
- else {
- $result[$dbRow[self::COLUMN_TARGET_COUNTRY]]['items'][] = $dbRow;
- }
- }
- if (!empty($otherCountries)) {
- $result[self::COUNTRY_OTHER]['items'] = $otherCountries;
- }
- return $result;
- }
-
- /**
- * Returns list of rules for given country.
- *
- * @param $countryCode string iso code of target country
- * @return array list of rules
- */
- public function getRulesForCountry($countryCode) {
- $sqlQuery = sprintf('SELECT * FROM `%s` WHERE `target_country` = "%s" ORDER BY `min_weight`;',
- self::TABLE_NAME, $this->db->escape($countryCode));
-
- /** @var StdClass $queryResult */
- $queryResult = $this->db->query($sqlQuery);
- return $queryResult->rows;
- }
-
- /**
- * Get content of rule.
- *
- * @param $ruleId int internal rule ID
- * @return array content of rule
- */
- public function getRule($ruleId) {
- $sqlQuery = sprintf('SELECT * FROM %s WHERE `rule_id` = %s', self::TABLE_NAME, (int) $ruleId);
- /** @var StdClass $queryResult */
- $queryResult = $this->db->query($sqlQuery);
-
- return $queryResult->row;
- }
-
- /**
- * Creates a new weight rule for country.
- *
- * @param array $ruleData data of new rule from POST parameters
- * @param string $countryCode iso code of target country for new record
- * @return string identifier of error message, empty if no error occurred
- */
- public function addRule(array $ruleData, $countryCode) {
- $checkErrorMessage = $this->checkRuleData($ruleData, $countryCode);
- if (!empty($checkErrorMessage)) {
- return $checkErrorMessage;
- }
-
- $sqlQuery = sprintf('INSERT INTO `%s` (`target_country`, `min_weight`, `max_weight`, `price`) VALUES ("%s", %s, %s, "%.2f");',
- self::TABLE_NAME, $this->db->escape($countryCode), (int) $ruleData[self::COLUMN_MIN_WEIGHT],
- (int) $ruleData[self::COLUMN_MAX_WEIGHT], (float) $ruleData[self::COLUMN_PRICE]);
- $this->db->query($sqlQuery);
-
- return '';
- }
-
- /**
- * Edit an existing rule for country.
- *
- * @param int $ruleId internal ID of changed rule
- * @param array $ruleData data of new rule from POST parameters
- * @param string $countryCode iso code of target country for changed record
- * @return string identifier of error message, empty if no error occurred
- */
- public function editRule($ruleId, array $ruleData, $countryCode) {
- $ruleData[self::COLUMN_TARGET_COUNTRY] = $countryCode;
- $errorMessage = $this->checkRuleData($ruleData, $countryCode, $ruleId);
- if (!empty($errorMessage)) {
- return $errorMessage;
- }
-
- $sqlQuery = sprintf('UPDATE `%s` SET `min_weight`= %s, `max_weight` = %s, `price` = "%.2f" WHERE `rule_id` = %s',
- self::TABLE_NAME, (int) $ruleData[self::COLUMN_MIN_WEIGHT], (int) $ruleData[self::COLUMN_MAX_WEIGHT], (float) $ruleData[self::COLUMN_PRICE],
- (int) $ruleId);
- $this->db->query($sqlQuery);
-
- return '';
- }
-
- /**
- * Check content of weight rule data.
- *
- * @param array $ruleData data of new rule from POST parameters
- * @param string $countryCode iso code of target country for new record
- * @param int $ruleToIgnore ID of ignored rule (for change of rule)
- *
- * @return string identifier of error message, empty if no error occurred
- */
- public function checkRuleData(array $ruleData, $countryCode, $ruleToIgnore = 0) {
- // check if user has rights to modify setting
- if (!$this->user->hasPermission('modify', 'extension/shipping/zasilkovna')) {
- return self::ERROR_PERMISSION;
- }
-
- // check if weight and price is positive integer number including weight range
- $minWeight = (int) $ruleData[self::COLUMN_MIN_WEIGHT];
- $maxWeight = (int) $ruleData[self::COLUMN_MAX_WEIGHT];
- $price = (float) $ruleData[self::COLUMN_PRICE];
-
- if ($minWeight < 0 || $maxWeight <= 0) { // minimal weight can be 0
- return self::ERROR_INVALID_WEIGHT;
- }
-
- if ($minWeight >= $maxWeight) {
- return self::ERROR_INVALID_WEIGHT_RANGE;
- }
-
- if ($price <= 0) {
- return self::ERROR_INVALID_PRICE;
- }
-
- // check if rule is overlapping with any other rule
- $sqlQuery = sprintf('SELECT * FROM `%s` WHERE `min_weight`<%s AND `max_weight` > %s AND `target_country` = "%s"',
- self::TABLE_NAME, $maxWeight, $minWeight, $countryCode);
- if ($ruleToIgnore > 0) {
- $sqlQuery .= ' AND `rule_id` <> ' . $ruleToIgnore;
- }
- /** @var StdClass $sqlResult */
- $sqlResult = $this->db->query($sqlQuery);
- if ($sqlResult->num_rows > 0) {
- $errorMesage = sprintf(self::ERROR_RULES_OVERLAPPING, $sqlResult->row[self::COLUMN_MIN_WEIGHT],
- $sqlResult->row[self::COLUMN_MAX_WEIGHT]);
- return $errorMesage;
- }
-
- return ''; // no error
- }
-
- /**
- * Delete an existing rules for country. All selected rules will be deleted.
- *
- * @param array $ruleIdList list of internal rule IDs
- * @return string identifier of error message, empty if no error occurred
- */
- public function deleteRules(array $ruleIdList) {
- // check if user has rights to modify setting
- if (!$this->user->hasPermission('modify', 'extension/shipping/zasilkovna')) {
- return self::ERROR_PERMISSION;
- }
-
- if (empty($ruleIdList)) { // check if list of rules to delete is not empty
- return '';
- }
-
- // convert array of rule IDs to list for sql command (including conversion to int)
- $sqlList = '';
- foreach ($ruleIdList as $ruleId) {
- $sqlList .= (int) $ruleId . ',';
- }
- $sqlList = substr($sqlList, 0, -1);
-
- $sqlQuery = sprintf('DELETE FROM %s WHERE `rule_id` IN (%s);', self::TABLE_NAME, $sqlList);
- $this->db->query($sqlQuery);
-
- return '';
- }
+= min_weight, < max_weight) */
+ const COLUMN_PRICE = 'price';
+
+ /** @var string country code for "other" countries */
+ const COUNTRY_OTHER = 'other';
+
+ /**
+ * Returns list of rules for all countries.
+ * First level is country code. Second level is list of rules for country.
+ *
+ * @return array list of rules
+ */
+ public function getAllRules() {
+ $sqlQuery = sprintf('SELECT * FROM `%s` ORDER BY `target_country`, `min_weight`',self::TABLE_NAME);
+ /** @var StdClass $queryResult */
+ $queryResult = $this->db->query($sqlQuery);
+
+ // conversion of flat list to two-dimensional array with rules for "other" countries as last item
+ $result = [];
+ $otherCountries = [];
+ foreach ($queryResult->rows as $dbRow) {
+ if (self::COUNTRY_OTHER === $dbRow[self::COLUMN_TARGET_COUNTRY]) {
+ $otherCountries[] = $dbRow;
+ }
+ else {
+ $result[$dbRow[self::COLUMN_TARGET_COUNTRY]]['items'][] = $dbRow;
+ }
+ }
+ if (!empty($otherCountries)) {
+ $result[self::COUNTRY_OTHER]['items'] = $otherCountries;
+ }
+ return $result;
+ }
+
+ /**
+ * Returns list of rules for given country.
+ *
+ * @param $countryCode string iso code of target country
+ * @return array list of rules
+ */
+ public function getRulesForCountry($countryCode) {
+ $sqlQuery = sprintf('SELECT * FROM `%s` WHERE `target_country` = "%s" ORDER BY `min_weight`;',
+ self::TABLE_NAME, $this->db->escape($countryCode));
+
+ /** @var StdClass $queryResult */
+ $queryResult = $this->db->query($sqlQuery);
+ return $queryResult->rows;
+ }
+
+ /**
+ * Get content of rule.
+ *
+ * @param $ruleId int internal rule ID
+ * @return array content of rule
+ */
+ public function getRule($ruleId) {
+ $sqlQuery = sprintf('SELECT * FROM %s WHERE `rule_id` = %s', self::TABLE_NAME, (int) $ruleId);
+ /** @var StdClass $queryResult */
+ $queryResult = $this->db->query($sqlQuery);
+
+ return $queryResult->row;
+ }
+
+ /**
+ * Creates a new weight rule for country.
+ *
+ * @param array $ruleData data of new rule from POST parameters
+ * @param string $countryCode iso code of target country for new record
+ * @return string identifier of error message, empty if no error occurred
+ */
+ public function addRule(array $ruleData, $countryCode) {
+ $checkErrorMessage = $this->checkRuleData($ruleData, $countryCode);
+ if (!empty($checkErrorMessage)) {
+ return $checkErrorMessage;
+ }
+
+ $sqlQuery = sprintf(
+ 'INSERT INTO `%s` (`target_country`, `min_weight`, `max_weight`, `price`) VALUES ("%s", %s, %s, "%.2f");',
+ self::TABLE_NAME, $this->db->escape($countryCode), (float)$ruleData[self::COLUMN_MIN_WEIGHT],
+ (float)$ruleData[self::COLUMN_MAX_WEIGHT], (float)$ruleData[self::COLUMN_PRICE]);
+ $this->db->query($sqlQuery);
+
+ return '';
+ }
+
+ /**
+ * Edit an existing rule for country.
+ *
+ * @param int $ruleId internal ID of changed rule
+ * @param array $ruleData data of new rule from POST parameters
+ * @param string $countryCode iso code of target country for changed record
+ * @return string identifier of error message, empty if no error occurred
+ */
+ public function editRule($ruleId, array $ruleData, $countryCode) {
+ $ruleData[self::COLUMN_TARGET_COUNTRY] = $countryCode;
+ $errorMessage = $this->checkRuleData($ruleData, $countryCode, $ruleId);
+ if (!empty($errorMessage)) {
+ return $errorMessage;
+ }
+
+ $sqlQuery = sprintf(
+ 'UPDATE `%s` SET `min_weight`= %s, `max_weight` = %s, `price` = "%.2f" WHERE `rule_id` = %s',
+ self::TABLE_NAME, (float)$ruleData[self::COLUMN_MIN_WEIGHT],
+ (float)$ruleData[self::COLUMN_MAX_WEIGHT], (float)$ruleData[self::COLUMN_PRICE], (int)$ruleId);
+ $this->db->query($sqlQuery);
+
+ return '';
+ }
+
+ /**
+ * Check content of weight rule data.
+ *
+ * @param array $ruleData data of new rule from POST parameters
+ * @param string $countryCode iso code of target country for new record
+ * @param int $ruleToIgnore ID of ignored rule (for change of rule)
+ *
+ * @return string identifier of error message, empty if no error occurred
+ */
+ public function checkRuleData(array $ruleData, $countryCode, $ruleToIgnore = 0) {
+ // check if user has rights to modify setting
+ if (!$this->user->hasPermission('modify', 'extension/shipping/zasilkovna')) {
+ return self::ERROR_PERMISSION;
+ }
+
+ // check if weight and price is positive integer number including weight range
+ $minWeight = (float)$ruleData[self::COLUMN_MIN_WEIGHT];
+ $maxWeight = (float)$ruleData[self::COLUMN_MAX_WEIGHT];
+ $price = (float) $ruleData[self::COLUMN_PRICE];
+
+ if ($minWeight < 0 || $maxWeight <= 0) { // minimal weight can be 0
+ return self::ERROR_INVALID_WEIGHT;
+ }
+
+ if ($minWeight >= $maxWeight) {
+ return self::ERROR_INVALID_WEIGHT_RANGE;
+ }
+
+ if ($price <= 0) {
+ return self::ERROR_INVALID_PRICE;
+ }
+
+ // check if rule is overlapping with any other rule
+ $sqlQuery = sprintf('SELECT * FROM `%s` WHERE `min_weight`<%s AND `max_weight` > %s AND `target_country` = "%s"',
+ self::TABLE_NAME, $maxWeight, $minWeight, $countryCode);
+ if ($ruleToIgnore > 0) {
+ $sqlQuery .= ' AND `rule_id` <> ' . $ruleToIgnore;
+ }
+ /** @var StdClass $sqlResult */
+ $sqlResult = $this->db->query($sqlQuery);
+ if ($sqlResult->num_rows > 0) {
+ $errorMesage = sprintf(self::ERROR_RULES_OVERLAPPING, $sqlResult->row[self::COLUMN_MIN_WEIGHT],
+ $sqlResult->row[self::COLUMN_MAX_WEIGHT]);
+ return $errorMesage;
+ }
+
+ return ''; // no error
+ }
+
+ /**
+ * Delete an existing rules for country. All selected rules will be deleted.
+ *
+ * @param array $ruleIdList list of internal rule IDs
+ * @return string identifier of error message, empty if no error occurred
+ */
+ public function deleteRules(array $ruleIdList) {
+ // check if user has rights to modify setting
+ if (!$this->user->hasPermission('modify', 'extension/shipping/zasilkovna')) {
+ return self::ERROR_PERMISSION;
+ }
+
+ if (empty($ruleIdList)) { // check if list of rules to delete is not empty
+ return '';
+ }
+
+ // convert array of rule IDs to list for sql command (including conversion to int)
+ $sqlList = '';
+ foreach ($ruleIdList as $ruleId) {
+ $sqlList .= (int) $ruleId . ',';
+ }
+ $sqlList = substr($sqlList, 0, -1);
+
+ $sqlQuery = sprintf('DELETE FROM %s WHERE `rule_id` IN (%s);', self::TABLE_NAME, $sqlList);
+ $this->db->query($sqlQuery);
+
+ return '';
+ }
}
\ No newline at end of file
diff --git a/admin/view/template/extension/shipping/zasilkovna.twig b/upload/admin/view/template/extension/shipping/zasilkovna.twig
similarity index 94%
rename from admin/view/template/extension/shipping/zasilkovna.twig
rename to upload/admin/view/template/extension/shipping/zasilkovna.twig
index bfbb40b..25ca914 100644
--- a/admin/view/template/extension/shipping/zasilkovna.twig
+++ b/upload/admin/view/template/extension/shipping/zasilkovna.twig
@@ -1,279 +1,297 @@
-{{ header }}{{ column_left }}
-
{{ footer }}
\ No newline at end of file
diff --git a/admin/view/template/extension/shipping/zasilkovna_shipping_rules_form.twig b/upload/admin/view/template/extension/shipping/zasilkovna_shipping_rules_form.twig
similarity index 98%
rename from admin/view/template/extension/shipping/zasilkovna_shipping_rules_form.twig
rename to upload/admin/view/template/extension/shipping/zasilkovna_shipping_rules_form.twig
index 4fba38c..380487b 100644
--- a/admin/view/template/extension/shipping/zasilkovna_shipping_rules_form.twig
+++ b/upload/admin/view/template/extension/shipping/zasilkovna_shipping_rules_form.twig
@@ -1,66 +1,66 @@
-{{ header }}{{ column_left }}
-
{{ footer }}
\ No newline at end of file
diff --git a/admin/view/template/extension/shipping/zasilkovna_shipping_rules_list.twig b/upload/admin/view/template/extension/shipping/zasilkovna_shipping_rules_list.twig
similarity index 97%
rename from admin/view/template/extension/shipping/zasilkovna_shipping_rules_list.twig
rename to upload/admin/view/template/extension/shipping/zasilkovna_shipping_rules_list.twig
index 6ec8260..ff130c4 100644
--- a/admin/view/template/extension/shipping/zasilkovna_shipping_rules_list.twig
+++ b/upload/admin/view/template/extension/shipping/zasilkovna_shipping_rules_list.twig
@@ -1,74 +1,74 @@
-{{ header }}{{ column_left }}
-
{{ footer }}
\ No newline at end of file
diff --git a/admin/view/template/extension/shipping/zasilkovna_weight_rules.twig b/upload/admin/view/template/extension/shipping/zasilkovna_weight_rules.twig
similarity index 97%
rename from admin/view/template/extension/shipping/zasilkovna_weight_rules.twig
rename to upload/admin/view/template/extension/shipping/zasilkovna_weight_rules.twig
index 8f440b2..94040d2 100644
--- a/admin/view/template/extension/shipping/zasilkovna_weight_rules.twig
+++ b/upload/admin/view/template/extension/shipping/zasilkovna_weight_rules.twig
@@ -1,70 +1,71 @@
-{{ header }}{{ column_left }}
-
{{ footer }}
\ No newline at end of file
diff --git a/admin/view/template/extension/shipping/zasilkovna_weight_rules_form.twig b/upload/admin/view/template/extension/shipping/zasilkovna_weight_rules_form.twig
similarity index 84%
rename from admin/view/template/extension/shipping/zasilkovna_weight_rules_form.twig
rename to upload/admin/view/template/extension/shipping/zasilkovna_weight_rules_form.twig
index 986f6e6..a0c2fb2 100644
--- a/admin/view/template/extension/shipping/zasilkovna_weight_rules_form.twig
+++ b/upload/admin/view/template/extension/shipping/zasilkovna_weight_rules_form.twig
@@ -1,51 +1,52 @@
-{{ header }}{{ column_left }}
-
';
- var selectedPointElement;
- var additionalElementsEnvelope;
- var shippingElementEnvelope;
-
- // create envelope element with required additional html elements
- additionalElementsEnvelope = document.createElement('div');
- additionalElementsEnvelope.setAttribute('id', 'packeta-envelope');
- additionalElementsEnvelope.innerHTML = additionalElementsHtml;
- document.body.appendChild(additionalElementsEnvelope);
-
- // Adding additional visible element for display information about selected pickup point.
- // Search for dummy element of "zasilkovna" shipping item is required because there is no id nor class which can
- // be used for identification
- shippingElementEnvelope = $('#packeta-first-shipping-item').parent().parent();
- selectedPointElement = document.createElement('div');
- selectedPointElement.setAttribute('class', 'packeta-shipping-item-envelope');
- selectedPointElement.innerHTML = selectedPointElementHtml;
- shippingElementEnvelope.append(selectedPointElement);
-
- // adding onclick handler for radio buttons with list of shipping methods
- $('input[name="shipping_method"]:radio').click(zasilkovnaShipmentMethodOnChange);
-}
-
-/**
- * Handler for change of shipping type (click on radio button)
- */
-function zasilkovnaShipmentMethodOnChange() {
- // check if radio button for zasilkovna is selected
- var isZasilkovnaSelected = $(this).val().match('zasilkovna.*') !== null;
- var selectedBranch = $('#packeta-branch-id').val();
- var isSubmitButtonDisabled = false;
-
- // disable "Continue" button if zasilkovna is selected but no branch is selected from map widget
- isSubmitButtonDisabled = false;
- if (isZasilkovnaSelected) {
- if (selectedBranch === '') {
- isSubmitButtonDisabled = true;
- }
- }
-
- $('#button-shipping-method').attr('disabled', isSubmitButtonDisabled);
-}
-
-/**
- * Handler for load of selected branch from session.
- * It is called after initialization of additional HTML elements and JS events during after switch to "Step 4: Delivery Method"
- * during "checkout".
- */
-function zasilkovnaLoadSelectedBranch() {
- $.ajax({
- url: 'index.php?route=extension/module/zasilkovna/loadSelectedBranch',
- type: 'get',
- dataType: 'json',
- success: function(json) {
- if (json.zasilkovna_branch_id !== '') {
- $('#packeta-branch-id').val(json.zasilkovna_branch_id);
- $('#packeta-branch-name').val(json.zasilkovna_branch_name);
- $('#picked-delivery-place').html(json.zasilkovna_branch_description);
- }
- zasilkovnaUpdateSubmitButtonStatus();
- },
- error: function(xhr, ajaxOptions, thrownError) {
- alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
- }
- });
-}
-
-/**
- * Sets status of "Continue" button according to selected shipping properties.
- * Button "Continue" is disabled when "zasilkovna" is selected ad shipping method and target branch is not selected.
- */
-function zasilkovnaUpdateSubmitButtonStatus() {
- var selectedShipment = $('#collapse-shipping-method input[type=\'radio\']:checked');
- var isZasilkovnaSelected = selectedShipment.val().match('zasilkovna.*') !== null;
- var selectedBranchId = $('#packeta-branch-id').val();
-
- $('#button-shipping-method').attr('disabled', (isZasilkovnaSelected && selectedBranchId === ''));
-}
-
-/**
- * Handler for save selected branch to session.
- * It it called after click on "Continue" button in "Step 4: Delivery Method". Another ajax request for save
- * selected shipping method and comment is sent at the same time.
- */
-function zasilkovnaSaveSelectedBranch() {
- var branchId = $('#packeta-branch-id').val(),
- dataToSend;
-
- dataToSend = {
- zasilkovna_branch_id: branchId,
- zasilkovna_branch_name: $('#packeta-branch-name').val(),
- zasilkovna_branch_description: $('#picked-delivery-place').html()
- };
-
- $.ajax({
- url: 'index.php?route=extension/module/zasilkovna/saveSelectedBranch',
- type: 'post',
- data: dataToSend,
- success: function() {
- // enable "Continue" button for switch to next step in "checkout workflow"
- $('#button-shipping-method').attr('disabled', false);
- // mark carrier "Zasilkovna" as active when pickup point is selected
- $('#packeta-first-shipping-item').parent().parent().find('input[type=radio]').prop('checked', true);
- },
- error: function(xhr, ajaxOptions, thrownError) {
- alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
- }
- });
-}
-
-/**
- * helper function for library to choose delivery point using map widget
- * defined as function because it must be called when all required elements are created in DOM
- */
-function initializePacketaWidget() {
- // list of configuration properties for widget
- var apiKey = window.zasilkovnaWidgetParameters.apiKey;
-
-
- // preparation of parameters for widget
- var widgetOptions = {
- appIdentity: window.zasilkovnaWidgetParameters.appIdentity,
- country: window.zasilkovnaWidgetParameters.enabledCountries,
- language: window.zasilkovnaWidgetParameters.language
- };
-
- document.getElementById('open-packeta-widget').addEventListener('click', function (e) {
- e.preventDefault();
- // displaying of map widget
- Packeta.Widget.pick(apiKey, selectPickUpPointCallback, widgetOptions);
- });
-
-}
-
-/**
- * Callback function for processing of pickup point selection using map widget.
- * It is called by widget with object "ExtendedPoint" as parameter.
- *
- * @param targetPoint detail information about selected point
- * @return void
- */
-function selectPickUpPointCallback(targetPoint) {
- if (null == targetPoint) { // selection of pickup point was cancelled
- return;
- }
-
- // save ID and name of selected point point to hidden input elements
- document.getElementById('packeta-branch-id').value = targetPoint.id;
- document.getElementById('packeta-branch-name').value = targetPoint.nameStreet;
-
- // show name of selected pickup point to user
- document.getElementById('picked-delivery-place').innerHTML = targetPoint.nameStreet;
-
- // Save selected branch to session. It must be done now because it it not possible to send two ajax requests after click
- // on "Continue" button. There is conflict if two php script wants to save to session. Session data saved by first script
- // can be overwritten by second script.
- // Button "Continue" is enabled when request is finished to avoid conflict described above.
- zasilkovnaSaveSelectedBranch();
-}
+// helper function used for shipping extension for zasilkovna
+
+// add new cart here 3/3
+var cartsConfig = {
+ urls: {
+ standard: /checkout\/shipping_method/,
+ journal3: /journal3\/checkout/,
+ },
+ buttons: {
+ standard: '#button-shipping-method',
+ journal3: '#quick-checkout-button-confirm'
+ },
+};
+
+var $widgetButton = false;
+
+$(function() {
+ /**
+ * Initialization of all required parts.
+ * Called every time ajax call finishes, several times for both classic and journal checkout
+ */
+ $(document).ajaxSuccess(function(e, xhr, settings) {
+ var isFetchShippingMethodUrl = false;
+ for (var cartType in cartsConfig['urls']) {
+ if (settings.url.match(cartsConfig['urls'][cartType]) !== null) {
+ isFetchShippingMethodUrl = true;
+ break;
+ }
+ }
+
+ if (! isFetchShippingMethodUrl) {
+ return;
+ }
+
+ $('#packeta-envelope, .packeta-shipping-item-envelope').remove();
+
+ $widgetButton = $('#packeta-first-shipping-item');
+ if (!$widgetButton.length) {
+ return;
+ }
+
+ zasilkovnaCreateElementsandEvents();
+ initializePacketaWidget();
+ zasilkovnaLoadSelectedBranch();
+ });
+
+});
+
+/**
+ * Initialization of required elements and events.
+ */
+function zasilkovnaCreateElementsandEvents() {
+ var additionalElementsHtml = ''
+ + ''
+ + ''
+ + '';
+ var selectedPointElementHtml = '
';
+ var selectedPointElement;
+ var additionalElementsEnvelope;
+ var shippingElementEnvelope;
+
+ // create envelope element with required additional html elements
+ additionalElementsEnvelope = document.createElement('div');
+ additionalElementsEnvelope.setAttribute('id', 'packeta-envelope');
+ additionalElementsEnvelope.innerHTML = additionalElementsHtml;
+ document.body.appendChild(additionalElementsEnvelope);
+
+ // Adding additional visible element for display information about selected pickup point.
+ // Search for dummy element of "zasilkovna" shipping item is required because there is no id nor class which can
+ // be used for identification
+ shippingElementEnvelope = $widgetButton.parent().parent();
+ selectedPointElement = document.createElement('div');
+ selectedPointElement.setAttribute('class', 'packeta-shipping-item-envelope');
+ selectedPointElement.innerHTML = selectedPointElementHtml;
+ shippingElementEnvelope.append(selectedPointElement);
+
+ // adding onclick handler for radio buttons with list of shipping methods
+ $('input[name="shipping_method"]:radio').click(zasilkovnaShipmentMethodOnChange);
+ // for case it's selected
+ zasilkovnaShipmentMethodOnChange();
+}
+
+/**
+ * Handler for change of shipping type (click on radio button)
+ */
+function zasilkovnaShipmentMethodOnChange() {
+ // check if radio button for zasilkovna is selected
+ var isZasilkovnaSelected = detectPacketeryShippingMethod();
+ var selectedBranch = $('#packeta-branch-id').val();
+ var isSubmitButtonDisabled = false;
+
+ // disable "Continue" button if zasilkovna is selected but no branch is selected from map widget
+ isSubmitButtonDisabled = false;
+ if (isZasilkovnaSelected) {
+ if (selectedBranch === '') {
+ isSubmitButtonDisabled = true;
+ }
+ }
+
+ getConfirmationButton().attr('disabled', isSubmitButtonDisabled);
+}
+
+function detectPacketeryShippingMethod() {
+ return $("input[name='shipping_method'][value^='zasilkovna.']:checked").length === 1;
+}
+
+function getConfirmationButton() {
+ for (var cartType in cartsConfig['buttons']) {
+ var $element = $(cartsConfig['buttons'][cartType]);
+ if ($element.length) {
+ return $element;
+ }
+ }
+
+ console.error('No supported confirmation button found.');
+ return null;
+}
+
+/**
+ * Handler for load of selected branch from session.
+ * It is called after initialization of additional HTML elements and JS events during after switch to "Step 4: Delivery Method"
+ * during "checkout".
+ */
+function zasilkovnaLoadSelectedBranch() {
+ $.ajax({
+ url: 'index.php?route=extension/module/zasilkovna/loadSelectedBranch',
+ type: 'get',
+ dataType: 'json',
+ success: function(json) {
+ if (json.zasilkovna_branch_id !== '') {
+ $('#packeta-branch-id').val(json.zasilkovna_branch_id);
+ $('#packeta-branch-name').val(json.zasilkovna_branch_name);
+ $('#picked-delivery-place').html(json.zasilkovna_branch_description);
+ $('#packeta-carrier-id').val(json.zasilkovna_carrier_id);
+ $('#packeta-carrier-pickup-point').val(json.zasilkovna_carrier_pickup_point);
+ }
+ zasilkovnaUpdateSubmitButtonStatus();
+ },
+ error: function(xhr, ajaxOptions, thrownError) {
+ alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
+ }
+ });
+}
+
+/**
+ * Sets status of "Continue" button according to selected shipping properties.
+ * Button "Continue" is disabled when "zasilkovna" is selected ad shipping method and target branch is not selected.
+ */
+function zasilkovnaUpdateSubmitButtonStatus() {
+ var selectedShipment = $('#collapse-shipping-method input[type=\'radio\']:checked');
+ var isZasilkovnaSelected = detectPacketeryShippingMethod();
+ var selectedBranchId = $('#packeta-branch-id').val();
+
+ getConfirmationButton().attr('disabled', (isZasilkovnaSelected && selectedBranchId === ''));
+}
+
+/**
+ * Handler for save selected branch to session.
+ * It it called after click on "Continue" button in "Step 4: Delivery Method". Another ajax request for save
+ * selected shipping method and comment is sent at the same time.
+ */
+function zasilkovnaSaveSelectedBranch() {
+ var branchId = $('#packeta-branch-id').val(),
+ dataToSend;
+
+ dataToSend = {
+ zasilkovna_branch_id: branchId,
+ zasilkovna_branch_name: $('#packeta-branch-name').val(),
+ zasilkovna_branch_description: $('#picked-delivery-place').html(),
+ zasilkovna_carrier_id: $('#packeta-carrier-id').val(),
+ zasilkovna_carrier_pickup_point: $('#packeta-carrier-pickup-point').val()
+ };
+
+ $.ajax({
+ url: 'index.php?route=extension/module/zasilkovna/saveSelectedBranch',
+ type: 'post',
+ data: dataToSend,
+ success: function() {
+ // enable "Continue" button for switch to next step in "checkout workflow"
+ getConfirmationButton().attr('disabled', false);
+ // mark carrier "Zasilkovna" as active when pickup point is selected
+ $widgetButton.parent().parent().find('input[type=radio]').prop('checked', true);
+ },
+ error: function(xhr, ajaxOptions, thrownError) {
+ alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
+ }
+ });
+}
+
+/**
+ * helper function for library to choose delivery point using map widget
+ * defined as function because it must be called when all required elements are created in DOM
+ */
+function initializePacketaWidget() {
+ // list of configuration properties for widget
+ var apiKey = $widgetButton.data('api_key');
+
+ // preparation of parameters for widget
+ var widgetOptions = {
+ appIdentity: $widgetButton.data('app_identity'),
+ country: $widgetButton.data('enabled_countries'),
+ language: $widgetButton.data('language')
+ };
+
+ document.getElementById('open-packeta-widget').addEventListener('click', function (e) {
+ e.preventDefault();
+ // displaying of map widget
+ Packeta.Widget.pick(apiKey, selectPickUpPointCallback, widgetOptions);
+ });
+
+}
+
+/**
+ * Callback function for processing of pickup point selection using map widget.
+ * It is called by widget with object "ExtendedPoint" as parameter.
+ *
+ * @param targetPoint detail information about selected point
+ * @return void
+ */
+function selectPickUpPointCallback(targetPoint) {
+ if (null == targetPoint) { // selection of pickup point was cancelled
+ return;
+ }
+
+ // save ID and name of selected point point to hidden input elements
+ document.getElementById('packeta-branch-id').value = targetPoint.pickupPointType === 'external' ? targetPoint.carrierId : targetPoint.id;
+ document.getElementById('packeta-branch-name').value = targetPoint.nameStreet;
+ document.getElementById('packeta-carrier-id').value = targetPoint.carrierId ? targetPoint.carrierId : '';
+ document.getElementById('packeta-carrier-pickup-point').value = targetPoint.carrierPickupPointId ? targetPoint.carrierPickupPointId : '';
+
+ // show name of selected pickup point to user
+ document.getElementById('picked-delivery-place').innerHTML = targetPoint.nameStreet;
+
+ // Save selected branch to session. It must be done now because it it not possible to send two ajax requests after click
+ // on "Continue" button. There is conflict if two php script wants to save to session. Session data saved by first script
+ // can be overwritten by second script.
+ // Button "Continue" is enabled when request is finished to avoid conflict described above.
+ zasilkovnaSaveSelectedBranch();
+}
diff --git a/catalog/view/stylesheet/zasilkovna/zasilkovna.css b/upload/catalog/view/theme/zasilkovna/zasilkovna.css
similarity index 93%
rename from catalog/view/stylesheet/zasilkovna/zasilkovna.css
rename to upload/catalog/view/theme/zasilkovna/zasilkovna.css
index c48b002..cee7ff1 100644
--- a/catalog/view/stylesheet/zasilkovna/zasilkovna.css
+++ b/upload/catalog/view/theme/zasilkovna/zasilkovna.css
@@ -1,7 +1,7 @@
-.packeta-shipping-item-envelope {
- padding-left: 20px;
-}
-
-#picked-delivery-place {
- padding-top: 5px;
-}
\ No newline at end of file
+.packeta-shipping-item-envelope {
+ padding-left: 20px;
+}
+
+#picked-delivery-place {
+ padding-top: 5px;
+}
diff --git a/catalog/view/image/zasilkovna.jpg b/upload/catalog/view/theme/zasilkovna/zasilkovna.jpg
similarity index 100%
rename from catalog/view/image/zasilkovna.jpg
rename to upload/catalog/view/theme/zasilkovna/zasilkovna.jpg