Subida del módulo y tema de PrestaShop

This commit is contained in:
Kaloyan
2026-04-09 18:31:51 +02:00
parent 12c253296f
commit 16b3ff9424
39262 changed files with 7418797 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
# Apache 2.2
<IfModule !mod_authz_core.c>
<Files *.php>
order allow,deny
deny from all
</Files>
</IfModule>
# Apache 2.4
<IfModule mod_authz_core.c>
<Files *.php>
Require all denied
</Files>
</IfModule>

View File

@@ -0,0 +1,47 @@
Academic Free License ("AFL") v. 3.0
This Academic Free License (the “License”) applies to any original work of authorship (the “Original Work”) whose owner (the “Licensor”) has placed the following licensing notice adjacent to the copyright notice for the Original Work:
Licensed under the Academic Free License version 3.0
1) Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following:
a) to reproduce the Original Work in copies, either alone or as part of a collective work;
b) to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works (“Derivative Works”) based upon the Original Work;
c) to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensors reserved rights and remedies, in this Academic Free License;
d) to perform the Original Work publicly; and
e) to display the Original Work publicly.
2) Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works.
3) Grant of Source Code License. The term “Source Code” means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work.
4) Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensors trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license.
5) External Deployment. The term “External Deployment” means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c).
6) Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an “Attribution Notice.” You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an “AS IS” BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer.
8) Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation.
9) Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including “fair use” or “fair dealing”). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c).
10) Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License.
12) Attorneys Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
13) Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
14) Definition of “You” in This License. “You” throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, “control” means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
15) Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
16) Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the “Modified License”) and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the “Academic Free License” or “AFL” and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice “Licensed under <insert your license name here>” or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process.

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<module>
<name>psshipping</name>
<displayName><![CDATA[PrestaShop Shipping]]></displayName>
<version><![CDATA[2.1.1]]></version>
<description><![CDATA[Powered by Mail Boxes Etc, PrestaShop Shipping offers standard, pickup-point and express international delivery methods to your customers no matter where they are located.
Have access to exclusive rates for each delivered and returned parcels by using our extensive network of trusted partners.]]></description>
<author><![CDATA[PrestaShop]]></author>
<tab><![CDATA[shipping_logistics]]></tab>
<confirmUninstall><![CDATA[Are you sure you want to uninstall PrestaShop Shipping module?]]></confirmUninstall>
<is_configurable>1</is_configurable>
<need_instance>0</need_instance>
</module>

View File

@@ -0,0 +1,13 @@
services:
_defaults:
public: true
ps_accounts.installer:
class: 'PrestaShop\PsAccountsInstaller\Installer\Installer'
arguments:
- "5.0"
ps_accounts.facade:
class: 'PrestaShop\PsAccountsInstaller\Installer\Facade\PsAccounts'
arguments:
- "@ps_accounts.installer"

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,2 @@
imports:
- { resource: ./../services.yml }

View File

@@ -0,0 +1,23 @@
services:
_defaults:
public: true
psshipping.ps_billings_context_wrapper:
class: 'PrestaShopCorp\Billing\Wrappers\BillingContextWrapper'
arguments:
- '@ps_accounts.facade'
- '@psshipping.context'
- "%psshipping.ps_billing_sandbox%"
psshipping.ps_billings_facade:
class: 'PrestaShopCorp\Billing\Presenter\BillingPresenter'
arguments:
- '@psshipping.ps_billings_context_wrapper'
- '@psshipping'
# Remove this if you do not need BillingService
psshipping.ps_billings_service:
class: 'PrestaShopCorp\Billing\Services\BillingService'
arguments:
- '@psshipping.ps_billings_context_wrapper'
- '@psshipping'

View File

@@ -0,0 +1,13 @@
services:
_defaults:
public: true
PrestaShop\Module\Psshipping\Domain\Carriers\MbeStandardCarrierConfiguration:
class: 'PrestaShop\Module\Psshipping\Domain\Carriers\MbeStandardCarrierConfiguration'
arguments:
- 'prestashop.core.command_bus'
PrestaShop\Module\Psshipping\Domain\Carriers\MbePickupCarrierConfiguration:
class: 'PrestaShop\Module\Psshipping\Domain\Carriers\MbePickupCarrierConfiguration'
arguments:
- 'prestashop.core.command_bus'

View File

@@ -0,0 +1,33 @@
services:
_defaults:
public: true
PrestaShop\Module\Psshipping\Controller\Admin\PsshippingHomeController:
class: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingHomeController'
arguments:
- '@psshipping'
PrestaShop\Module\Psshipping\Controller\Admin\PsshippingCarrierController:
class: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingCarrierController'
arguments:
- '@psshipping'
- '@PrestaShop\Module\Psshipping\Domain\Carriers\CarrierService'
PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController:
class: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController'
arguments:
- '@psshipping'
PrestaShop\Module\Psshipping\Controller\Admin\PsshippingKeycloakAuthController:
class: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingKeycloakAuthController'
PrestaShop\Module\Psshipping\Controller\Admin\PsshippingFaqController:
class: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingFaqController'
arguments:
- '@psshipping'
PrestaShop\Module\Psshipping\Controller\Admin\PsshippingOrdersController:
class: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingOrdersController'
arguments:
- '@psshipping'
- '@PrestaShop\Module\Psshipping\Domain\Carriers\CarrierService'

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,2 @@
imports:
- { resource: ./../services.yml }

View File

@@ -0,0 +1,8 @@
services:
_defaults:
public: true
PrestaShop\Module\Psshipping\Domain\GelProximity\GelProximityService:
class: 'PrestaShop\Module\Psshipping\Domain\GelProximity\GelProximityService'
arguments:
- '@psshipping'

View File

@@ -0,0 +1,6 @@
services:
_defaults:
public: true
PrestaShop\Module\Psshipping\Handler\ErrorHandler:
class: PrestaShop\Module\Psshipping\Handler\ErrorHandler

View File

@@ -0,0 +1,42 @@
services:
_defaults:
public: true
PrestaShop\Module\Psshipping\Hooks\HookActionObjectCarrierUpdateAfter:
class: 'PrestaShop\Module\Psshipping\Hooks\HookActionObjectCarrierUpdateAfter'
arguments:
- '@psshipping'
- '@PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository'
- '@PrestaShop\Module\Psshipping\Domain\Orders\OrdersRepository'
PrestaShop\Module\Psshipping\Hooks\HookDisplayCarrierExtraContent:
class: 'PrestaShop\Module\Psshipping\Hooks\HookDisplayCarrierExtraContent'
arguments:
- '@psshipping'
- '@PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository'
- '@psshipping.context'
PrestaShop\Module\Psshipping\Hooks\HookDisplayHeader:
class: 'PrestaShop\Module\Psshipping\Hooks\HookDisplayHeader'
arguments:
- '@psshipping'
- '@PrestaShop\Module\Psshipping\Domain\GelProximity\GelProximityService'
- '@PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository'
- '@psshipping.context'
- "%psshipping.gel_proximity.end_user_url%"
PrestaShop\Module\Psshipping\Hooks\HookActionValidateOrder:
class: 'PrestaShop\Module\Psshipping\Hooks\HookActionValidateOrder'
arguments:
- '@PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository'
- '@PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressRepository'
- '@PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressOrdersRepository'
- '@psshipping.context'
PrestaShop\Module\Psshipping\Hooks\HookDisplayOrderConfirmation:
class: 'PrestaShop\Module\Psshipping\Hooks\HookDisplayOrderConfirmation'
arguments:
- '@psshipping'
- '@PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository'
- '@PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressOrdersRepository'
- '@psshipping.context'

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,18 @@
parameters:
psshipping.sentry_dsn: "https://78c41abf489931010a3a83cacc14926b@o298402.ingest.sentry.io/4505906299600896"
psshipping.sentry_env: "production"
# Either or not using a billing stub
psshipping.ps_billing_sandbox: 0
# URL to communicate with psshipping APIs
psshipping.api_url: 'https://shipping-api.prestashop.com'
# URL to load CDC cloudsync
psshipping.cloudsync_cdc_url: 'https://assets.prestashop3.com/ext/cloudsync-merchant-sync-consent/latest/cloudsync-cdc.js'
psshipping.mbe_tracking_url: "https://www.mbe.it/en/tracking?c=@"
psshipping.segment_key: "3XsHeI2dfKoKE2wReGp7IO2bLa5hbeVB"
psshipping.gel_proximity.end_user_url: 'https://platform.gelproximity.com/gel-enduser-client/'

View File

@@ -0,0 +1,23 @@
services:
_defaults:
public: true
PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository:
class: 'PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository'
arguments:
- '@psshipping'
PrestaShop\Module\Psshipping\Domain\Orders\OrdersRepository:
class: 'PrestaShop\Module\Psshipping\Domain\Orders\OrdersRepository'
arguments:
- '@psshipping'
PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressRepository:
class: 'PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressRepository'
arguments:
- '@psshipping'
PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressOrdersRepository:
class: 'PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressOrdersRepository'
arguments:
- '@psshipping'

View File

@@ -0,0 +1,175 @@
home:
path: /psshipping
methods: [GET, POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingHomeController::renderApp'
_legacy_controller: PsshippingHomeController
_legacy_link: PsshippingHomeController
register_hooks:
path: /psshipping/hooks
methods: [POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingHomeController::activateHooks'
_legacy_controller: PsshippingHomeController
_legacy_link: PsshippingHomeController
carrier_create:
path: /psshipping/carrier/create
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingCarrierController::createAction'
_legacy_controller: PsshippingCarrierController
_legacy_link: PsshippingCarrierController
carrier_list:
path: /psshipping/carrier
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingCarrierController::listAction'
_legacy_controller: PsshippingCarrierController
_legacy_link: PsshippingCarrierController
carrier_toggle_status:
path: /psshipping/carrier/toggle-status
methods: [GET, POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingCarrierController::toggleStatusAction'
_legacy_controller: PsshippingCarrierController
_legacy_link: PsshippingCarrierController
carrier_admin_link:
path: /psshipping/carrier/admin-link
methods: [GET, POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingCarrierController::getAdminLinkAction'
_legacy_controller: PsshippingCarrierController
_legacy_link: PsshippingCarrierController
onboarding_toggle_status:
path: /psshipping/onboarding/toggle-status
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController::toggleOnboardingStatusAction'
_legacy_controller: PsshippingConfigurationController
_legacy_link: PsshippingConfigurationController
get_states:
path: /psshipping/configuration/get-states
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController::getStates'
_legacy_controller: PsshippingConfigurationController
_legacy_link: PsshippingConfigurationController
callback_oauth_keycloak:
path: /psshipping/keycloak/oauth
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingKeycloakAuthController::oauthCallback'
_legacy_controller: PsshippingKeycloakAuthController
_legacy_link: PsshippingKeycloakAuthController
list_orders:
path: /psshipping/orders
methods: [POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingOrdersController::listOrdersAction'
_legacy_controller: PsshippingOrdersController
_legacy_link: PsshippingOrdersController
get_orders_status:
path: /psshipping/orders-status
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingOrdersController::getOrdersStatusAction'
_legacy_controller: PsshippingOrdersController
_legacy_link: PsshippingOrdersController
get_last_tracking_number:
path: /psshipping/orders/last_tracking_number
methods: [POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingOrdersController::getTrackingNumberAction'
_legacy_controller: PsshippingOrdersController
_legacy_link: PsshippingOrdersController
save_tracking_number:
path: /psshipping/orders/trackingNumber
methods: [POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingOrdersController::saveTrackingNumberAction'
_legacy_controller: PsshippingOrdersController
_legacy_link: PsshippingOrdersController
save_dimensions_per_packages:
path: /psshipping/configuration/setDimensionPerPage
methods: [POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController::setPackagesDimensions'
_legacy_controller: PsshippingConfigurationController
_legacy_link: PsshippingConfigurationController
set_order_status_mapping:
path: /psshipping/configuration/setOrderStatusMapping
methods: [POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController::setOrderStatusMapping'
_legacy_controller: PsshippingConfigurationController
_legacy_link: PsshippingConfigurationController
set_status_for_order_status_mapping:
path: /psshipping/configuration/setStatusForOrderStatusMapping
methods: [POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController::setStatusForOrderStatusMapping'
_legacy_controller: PsshippingConfigurationController
_legacy_link: PsshippingConfigurationController
get_status_order_status_mapping:
path: /psshipping/configuration/getStatusOrderStatusMapping
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController::getStatusOrderStatusMapping'
_legacy_controller: PsshippingConfigurationController
_legacy_link: PsshippingConfigurationController
get_dimensions_per_packages:
path: /psshipping/configuration/getDimensionPerPage
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController::getPackagesDimensions'
_legacy_controller: PsshippingConfigurationController
_legacy_link: PsshippingConfigurationController
get_advanced_setting:
path: /psshipping/configuration/getAdvancedSetting
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController::getAdvancedSetting'
_legacy_controller: PsshippingConfigurationController
_legacy_link: PsshippingConfigurationController
save_advanced_setting:
path: /psshipping/configuration/saveAdvancedSetting
methods: [POST]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController::setAdvancedSetting'
_legacy_controller: PsshippingConfigurationController
_legacy_link: PsshippingConfigurationController
mbe_login:
path: /psshipping/mbe/login
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingKeycloakAuthController::oauthCallback'
_legacy_controller: PsshippingKeycloakAuthController
_legacy_link: PsshippingKeycloakAuthController
faq_list:
path: /psshipping/faq/list
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Psshipping\Controller\Admin\PsshippingFaqController::getFaq'
_legacy_controller: PsshippingFaqController
_legacy_link: PsshippingFaqController

View File

@@ -0,0 +1,39 @@
imports:
- { resource: parameters.yml }
- { resource: controllers.yml }
- { resource: accounts.yml }
- { resource: billing.yml }
- { resource: handler.yml }
- { resource: configuration.yml }
- { resource: hooks.yml }
- { resource: repositories.yml }
- { resource: gelProximity.yml }
services:
_defaults:
public: true
psshipping:
class: 'Psshipping'
factory: ['Module', 'getInstanceByName']
arguments:
- "psshipping"
psshipping.helper.config:
class: 'PrestaShop\Module\Psshipping\Helper\ConfigHelper'
arguments:
- "%psshipping.api_url%"
- "%psshipping.mbe_tracking_url%"
- "%psshipping.segment_key%"
- "%psshipping.sentry_dsn%"
- "%psshipping.sentry_env%"
psshipping.context:
class: Context
factory: ['Context', 'getContext']
PrestaShop\Module\Psshipping\Domain\Carriers\CarrierService:
class: 'PrestaShop\Module\Psshipping\Domain\Carriers\CarrierService'
arguments:
- '@psshipping'
- '@PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository'

View File

@@ -0,0 +1,98 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
use PrestaShop\Module\Psshipping\Domain\GelProximity\Models\PickupPoint;
class psshippingGelProximityNotificationHandlerModuleFrontController extends \ModuleFrontController
{
protected $validActions = ['setPickUpPointForCurrentCart'];
public function init()
{
$this->ajax = true;
$this->content_only = true;
$this->controller_type = 'module';
}
private function respondAndDie($message, $data, $response_code = 500)
{
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Content-Type: application/json');
http_response_code($response_code);
$response = [
'status' => $response_code,
'message' => $message,
'data' => $data,
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
public function setPickUpPointForCurrentCart()
{
$payload = Tools::getValue('payload');
/** @var array{
* pickupPointId: int,
* networkCode: string,
* code: string,
* address: string,
* description: string|null,
* city: string,
* zipCode: string,
* department: string|null,
* country: string
* } $pickupPoint */
$pickupPoint = json_decode($payload, true);
$pickupPoint = PickupPoint::fromArray($pickupPoint);
$pickupPoint->injectIntoCookies($this->context);
$template = $this->context->smarty->createTemplate(_PS_MODULE_DIR_ . 'psshipping/views/templates/hook/pickUpPointDetails.tpl');
$template->assign([
'btnText' => $this->trans('Change pick-up point', [], 'Modules.Psshipping.Admin'),
'detailsTitle' => $this->trans('Pick-up point selected:', [], 'Modules.Psshipping.Admin'),
'pickupPoint' => $pickupPoint->toArray(),
]);
return ['pickupsDetails' => $template->fetch()];
}
public function postProcess()
{
$action = Tools::getValue('action');
if (!in_array($action, $this->validActions, true)) {
$this->respondAndDie(
['unknown action'],
false,
400
);
} elseif ($action === 'setPickUpPointForCurrentCart') {
$this->respondAndDie(
false,
$this->setPickUpPointForCurrentCart(),
200
);
}
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,120 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
use Context as LegacyContext;
use PrestaShop\Module\Psshipping\Domain\Orders\OrdersRepository;
use PrestaShop\PrestaShop\Adapter\Configuration;
use Svix\Exception\WebhookVerificationException;
use Svix\Webhook;
class psshippingWebhookOrderStatusModuleFrontController extends \ModuleFrontController
{
public function init()
{
$this->ajax = true;
$this->content_only = true;
$this->controller_type = 'module';
}
/**
* @return void
*
* @throws\PrestaShopException
*/
public function postProcess()
{
$configuration = new Configuration();
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
$secretKey = $configuration->get('PS_SHIPPING_WEBHOOK_SECRET');
if (empty($secretKey)) {
$this->exitWithResponse([
'success' => false,
'httpCode' => 400,
'msg' => 'missing secret key',
]);
}
$json = file_get_contents('php://input');
if (empty($json)) {
$this->exitWithResponse([
'success' => false,
'httpCode' => 400,
'msg' => 'payload is empty',
]);
}
try {
(new Webhook($secretKey))->verify($json, array_change_key_case(getallheaders(), CASE_LOWER));
$resp = json_decode($json, true);
$orderRepository = new OrdersRepository($this->module);
$orderRepository->updateOrder($resp['orderId'], $resp['status']);
$this->exitWithResponse([
'success' => true,
'httpCode' => 200,
'body' => $resp,
]);
} catch (WebhookVerificationException $e) {
$this->exitWithResponse([
'success' => false,
'httpCode' => 400,
'msg' => $e->getMessage(),
]);
}
}
/**
* @param array $response
*
* @return void
*/
protected function exitWithResponse(array $response)
{
$httpCode = isset($response['httpCode']) ? (int) $response['httpCode'] : 200;
$this->dieWithResponse($response, $httpCode);
}
/**
* @param array $response
* @param int $code
*
* @return void
*/
private function dieWithResponse(array $response, $code)
{
$httpStatusText = "HTTP/1.1 $code";
$response['httpCode'] = (int) $code;
header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
header('Content-Type: application/json;charset=utf-8');
header($httpStatusText);
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

BIN
modules/psshipping/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,10 @@
{
"dependencies": [
{
"name" : "ps_accounts"
},
{
"name" : "ps_eventbus"
}
]
}

View File

@@ -0,0 +1,824 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
if (!defined('_PS_VERSION_')) {
exit();
}
use PrestaShop\Module\Psshipping\Controller\Admin\PsshippingConfigurationController;
use PrestaShop\Module\Psshipping\Domain\Accounts\AccountsService;
use PrestaShop\Module\Psshipping\Domain\Api\Webhook;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierService;
use PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressOrdersRepository;
use PrestaShop\Module\Psshipping\Domain\Legacy\PrestaShopAdapter;
use PrestaShop\Module\Psshipping\Domain\Orders\OrdersRepository;
use PrestaShop\Module\Psshipping\Domain\Segment\Segment;
use PrestaShop\Module\Psshipping\Domain\Shipment\RecipientDTO;
use PrestaShop\Module\Psshipping\Domain\Shipment\RecipientPickupPointDTO;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
use PrestaShop\Module\Psshipping\Helper\ConfigHelper;
use PrestaShop\Module\Psshipping\Hooks\HookActionObjectCarrierUpdateAfter;
use PrestaShop\Module\Psshipping\Hooks\HookActionValidateOrder;
use PrestaShop\Module\Psshipping\Hooks\HookDisplayCarrierExtraContent;
use PrestaShop\Module\Psshipping\Hooks\HookDisplayHeader;
use PrestaShop\Module\Psshipping\Hooks\HookDisplayOrderConfirmation;
use PrestaShop\Module\Psshipping\Service\DatabaseInstaller;
use PrestaShop\ModuleLibServiceContainer\DependencyInjection\ServiceContainer;
use PrestaShop\PrestaShop\Adapter\Configuration;
use PrestaShop\PrestaShop\Core\Action\ActionsBarButtonsCollection as NewActionsBarButtonsCollection;
use PrestaShopBundle\Controller\Admin\Sell\Order\ActionsBarButtonsCollection;
use PrestaShopBundle\Service\Routing\Router;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Twig\Environment as Twig_Environment;
class Psshipping extends Module
{
/** @var bool */
public $bootstrap;
/** @var array<string, string> */
public $ps_versions_compliancy;
/** @var string */
public $emailSupport;
/** @var string */
public $termsOfServiceUrl;
/** @var string */
public $name;
/** @var string */
public $version;
/** @var string */
public $module_key;
/** @var ServiceContainer */
public $serviceContainer;
const MODULE_TECHNICAL_NAME = 'psshipping';
const MBE_API_SERVICE_ID_CARRIER_STANDARD = 2;
const MBE_API_SERVICE_ID_CARRIER_EXPRESS = 4;
const MBE_API_SERVICE_ID_CARRIER_PICKUP = 12;
const UPS_DAP_API_SERVICE_ID_CARRIER_STANDARD = 13;
const UPS_DAP_API_SERVICE_ID_CARRIER_EXPRESS = 14;
const HOOK_LIST = [
'actionGetAdminOrderButtons',
'actionValidateOrder',
'displayHeader',
'displayAdminOrderTabContent',
'displayAdminOrderTabLink',
'displayAdminOrderContentShip',
'displayAdminOrderTabShip',
'displayBackOfficeHeader',
'displayCarrierExtraContent',
'displayOrderConfirmation',
'actionObjectCarrierUpdateAfter',
'actionGetOrderShipments',
];
/** @var array<array<string, string|bool>> */
public $tabs = [
[
'name' => 'Homepage',
'class_name' => 'PsshippingHomeController',
'visible' => false,
'parent_class_name' => 'AdminParentModulesSf',
'wording' => 'Homepage',
'wording_domain' => 'Modules.Pshipping.Admin',
],
];
/**
* Module constructor
*/
public function __construct()
{
$this->name = 'psshipping';
$this->tab = 'shipping_logistics';
$this->version = '2.1.1';
$this->author = 'PrestaShop';
$this->need_instance = 0;
$this->module_key = '8a4eff554bcb2ec847b3d4c70286b0e2';
$this->ps_versions_compliancy = [
'min' => '1.7.6.0',
'max' => _PS_VERSION_,
];
parent::__construct();
$this->emailSupport = 'support@prestashop.com';
$this->termsOfServiceUrl =
'https://www.prestashop.com/en/prestashop-account-privacy';
$this->displayName = $this->trans('PrestaShop Shipping', [], 'Modules.Psshipping.Admin');
$this->description = $this->trans(
'Powered by Mail Boxes Etc., PrestaShop Shipping offers standard and express international delivery methods to your customers no matter where they are located. Have access to exclusive rates for each delivered and returned parcels by using our extensive network of trusted partners.',
[],
'Modules.Psshipping.Admin'
);
$this->confirmUninstall = $this->trans(
'Are you sure you want to uninstall PrestaShop Shipping module?',
[],
'Modules.Psshipping.Admin'
);
require_once __DIR__ . '/vendor/autoload.php';
if ($this->serviceContainer === null) {
$this->serviceContainer = new ServiceContainer(
(string) $this->name,
$this->getLocalPath()
);
}
}
public function install(): bool
{
$segment = new Segment($this, true);
$segment->setMessage('[SHI] PS Shipping Installed');
$segment->track();
if (!$this->isPhpVersionCompliant()) {
$this->_errors[] = $this->trans('This requires PHP 7.2 to work properly. Please upgrade your server configuration.', [], 'Modules.Psshipping.Admin');
return defined('PS_INSTALLATION_IN_PROGRESS');
}
if (!parent::install()) {
$this->_errors[] = $this->trans('An error occured during the parent installation.', [], 'Modules.Psshipping.Admin');
return false;
}
if (!$this->registerHook(self::HOOK_LIST)) {
$this->_errors[] = $this->trans('An error occured while trying to register hooks.', [], 'Modules.Psshipping.Admin');
return false;
}
try {
(new DatabaseInstaller($this))->install();
} catch (Exception $e) {
$this->_errors[] = $e->getMessage();
return false;
}
return true;
}
public function uninstall()
{
$segment = new Segment($this);
$segment->setMessage('[SHI] PS Shipping Uninstalled');
$segment->track();
if (!$this->isPhpVersionCompliant()) {
return parent::uninstall();
}
parent::uninstall();
$configuration = new Configuration();
$configuration->remove(PsshippingConfigurationController::ONBOARDING_IS_DONE);
$configuration->remove(PsshippingConfigurationController::MAX_WEIGHT_PER_PACKAGE);
$configuration->remove(PsshippingConfigurationController::MAX_WIDTH_PER_PACKAGE);
$configuration->remove(PsshippingConfigurationController::MAX_HEIGHT_PER_PACKAGE);
$configuration->remove(PsshippingConfigurationController::MAX_LENGTH_PER_PACKAGE);
$configuration->remove(PsshippingConfigurationController::ORDER_MAPPING_IS_ACTIVATE);
$configuration->remove(PsshippingConfigurationController::ORDER_STATUS_MAPPING);
$configuration->remove('PS_SHIPPING_WEBHOOK_SECRET');
(new Webhook($this))->deleteSvixEndpoint();
$carrierRepository = new CarrierRepository($this);
$carrierService = new CarrierService($this, $carrierRepository);
$carrierService->delete();
return true;
}
public function disable($force_all = false): bool
{
$carrierRepository = new CarrierRepository($this);
$carrierService = new CarrierService($this, $carrierRepository);
$carrierService->update();
return parent::disable($force_all);
}
/**
* Configuration page of the module - redirect to controller
*
* @return void
*/
public function getContent(): void
{
$segment = new Segment($this);
$segment->setMessage('[SHI] PS Shipping Module Manager Configure CTA Clicked');
$segment->track();
$this->registerHook('actionGetOrderShipments');
try {
Tools::redirectAdmin((new PrestaShopAdapter($this))->generateRoute('home', ['route' => 'home']));
} catch (\Exception $e) {
if ($e instanceof RouteNotFoundException) {
throw new PsshippingException($e->getMessage(), $e->getCode());
}
}
}
/**
* @param array{
* carrier: array{
* id: int,
* }
* } $params
*/
public function hookDisplayCarrierExtraContent(array $params): string
{
/** @var HookDisplayCarrierExtraContent $hookDisplayCarrierExtraContent */
$hookDisplayCarrierExtraContent = $this->getService(HookDisplayCarrierExtraContent::class);
return $hookDisplayCarrierExtraContent->run($params);
}
public function hookDisplayHeader(): void
{
/** @var HookDisplayHeader $hookDisplayHeader */
$hookDisplayHeader = $this->getService(HookDisplayHeader::class);
$hookDisplayHeader->run();
}
/**
* @param array{
* order: Order,
* } $params
*/
public function hookDisplayOrderConfirmation(array $params): string
{
/** @var HookDisplayOrderConfirmation $hookDisplayOrderConfirmation */
$hookDisplayOrderConfirmation = $this->getService(HookDisplayOrderConfirmation::class);
return $hookDisplayOrderConfirmation->run($params);
}
/**
* @param array{
* cart: Cart,
* order: Order,
* } $params
*/
public function hookActionValidateOrder(array $params): void
{
/** @var HookActionValidateOrder $hookActionValidateOrder */
$hookActionValidateOrder = $this->getService(HookActionValidateOrder::class);
$hookActionValidateOrder->run($params);
}
/**
* Enable the new PrestaShop translations system for the module
* https://devdocs.prestashop.com/1.7/modules/creation/module-translation/new-system/
*
* @return bool
*/
public function isUsingNewTranslationSystem(): bool
{
return true;
}
/**
* Method that dispatches to the correct service container
*
* @param string $serviceName
*
* @return mixed
*/
public function getService($serviceName)
{
// Check if it's a module service (dot notation or full namespace)
$isModuleService =
strpos($serviceName, 'psshipping.') === 0 ||
strpos($serviceName, 'PrestaShop\\Module\\Psshipping\\') === 0;
if ($isModuleService) {
return $this->serviceContainer->getService($serviceName);
}
// Otherwise use PrestaShops main container
return $this->get($serviceName);
}
/**
* Hook executed on the header of each pages in the backoffice
*
* @return string|void
*/
public function hookDisplayBackOfficeHeader()
{
return $this->renderPromoteBanner();
}
/**
* Render the banner promoting the shipping module.
* Only display the banner on the carrier page.
* To be called on the backofficeHeader hook.
*
* @return string
*/
private function renderPromoteBanner(): string
{
if (empty($this->context->controller)) {
return '';
}
$controller = $this->context->controller;
if (empty($controller->controller_name)) {
return '';
}
$controllerName = $controller->controller_name;
if ($controllerName !== 'AdminCarriers') {
return '';
}
Media::addJsDef([
'psshippingModuleLink' => (new PrestaShopAdapter($this))->generateRoute('home', ['route' => 'home']),
'defaultIsoCode' => $this->context->language->iso_code ?? 'en',
]);
if (empty($this->context->smarty)) {
return '';
}
return $this->display(__DIR__, 'views/templates/hook/promoteBanner.tpl');
}
/**
* @return string
*/
public function getFilePath(): string
{
return __FILE__;
}
/**
* @return string
*/
public function getSegmentKey(): string
{
/** @var ConfigHelper $config */
$config = $this->getService('psshipping.helper.config');
return $config->segment_key;
}
/**
* @return string
*/
public function getSentryDsn(): string
{
/** @var ConfigHelper $config */
$config = $this->getService('psshipping.helper.config');
return $config->sentry_dsn;
}
/**
* @return string
*/
public function getSentryEnv(): string
{
/** @var ConfigHelper $config */
$config = $this->getService('psshipping.helper.config');
return $config->sentry_env;
}
/**
* @return string
*/
public function getApiUrl(): string
{
/** @var ConfigHelper $config */
$config = $this->getService('psshipping.helper.config');
return $config->api_url;
}
public function getMbeTrackingUrl(): string
{
/** @var ConfigHelper $config */
$config = $this->getService('psshipping.helper.config');
return $config->mbe_tracking_url;
}
/**
* Add buttons to main buttons bar
*
* @param array<string, string> $params
*
* @return void
*/
public function hookActionGetAdminOrderButtons(array $params)
{
if (!$this->canDisplayShippingTab((int) $params['id_order'])) {
return;
}
/** @var ActionsBarButtonsCollection|NewActionsBarButtonsCollection $bar */
$bar = $params['actions_bar_buttons_collection'];
if (version_compare(_PS_VERSION_, '9.0.0', '>=')) {
$bar->add(
new PrestaShop\PrestaShop\Core\Action\ActionsBarButton(
'btn-dark',
['href' => '#psshipping-app'],
$this->trans('Print shipping label', [], 'Modules.Psshipping.Admin')
)
);
} else {
$bar->add(
new PrestaShopBundle\Controller\Admin\Sell\Order\ActionsBarButton(
'btn-dark',
['href' => '#psshipping-app'],
$this->trans('Print shipping label', [], 'Modules.Psshipping.Admin')
)
);
}
}
/**
* We use this hook in order to listen changes made on carriers created
* by the PrestaShop Shipping module. We only want to listen 'active'
* field edit
*
* @param array<string, string> $params
*/
public function hookActionObjectCarrierUpdateAfter(array $params): void
{
/** @var HookActionObjectCarrierUpdateAfter $hookActionObjectCarrierUpdateAfter */
$hookActionObjectCarrierUpdateAfter = $this->getService(HookActionObjectCarrierUpdateAfter::class);
$hookActionObjectCarrierUpdateAfter->run($params);
}
/**
* Only for 1.7.6
*
* @param Order[] $params
*
* @return string
*/
public function hookDisplayAdminOrderContentShip(array $params)
{
if (!$this->canDisplayShippingTab((int) $params['order']->id)) {
return '';
}
if (empty($this->context->smarty)) {
return '';
}
Media::addJsDef([
'shipmentDetail' => $this->renderOrderDetail(new Order($params['order']->id)),
'contextPsAccounts' => (new AccountsService())->getAccountsContext($this),
]);
return $this->display(__DIR__, 'views/templates/admin/shipping.tpl');
}
/**
* @return array<string, mixed>
*/
private function renderOrderDetail(Order $order)
{
$totalCartPackageWeight = (float) (new Cart($order->id_cart))->getTotalWeight();
$maxWeightPerPackageConfiguration = (new Configuration())->get(PsshippingConfigurationController::MAX_WEIGHT_PER_PACKAGE, 0);
$maxWeightPerPackage = is_numeric($maxWeightPerPackageConfiguration) ? (float) $maxWeightPerPackageConfiguration : 0.0;
$orderCarrierId = $order->getIdOrderCarrier();
/** @var string|null $trackingNumber */
$trackingNumber = (new OrderCarrier($orderCarrierId))->tracking_number;
$carrier = new Carrier((int) $order->id_carrier);
$recipient = $this->buildRecipient($order);
/** @var CarrierRepository $carrierRepository */
$carrierRepository = $this->getService(CarrierRepository::class);
$carrierMapping = $carrierRepository->getShippingCarriersMapping();
/** @var array{type: string, provider: string} $carrierType */
$carrierType = $carrierMapping[$carrier->id];
return [
'deliveryMode' => $carrier->name,
'numberOfPackages' => (int) ($maxWeightPerPackage > 0 ? ceil($totalCartPackageWeight / $maxWeightPerPackage) : 0),
'totalCartWeight' => $totalCartPackageWeight,
'maxWeightPerPackage' => $maxWeightPerPackage,
'shippingDate' => $order->delivery_date,
'deliveryAddress' => [
'recipient' => $recipient->toArray(),
'shipment' => $this->buildShipmentDetail($order, $carrierType, $recipient),
],
'contextPsAccounts' => (new AccountsService())->getAccountsContext($this),
'tokenPsAccounts' => (new AccountsService())->getPsAccountToken($this),
'psxShippingApiUrl' => $this->getApiUrl(),
'defaultIsoCode' => $this->context->language->iso_code ?? 'en',
'orderId' => $order->id,
'trackingNumber' => $trackingNumber ?? '',
'saveTrackingNumberControllerLink' => (new PrestaShopAdapter($this))->generateRoute('save_tracking_number', ['route' => 'save_tracking_number']),
];
}
/**
* @param array<string, string> $params
*
* Only for 1.7.7+
*
* @return string
*/
public function hookDisplayAdminOrderTabContent(array $params)
{
if (!$this->canDisplayShippingTab((int) $params['id_order'])) {
return '';
}
/** @var Router $router */
$router = $this->get('router');
$order = new Order((int) $params['id_order']);
$shipmentDetail = $this->renderOrderDetail($order);
$shipmentDetail['saveTrackingNumberControllerLink'] = $router->generate('save_tracking_number');
return $this->render('@Modules/psshipping/views/templates/admin/shipping.html.twig', [
'shipmentDetail' => $shipmentDetail,
'params' => $order,
'defaultIsoCode' => $this->context->language->iso_code ?? 'en',
'contextPsAccounts' => (new AccountsService())->getAccountsContext($this),
]);
}
/**
* @param Order $order
*
* @return RecipientDTO
*/
private function buildRecipient(Order $order)
{
/** @var CarrierRepository $carrierRepository */
$carrierRepository = $this->getService(CarrierRepository::class);
$isOrderUsePickupPointCarrier = $carrierRepository->isPickupCarrierFromMapping((int) $order->id_carrier);
$customer = new Customer((int) $order->id_customer);
$customerAddress = new Address((int) $order->id_address_delivery);
// if the order was made with a pickup point carrier, use the address of the pickup point
if ($isOrderUsePickupPointCarrier) {
/** @var PsshippingAddressOrdersRepository $addressRepository */
$addressRepository = $this->getService(PsshippingAddressOrdersRepository::class);
$pickupPointAddress = $addressRepository->findOneByIdOrderAndShop((int) $order->id, (int) $order->id_shop);
if ($pickupPointAddress === null) {
throw new PsshippingException(sprintf('Cannot find the pickup point address associated to the orderId %s.', $order->id));
}
$pickupPointAddress = $pickupPointAddress->getAddress();
$recipient = new RecipientPickupPointDTO(
$pickupPointAddress->getCode(),
$pickupPointAddress->getNetworkCode(),
$customer->firstname . ' ' . $customer->lastname,
$pickupPointAddress->getAddress(),
$pickupPointAddress->getDescription() ?? '',
$customerAddress->phone,
$pickupPointAddress->getZipCode(),
$pickupPointAddress->getCity(),
$pickupPointAddress->getDepartment(),
$pickupPointAddress->getCountry(),
$customer->email
);
} else { // otherwise use the address delivery of the order (from the customer)
$customerCountry = new Country($customerAddress->id_country);
$recipient = new RecipientDTO(
empty($customerAddress->company) ? $customer->firstname . ' ' . $customer->lastname : $customerAddress->company,
$customerAddress->address1,
$customerAddress->address2,
$customerAddress->phone,
$customerAddress->postcode,
$customerAddress->city,
(new StateCore($customerAddress->id_state))->iso_code,
$customerCountry->iso_code,
$customer->email
);
}
return $recipient;
}
/**
* @param Order $order
* @param array{type: string, provider: string} $carrierType
* @param RecipientDTO $recipient
*
* @return array<string, array<int<0, max>|string,float|int>|int|string>
*/
private function buildShipmentDetail($order, $carrierType, $recipient)
{
$configuration = new Configuration();
$weight = 0;
$width = 0;
$height = 0;
$length = 0;
$productsWeight = [];
if (is_numeric($configuration->get(PsshippingConfigurationController::MAX_WEIGHT_PER_PACKAGE))) {
$weight = floatval($configuration->get(PsshippingConfigurationController::MAX_WEIGHT_PER_PACKAGE));
}
if (is_numeric($configuration->get(PsshippingConfigurationController::MAX_WIDTH_PER_PACKAGE))) {
$width = floatval($configuration->get(PsshippingConfigurationController::MAX_WIDTH_PER_PACKAGE));
}
if (is_numeric($configuration->get(PsshippingConfigurationController::MAX_HEIGHT_PER_PACKAGE))) {
$height = floatval($configuration->get(PsshippingConfigurationController::MAX_HEIGHT_PER_PACKAGE));
}
if (is_numeric($configuration->get(PsshippingConfigurationController::MAX_LENGTH_PER_PACKAGE))) {
$length = floatval($configuration->get(PsshippingConfigurationController::MAX_LENGTH_PER_PACKAGE));
}
foreach ($order->getProducts() as $product) {
if ($product['product_quantity'] > 1) {
for ($i = 1; $i < $product['product_quantity']; ++$i) {
$productsWeight[] = (float) $product['weight'];
}
}
$productsWeight[] = (float) $product['weight'];
}
switch ($carrierType['type']) {
case CarrierService::CARRIERS_STANDARD:
$serviceId = $carrierType['provider'] === CarrierService::PROVIDER_MBE ? self::MBE_API_SERVICE_ID_CARRIER_STANDARD : self::UPS_DAP_API_SERVICE_ID_CARRIER_STANDARD;
break;
case CarrierService::CARRIERS_PICKUP:
$serviceId = self::MBE_API_SERVICE_ID_CARRIER_PICKUP;
break;
case CarrierService::CARRIERS_EXPRESS:
$serviceId = $carrierType['provider'] === CarrierService::PROVIDER_MBE ? self::MBE_API_SERVICE_ID_CARRIER_EXPRESS : self::UPS_DAP_API_SERVICE_ID_CARRIER_EXPRESS;
break;
default:
$serviceId = 0;
break;
}
return [
'orderDate' => $order->date_upd,
'service' => $serviceId,
'packageType' => 'GENERIC',
'description' => $recipient->address2 ?? '-',
'productsWeight' => $productsWeight,
'defaultConfiguration' => [
'weight' => $weight,
'width' => $width,
'height' => $height,
'length' => $length,
],
];
}
/**
* @return bool
*/
private function canDisplayShippingTab(int $idOrder)
{
$order = new Order($idOrder);
/** @var CarrierRepository $carrierRepository */
$carrierRepository = $this->getService(CarrierRepository::class);
$carrierMapping = $carrierRepository->getShippingCarriersMapping();
$configuration = new Configuration();
if (
$configuration->get(PsshippingConfigurationController::MAX_WEIGHT_PER_PACKAGE) === '' ||
$configuration->get(PsshippingConfigurationController::MAX_WIDTH_PER_PACKAGE) === '' ||
$configuration->get(PsshippingConfigurationController::MAX_HEIGHT_PER_PACKAGE) === '' ||
$configuration->get(PsshippingConfigurationController::MAX_LENGTH_PER_PACKAGE) === ''
) {
return false;
}
return array_key_exists((int) $order->id_carrier, $carrierMapping);
}
/**
* Only for 1.7.6
*
* @param Order[] $params
*/
public function hookDisplayAdminOrderTabShip(array $params): string
{
if (!$this->canDisplayShippingTab((int) $params['order']->id)) {
return '';
}
$psImage = $this->getPathUri() . '/views/img/prestashop.svg';
if ($this->context->smarty === null) {
return '';
}
$this->context->smarty->assign([
'psImage' => $psImage,
]);
return $this->display(__DIR__, 'views/templates/admin/shipping-link.tpl');
}
/**
* Only for 1.7.7+
*
* @param array<string, string> $params
*/
public function hookDisplayAdminOrderTabLink(array $params): string
{
if (!$this->canDisplayShippingTab((int) $params['id_order'])) {
return '';
}
$psImage = $this->getPathUri() . '/views/img/prestashop.svg';
return $this->render('@Modules/psshipping/views/templates/admin/shipping-link.html.twig', [
'psImage' => $psImage,
]);
}
/**
* @param array<string, string> $params
*
* @return array<string, mixed>
*/
public function hookActionGetOrderShipments(array $params): array
{
if (empty($params['id_order'])) {
return [];
}
return (new OrdersRepository($this))->getOrderDetails((int) $params['id_order']);
}
/**
* Render a twig template.
*
* @param string $template
* @param array<string, array<string,mixed>|Order|string> $params
*
* @return string
*/
private function render(string $template, array $params = []): string
{
if (version_compare(_PS_VERSION_, '9.0.0', '>=')) {
$twig = $this->getTwig();
} else {
$twig = $this->get('twig');
}
if (!$twig instanceof Twig_Environment) {
throw new PrestaShopException('Twig service not found');
}
return $twig->render($template, $params);
}
/**
* @return bool
*/
private function isPhpVersionCompliant()
{
return 70200 <= PHP_VERSION_ID;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,24 @@
-- Create psshipping_address table
CREATE TABLE IF NOT EXISTS `_DB_PREFIX_psshipping_address` (
`id_address` INT AUTO_INCREMENT NOT NULL,
`pickup_point_id` INT NOT NULL,
`network_code` VARCHAR(20) NOT NULL,
`code` VARCHAR(255) NOT NULL,
`description` VARCHAR(255) DEFAULT NULL,
`address` VARCHAR(255) NOT NULL,
`city` VARCHAR(255) NOT NULL,
`zip_code` VARCHAR(255) NOT NULL,
`department` VARCHAR(255) DEFAULT NULL,
`country` VARCHAR(255) NOT NULL,
UNIQUE INDEX UNIQ_ED8CCBFF682033F1 (`pickup_point_id`),
PRIMARY KEY(`id_address`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;
-- Create psshipping_address_orders table
CREATE TABLE IF NOT EXISTS `_DB_PREFIX_psshipping_address_orders` (
`id_order` INT NOT NULL,
`id_shop` INT NOT NULL,
`id_address` INT NOT NULL,
INDEX IDX_A5067A5CD3D3C6F1 (`id_address`),
PRIMARY KEY(`id_order`, `id_shop`, `id_address`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;

View File

@@ -0,0 +1,5 @@
-- Drop psshipping_address_orders table
DROP TABLE IF EXISTS `_DB_PREFIX_psshipping_address_orders`;
-- Drop psshipping_address table
DROP TABLE IF EXISTS `_DB_PREFIX_psshipping_address`;

View File

@@ -0,0 +1,150 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Controller\Admin;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierService;
use PrestaShop\Module\Psshipping\Domain\Carriers\MbeExpressCarrierConfiguration;
use PrestaShop\Module\Psshipping\Domain\Carriers\MbePickupCarrierConfiguration;
use PrestaShop\Module\Psshipping\Domain\Carriers\MbeStandardCarrierConfiguration;
use PrestaShop\Module\Psshipping\Domain\Carriers\UpsExpressCarrierConfiguration;
use PrestaShop\Module\Psshipping\Domain\Carriers\UpsStandardCarrierConfiguration;
use PrestaShop\Module\Psshipping\Exception\BadRequestException;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use Psshipping;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
if (!defined('_PS_VERSION_')) {
exit();
}
class PsshippingCarrierController extends FrameworkBundleAdminController
{
/** @var CarrierService */
private $carrierService;
/** @var Psshipping */
private $module;
public function __construct(Psshipping $module, CarrierService $carrierService)
{
$this->module = $module;
$this->carrierService = $carrierService;
}
public function createAction(): Response
{
try {
$mbe_tracking_url = $this->module->getMbeTrackingUrl();
return new Response(
json_encode([
'success' => true,
'carrier' => [
'standard' => [
$this->carrierService->create(new MbeStandardCarrierConfiguration($mbe_tracking_url))->jsonSerialize(),
$this->carrierService->create(new UpsStandardCarrierConfiguration($mbe_tracking_url))->jsonSerialize(),
],
'pickup' => $this->carrierService->create(new MbePickupCarrierConfiguration($mbe_tracking_url))->jsonSerialize(),
'express' => [
$this->carrierService->create(new MbeExpressCarrierConfiguration($mbe_tracking_url))->jsonSerialize(),
$this->carrierService->create(new UpsExpressCarrierConfiguration($mbe_tracking_url))->jsonSerialize(),
],
],
]),
201,
['Content-Type' => 'application/json']
);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
}
public function listAction(): Response
{
try {
return new Response(
json_encode(['carriers' => $this->carrierService->get()]),
200,
['Content-Type' => 'application/json']
);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
}
public function toggleStatusAction(Request $request): Response
{
try {
$requestBodyContent = (array) json_decode((string) $request->getContent(false), true);
if (empty($requestBodyContent['idCarrier'])) {
return new Response(
json_encode(['error' => 'Missing key idCarrier']),
400,
['Content-Type' => 'application/json']
);
}
if (!is_int($requestBodyContent['idCarrier'])) {
return new Response(
json_encode(['error' => 'idCarrier need to be an integer']),
400,
['Content-Type' => 'application/json']
);
}
return new Response(
json_encode(['carrierStatus' => $this->carrierService->toggle($requestBodyContent['idCarrier'])]),
200,
['Content-Type' => 'application/json']
);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
}
public function getAdminLinkAction(Request $request): Response
{
try {
$requestBodyContent = (array) json_decode((string) $request->getContent(false), true);
if (empty($requestBodyContent['idCarrier'])) {
return new Response(
json_encode(['error' => 'No carrier ID provided']),
400,
['Content-Type' => 'application/json']
);
}
return new Response(
json_encode(['carrierLink' => $this->getAdminLink('AdminCarrierWizard', ['id_carrier' => $requestBodyContent['idCarrier']], true)]),
200,
['Content-Type' => 'application/json']
);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
}
}

View File

@@ -0,0 +1,385 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Controller\Admin;
use Context as LegacyContext;
use PrestaShop\Module\Psshipping\Domain\Api\Webhook;
use PrestaShop\Module\Psshipping\Exception\BadRequestException;
use PrestaShop\PrestaShop\Adapter\Configuration;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use Psshipping;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
if (!defined('_PS_VERSION_')) {
exit();
}
class PsshippingConfigurationController extends FrameworkBundleAdminController
{
const MAX_WEIGHT_PER_PACKAGE = 'PS_SHIPPING_MAX_WEIGHT_PER_PACKAGE';
const MAX_WIDTH_PER_PACKAGE = 'PS_SHIPPING_MAX_WIDTH_PER_PACKAGE';
const MAX_HEIGHT_PER_PACKAGE = 'PS_SHIPPING_MAX_HEIGHT_PER_PACKAGE';
const MAX_LENGTH_PER_PACKAGE = 'PS_SHIPPING_MAX_LENGTH_PER_PACKAGE';
const ORDER_STATUS_MAPPING = 'PS_SHIPPING_ORDER_STATUS_MAPPING';
const ORDER_MAPPING_IS_ACTIVATE = 'PS_SHIPPING_ORDER_MAPPING_IS_ACTIVATE';
const ONBOARDING_IS_DONE = 'PS_SHIPPING_ONBOARDING_IS_DONE';
const ADVANCED_ORDER_SETTING = 'PS_SHIPPING_ADVANCED_ORDER_SETTING';
/** @var Psshipping */
private $module;
public function __construct(Psshipping $module)
{
$this->module = $module;
}
/**
* Toggle the status of the get started page and install tabs
* accordingly to the status.
*
* @return Response
*/
public function toggleOnboardingStatusAction(): Response
{
$configuration = new Configuration();
$context = LegacyContext::getContext();
try {
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
$onboardingIsDone = (bool) $configuration->get(self::ONBOARDING_IS_DONE, false);
$configuration->set(self::ONBOARDING_IS_DONE, !$onboardingIsDone);
} catch (\Exception $e) {
return new Response(
json_encode(['error' => 'An error occurred. Cannot toggle onboarding status.']),
400,
['Content-Type' => 'application/json']
);
}
return new Response(
json_encode(!$onboardingIsDone),
200,
['Content-Type' => 'application/json']
);
}
public function setPackagesDimensions(Request $request): Response
{
try {
$configuration = new Configuration();
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
$requestBodyContent = (array) json_decode((string) $request->getContent(false), true);
$requiredParams = ['weight', 'height', 'width', 'length'];
$maxWeightPerPackage = 0;
$maxHeightPerPackage = 0;
$maxWidthPerPackage = 0;
$maxLengthPerPackage = 0;
foreach ($requiredParams as $params) {
if (!in_array($params, array_keys($requestBodyContent))) {
return new Response(
json_encode([
'status' => false,
'error' => 'Missing ' . $params . ' parameter in request body',
]),
400,
['Content-Type' => 'application/json']
);
}
}
if (is_numeric($requestBodyContent['weight'])) {
$maxWeightPerPackage = floatval($requestBodyContent['weight']);
}
if (is_numeric($requestBodyContent['height'])) {
$maxHeightPerPackage = floatval($requestBodyContent['height']);
}
if (is_numeric($requestBodyContent['width'])) {
$maxWidthPerPackage = floatval($requestBodyContent['width']);
}
if (is_numeric($requestBodyContent['length'])) {
$maxLengthPerPackage = floatval($requestBodyContent['length']);
}
if ($maxWeightPerPackage > 30) {
return new Response(
json_encode([
'status' => false,
'error' => 'Weight must not exceed 30 kg',
]),
400,
['Content-Type' => 'application/json']
);
}
$configuration->set(self::MAX_WEIGHT_PER_PACKAGE, $maxWeightPerPackage);
$configuration->set(self::MAX_WIDTH_PER_PACKAGE, $maxWidthPerPackage);
$configuration->set(self::MAX_HEIGHT_PER_PACKAGE, $maxHeightPerPackage);
$configuration->set(self::MAX_LENGTH_PER_PACKAGE, $maxLengthPerPackage);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
return new Response(
json_encode([
'status' => true,
]),
200,
['Content-Type' => 'application/json']
);
}
public function getPackagesDimensions(): Response
{
$configuration = new Configuration();
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
$maxWeightPerPackage = 0;
$maxHeightPerPackage = 0;
$maxWidthPerPackage = 0;
$maxLengthPerPackage = 0;
if (is_numeric($configuration->get(self::MAX_WEIGHT_PER_PACKAGE, 0))) {
$maxWeightPerPackage = floatval($configuration->get(self::MAX_WEIGHT_PER_PACKAGE, 0));
}
if (is_numeric($configuration->get(self::MAX_WIDTH_PER_PACKAGE, 0))) {
$maxWidthPerPackage = floatval($configuration->get(self::MAX_WIDTH_PER_PACKAGE, 0));
}
if (is_numeric($configuration->get(self::MAX_HEIGHT_PER_PACKAGE, 0))) {
$maxHeightPerPackage = floatval($configuration->get(self::MAX_HEIGHT_PER_PACKAGE, 0));
}
if (is_numeric($configuration->get(self::MAX_LENGTH_PER_PACKAGE, 0))) {
$maxLengthPerPackage = floatval($configuration->get(self::MAX_LENGTH_PER_PACKAGE, 0));
}
return new Response(
json_encode([
'status' => true,
'configuration' => [
'height' => $maxHeightPerPackage,
'width' => $maxWidthPerPackage,
'weight' => $maxWeightPerPackage,
'length' => $maxLengthPerPackage,
],
]),
200,
['Content-Type' => 'application/json']
);
}
public function getAdvancedSetting(): Response
{
$configuration = new Configuration();
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
return new Response(
json_encode([
'status' => true,
'advancedSetting' => (bool) $configuration->get(self::ADVANCED_ORDER_SETTING, false),
]),
200,
['Content-Type' => 'application/json']
);
}
public function setAdvancedSetting(Request $request): Response
{
try {
$configuration = new Configuration();
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
$requestBodyContent = (array) json_decode((string) $request->getContent(false), true);
if (!isset($requestBodyContent['advancedValue'])) {
return new Response(
json_encode([
'status' => false,
'error' => 'Missing advancedValue parameter in request body',
]),
400,
['Content-Type' => 'application/json']
);
}
$configuration->set(self::ADVANCED_ORDER_SETTING, $requestBodyContent['advancedValue']);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
return new Response(
json_encode([
'status' => true,
]),
200,
['Content-Type' => 'application/json']
);
}
public function setOrderStatusMapping(Request $request): Response
{
try {
$configuration = new Configuration();
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
$requestBodyContent = (array) json_decode((string) $request->getContent(false), true);
if (!isset($requestBodyContent['mapping'])) {
return new Response(
json_encode([
'status' => false,
'error' => 'Missing mapping parameter in request body',
]),
400,
['Content-Type' => 'application/json']
);
}
if ($configuration->get(self::ORDER_STATUS_MAPPING) === null || empty($configuration->get(self::ORDER_STATUS_MAPPING))) {
(new Webhook($this->module))->saveSvixSecret();
}
$configuration->set(self::ORDER_STATUS_MAPPING, $requestBodyContent['mapping']);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
return new Response(
json_encode([
'status' => true,
]),
200,
['Content-Type' => 'application/json']
);
}
public function setStatusForOrderStatusMapping(Request $request): Response
{
try {
$configuration = new Configuration();
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
$requestBodyContent = (array) json_decode((string) $request->getContent(false), true);
if (!isset($requestBodyContent['enabled'])) {
return new Response(
json_encode([
'status' => false,
'error' => 'Missing enabled parameter in request body',
]),
400,
['Content-Type' => 'application/json']
);
}
$configuration->set(self::ORDER_MAPPING_IS_ACTIVATE, $requestBodyContent['enabled']);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
return new Response(
json_encode([
'status' => true,
]),
200,
['Content-Type' => 'application/json']
);
}
public function getStatusOrderStatusMapping(): Response
{
$configuration = new Configuration();
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
$mapping = $configuration->get(self::ORDER_STATUS_MAPPING);
return new Response(
json_encode([
'status' => true,
'enabled' => (bool) $configuration->get(self::ORDER_MAPPING_IS_ACTIVATE, false),
'mapping' => empty($mapping),
]),
200,
['Content-Type' => 'application/json']
);
}
public function getStates(Request $request): Response
{
$state = [];
$countryCode = 'IT';
if (!empty($request->get('countryCode') && is_scalar($request->get('countryCode')))) {
$countryCode = strval($request->get('countryCode'));
}
// Type is wrong before PS 8
// @phpstan-ignore notIdentical.alwaysTrue
if (\Country::getByIso($countryCode) !== false) {
$states = array_filter(\State::getStates(), function ($value) use ($countryCode) {
return (int) $value['id_country'] === \Country::getByIso($countryCode);
});
$state = array_map(function ($value) {
return [
'isoCode' => $value['iso_code'],
'name' => $value['name'],
];
}, $states);
}
return new Response(
json_encode([
'status' => true,
'state' => $state,
]),
200,
['Content-Type' => 'application/json']
);
}
}

View File

@@ -0,0 +1,78 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Controller\Admin;
use Context;
use PrestaShop\Module\Psshipping\Domain\Http\HttpClient;
use PrestaShop\Module\Psshipping\Exception\BadRequestException;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use Psshipping;
use Symfony\Component\HttpFoundation\Response;
if (!defined('_PS_VERSION_')) {
exit();
}
class PsshippingFaqController extends FrameworkBundleAdminController
{
/** @var Psshipping */
private $module;
public function __construct(Psshipping $module)
{
$this->module = $module;
}
/**
* @throws BadRequestException
*/
public function getFaq(): Response
{
try {
$context = Context::getContext();
$faq = [
'categories' => [],
];
if (!empty($context->language)) {
$request = new HttpClient('https://api.addons.prestashop.com');
$result = $request->get('/request/faq/' . $this->module->module_key . '/' . _PS_VERSION_ . '/' . $context->language->iso_code, []);
if ($result->getStatusCode() === 200) {
$faq['categories'] = json_decode($result->getBody(), true);
}
}
return new Response(
json_encode([
'faq' => $faq,
]),
200,
['Content-Type' => 'application/json']
);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
}
}

View File

@@ -0,0 +1,249 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Controller\Admin;
use Context;
use PrestaShop\Module\Psshipping\Domain\Accounts\AccountsService;
use PrestaShop\Module\Psshipping\Domain\Billing\BillingService;
use Prestashop\ModuleLibMboInstaller\DependencyBuilder;
use PrestaShop\PrestaShop\Adapter\Configuration;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use PrestaShopBundle\Service\Routing\Router;
use Psshipping;
use Shop as LegacyShop;
use ShopGroup as LegacyShopGroup;
use Symfony\Component\HttpFoundation\Response;
if (!defined('_PS_VERSION_')) {
exit();
}
class PsshippingHomeController extends FrameworkBundleAdminController
{
/** @var Psshipping */
private $module;
public function __construct(Psshipping $module)
{
$this->module = $module;
}
public function renderApp(): Response
{
$mboInstaller = new DependencyBuilder($this->module);
$dependencies = $mboInstaller->handleDependencies();
$isDependenciesMet = $mboInstaller->areDependenciesMet();
if (false === $isDependenciesMet) {
return $this->render(
'@Modules/psshipping/views/templates/admin/dependency.html.twig',
[
'dependencies' => $dependencies,
]
);
}
$context = Context::getContext();
/** @var Router $router */
$router = $this->get('router');
return $this->render(
'@Modules/psshipping/views/templates/admin/index.html.twig',
[
'layoutTitle' => $this->module->displayName,
'defaultIsoCode' => $context->language->iso_code ?? 'en',
'psxShippingApiUrl' => $this->module->getApiUrl(),
'contextPsAccounts' => (new AccountsService())->getAccountsContext($this->module),
'tokenPsAccounts' => (new AccountsService())->getPsAccountToken($this->module),
'psAccountCdnUrl' => (new AccountsService())->getPsAccountCdnUrl(),
'psBillingContext' => (new BillingService())->getBillingContext($this->module),
'isOnboardingDone' => (bool) $this->isOnboardingDone(),
'shops' => $this->getShops(),
'getMerchantIp' => $_SERVER['REMOTE_ADDR'],
'isMultiShopContext' => LegacyShop::isFeatureActive() && LegacyShop::getContext() !== LegacyShop::CONTEXT_SHOP,
'routes' => $this->generateRouteLink($router),
'phpVersion' => phpversion(),
'psVersion' => _PS_VERSION_,
'moduleKey' => $this->module->module_key,
'moduleVersion' => $this->module->version,
'activeHooks' => $this->getActiveHooks(),
]
);
}
/**
* Retrieve all shops
*
* @return array<array<string, string|int|bool>>
*/
private function getShops()
{
$shops = LegacyShop::getShops();
/** @var Router $router */
$router = $this->get('router');
$shops = array_map(function ($shop) use ($router) {
return [
'shopId' => intval($shop['id_shop']),
'shopIdGroup' => intval($shop['id_shop_group']),
'shopName' => (new LegacyShop($shop['id_shop']))->name,
'shopGroupName' => (new LegacyShopGroup($shop['id_shop_group']))->name,
'url' => $router->generate('home', ['setShopContext' => 's-' . $shop['id_shop']]),
'active' => intval($shop['active']),
];
}, $shops);
return $shops;
}
/**
* Retrieve if the user has done the onboarding or not
*
* @return bool
*/
private function isOnboardingDone(): bool
{
$configuration = new Configuration();
return (bool) $configuration->get('PS_SHIPPING_ONBOARDING_IS_DONE', false);
}
/**
* @param Router $router
*
* @return array<string, string>
*/
private function generateRouteLink(Router $router): array
{
return [
'home' => $router->generate('home'),
'createCarrier' => $router->generate('carrier_create'),
'toggleCarrier' => $router->generate('carrier_toggle_status'),
'getCarrier' => $router->generate('carrier_list'),
'carrierDetailLink' => $router->generate('carrier_admin_link'),
'toggleIsOnboardingDone' => $router->generate('onboarding_toggle_status'),
'oauthKeycloakCallback' => $this->getBaseURI('callback_oauth_keycloak'),
'getOrders' => $router->generate('list_orders'),
'getTrackingNumberForManifest' => $router->generate('get_last_tracking_number'),
'psAccountsDebugLink' => $this->getPsAccountsDebugLink(),
'orderStatusLink' => $this->getOrderStatusLink(),
'setDimensions' => $router->generate('save_dimensions_per_packages'),
'getDimensions' => $router->generate('get_dimensions_per_packages'),
'getAdvancedSetting' => $router->generate('get_advanced_setting'),
'setAdvancedSetting' => $router->generate('save_advanced_setting'),
'registerHooks' => $router->generate('register_hooks'),
'ordersLink' => $router->generate('admin_orders_index'),
'getOrdersStatus' => $router->generate('get_orders_status'),
'setOrderStatusMapping' => $router->generate('set_order_status_mapping'),
'setStatusForOrderStatusMapping' => $router->generate('set_status_for_order_status_mapping'),
'getStatusOrderStatusMapping' => $router->generate('get_status_order_status_mapping'),
'getStates' => $router->generate('get_states'),
];
}
/**
* @param string $route
*
* @return string
*/
private function getBaseURI(string $route)
{
$context = \Context::getContext();
if (!empty($context->link) && !empty($context->shop)) {
$redirectUri = $context->link->getAdminLink('KeycloakAuthController', true, [
'route' => $route,
]);
if (version_compare(_PS_VERSION_, '9.0.0', '>=')) {
return $redirectUri;
}
// in some strange cases that are still not identified, on some ps versions
// link->getAdminLink() generate also the base URI so we don't need go further and
// generate it again
if (strpos($redirectUri, 'http') !== false) {
return $redirectUri;
}
return rtrim((string) $context->shop->getBaseURL(true), '/') . $redirectUri;
}
return '';
}
private function getPsAccountsDebugLink(): string
{
$context = \Context::getContext();
if (!empty($context->link) && !empty($context->shop)) {
return $context->link->getAdminLink('AdminDebugPsAccounts');
}
return '';
}
private function getOrderStatusLink(): string
{
$context = \Context::getContext();
if (!empty($context->link) && !empty($context->shop)) {
return $context->link->getAdminLink('AdminStatuses');
}
return '';
}
/**
* @return array<string, bool>
*/
private function getActiveHooks()
{
$hooks = [];
$context = \Context::getContext();
if (!empty($context->link) && !empty($context->shop)) {
foreach (Psshipping::HOOK_LIST as $hook) {
$hooks[$hook] = \Hook::isModuleRegisteredOnHook($this->module, $hook, $context->shop->id);
}
}
return $hooks;
}
public function activateHooks(): Response
{
/* @phpstan-ignore-next-line */
$this->module->registerHook(Psshipping::HOOK_LIST);
return new Response(
json_encode([
'success' => true,
]),
200,
['Content-Type' => 'application/json']
);
}
}

View File

@@ -0,0 +1,57 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Controller\Admin;
use PrestaShop\Module\Psshipping\Exception\BadRequestException;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use PrestaShopBundle\Service\Routing\Router;
use Tools;
if (!defined('_PS_VERSION_')) {
exit();
}
class PsshippingKeycloakAuthController extends FrameworkBundleAdminController
{
public function oauthCallback(): void
{
/** @var Router $router */
$router = $this->get('router');
/** @var bool $callbackParam */
$callbackParam = (bool) Tools::getValue('keycloak-onboarding-success', false);
/** @var string $cbFromPage */
$cbFromPage = Tools::getValue('from-page', '');
$redirectUri = '';
if ($callbackParam === false) {
throw new BadRequestException('An error occured with keycloak oauth, missing callback parameter', 500);
}
$redirectUri = $router->generate('home') . '#/' . strval($cbFromPage);
Tools::redirectAdmin($redirectUri);
}
}

View File

@@ -0,0 +1,204 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Controller\Admin;
use Context as LegacyContext;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierService;
use PrestaShop\Module\Psshipping\Domain\Legacy\PrestaShopAdapter;
use PrestaShop\Module\Psshipping\Domain\Orders\OrdersService;
use PrestaShop\Module\Psshipping\Exception\BadRequestException;
use PrestaShop\PrestaShop\Adapter\Configuration;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use Psshipping;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
if (!defined('_PS_VERSION_')) {
exit();
}
class PsshippingOrdersController extends FrameworkBundleAdminController
{
/** @var Psshipping */
private $module;
/** @var CarrierService */
private $carrierService;
public function __construct(Psshipping $module, CarrierService $carrierService)
{
$this->module = $module;
$this->carrierService = $carrierService;
}
public function listOrdersAction(Request $request): Response
{
try {
$requestBodyContent = (array) json_decode((string) $request->getContent(false), true);
$carriers = $this->carrierService->get();
$itemPerPage = 10;
$pageNumber = 1;
$prestashopAdapter = new PrestaShopAdapter($this->module);
if (empty($requestBodyContent['pageNumber']) && $requestBodyContent['pageNumber'] < 0) {
return new Response(
json_encode([
'status' => false,
'error' => 'parameter pageNumber is not valid',
]),
400,
['Content-Type' => 'application/json']
);
}
if (empty($requestBodyContent['itemPerPage']) && $requestBodyContent['itemPerPage'] < 0) {
return new Response(
json_encode([
'status' => false,
'error' => 'parameter itemPerPage is not valid',
]),
400,
['Content-Type' => 'application/json']
);
}
if (is_int($requestBodyContent['pageNumber'])) {
$pageNumber = intval($requestBodyContent['pageNumber']);
}
if (is_int($requestBodyContent['itemPerPage'])) {
$itemPerPage = intval($requestBodyContent['itemPerPage']);
}
$offset = ($pageNumber - 1) * $itemPerPage;
$orders = (new OrdersService($this->module))->getOrdersByCustomCarriers($carriers, $prestashopAdapter, $itemPerPage, $offset);
$nbrOrders = intval($orders['ordersCount']);
$totalPages = ceil($nbrOrders / $itemPerPage);
return new Response(
json_encode([
'orders' => $orders['orders'],
'totalOrders' => $nbrOrders,
'pageNumber' => $pageNumber,
'totalPages' => $totalPages,
]),
200,
['Content-Type' => 'application/json']
);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
}
public function saveTrackingNumberAction(Request $request): Response
{
try {
$requestBodyContent = (array) json_decode((string) $request->getContent(false), true);
$orderId = 0;
$trackingNumber = '';
if (empty($requestBodyContent['trackingNumber']) && $requestBodyContent['orderId']) {
return new Response(
json_encode([
'status' => false,
'error' => 'Missing trackingNumber | orderId parameters',
]),
400,
['Content-Type' => 'application/json']
);
}
if (is_int($requestBodyContent['orderId'])) {
$orderId = intval($requestBodyContent['orderId']);
}
if (is_string($requestBodyContent['trackingNumber'])) {
$trackingNumber = (string) $requestBodyContent['trackingNumber'];
}
return new Response(
json_encode([
'status' => (new OrdersService($this->module))->saveTrackingNumber($orderId, $trackingNumber),
]),
200,
['Content-Type' => 'application/json']
);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
}
public function getTrackingNumberAction(): Response
{
try {
$carriersId = [];
$carriers = $this->carrierService->get();
foreach ($carriers as $carrier) {
foreach ($carrier as $carrierDetail) {
if ($carrierDetail && !empty($carrierDetail['id_carrier'])) {
$carriersId[] = (int) $carrierDetail['id_carrier'];
}
}
}
$getTrackingNumber = (new OrdersService($this->module))->getLastTrackingNumber($carriersId);
return new Response(
json_encode([
'trackingNumber' => $getTrackingNumber,
]),
200,
['Content-Type' => 'application/json']
);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
}
public function getOrdersStatusAction(): Response
{
try {
$configuration = new Configuration();
$mapping = '';
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
if (is_string($configuration->get('PS_SHIPPING_ORDER_STATUS_MAPPING', ''))) {
$mapping = $configuration->get('PS_SHIPPING_ORDER_STATUS_MAPPING', '');
}
$orderStatus = (new OrdersService($this->module))->getOrdersStatus();
return new Response(
json_encode([
'status' => $orderStatus,
'mapping' => json_decode($mapping) ?? [],
'isActivate' => (bool) $configuration->get('PS_SHIPPING_ORDER_MAPPING_IS_ACTIVATE', false),
]),
200,
['Content-Type' => 'application/json']
);
} catch (\Exception $e) {
throw new BadRequestException($e->getMessage(), $e->getCode());
}
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,45 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Accounts;
if (!defined('_PS_VERSION_')) {
exit();
}
abstract class AbstractAccountsType
{
/**
* @param string $name
*
* @return array<string, string|boolean|null>
*
* @throws AccountsIsNotInstalledException
*/
abstract public function present(string $name): array;
/**
* @return string
*/
abstract public function getOrRefreshToken();
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Accounts;
use PrestaShopExceptionCore;
if (!defined('_PS_VERSION_')) {
exit();
}
class AccountsIsNotInstalledException extends PrestaShopExceptionCore
{
}

View File

@@ -0,0 +1,104 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Accounts;
use PrestaShop\PrestaShop\Core\Addon\Module\ModuleManager as LegacyModuleManager;
use PrestaShop\PrestaShop\Core\Addon\Module\ModuleManagerBuilder;
use PrestaShop\PrestaShop\Core\Module\ModuleManager;
use PrestaShop\PsAccountsInstaller\Installer\Facade\PsAccounts;
use PrestaShop\PsAccountsInstaller\Installer\Installer as PsAccountsInstaller;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class AccountsService
{
/**
* @param Psshipping $module
*
* @return array<string, string|boolean|null>
*
* @throws AccountsIsNotInstalledException
*/
public function getAccountsContext(Psshipping $module, bool $onInstall = false): array
{
/** @var ModuleManagerBuilder $moduleManagerBuilder */
$moduleManagerBuilder = ModuleManagerBuilder::getInstance();
/** @var ModuleManager|LegacyModuleManager $moduleManager */
$moduleManager = $moduleManagerBuilder->build();
$psAccountsIsInstalled = $moduleManager->isInstalled('ps_accounts');
if (!$psAccountsIsInstalled) {
throw new AccountsIsNotInstalledException('PrestaShop accounts (ps_accounts) module is not installed, please install it.');
}
// we use this condition because we can't get the facade on install
if ($onInstall === true) {
/** @var PsAccounts $accounts */
$accounts = new PsAccounts(new PsAccountsInstaller('5'));
} else {
/** @var PsAccounts $accounts */
$accounts = $module->get('ps_accounts.facade');
}
/** @var AbstractAccountsType $accountPresenter */
$accountPresenter = $accounts->getPsAccountsPresenter();
return $accountPresenter->present($module->name);
}
public function getPsAccountToken(Psshipping $module): string
{
/** @var PsAccounts $accounts */
$accounts = $module->get('ps_accounts.facade');
/** @var AbstractAccountsType $accountService */
$accountService = $accounts->getPsAccountsService();
return $accountService->getOrRefreshToken();
}
public function getPsAccountCdnUrl(): string
{
/** @var ModuleManagerBuilder $moduleManagerBuilder */
$moduleManagerBuilder = ModuleManagerBuilder::getInstance();
/** @var ModuleManager|LegacyModuleManager $moduleManager */
$moduleManager = $moduleManagerBuilder->build();
if ($moduleManager->isInstalled('ps_accounts')) {
$accountsModule = \Module::getInstanceByName('ps_accounts');
if ($accountsModule && version_compare($accountsModule->version, '7', '>=')) {
/* @phpstan-ignore-next-line */
$accountsCdn = $accountsModule->getParameter('ps_accounts.accounts_cdn_url');
}
}
return $accountsCdn ?? 'https://unpkg.com/prestashop_accounts_vue_components@5';
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,124 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Api;
use Context as LegacyContext;
use PrestaShop\Module\Psshipping\Domain\Accounts\AccountsService;
use PrestaShop\Module\Psshipping\Domain\Http\HttpClient;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
use PrestaShop\PrestaShop\Adapter\Configuration;
use Psshipping;
class Webhook
{
/** @var Psshipping */
private $module;
public function __construct(Psshipping $module)
{
$this->module = $module;
}
/**
* @param string $svixSecret
*
* @return void
*
* @throws PsshippingException
*/
public function createSvixEndpoint(string $svixSecret)
{
$jwt = (new AccountsService())->getPsAccountToken($this->module);
$configuration = new Configuration();
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
$httpClient = new HttpClient($this->module->getApiUrl());
$httpClient->setHeaders([
'Accept: application/json',
'Authorization: Bearer ' . $jwt,
'Content-Type: application/json',
]);
$response = $httpClient->post('/shipment-status/webhook', (string) json_encode([
'svixSecret' => $svixSecret,
]));
if (substr(strval($response->getStatusCode()), 0, 1) !== '2') {
throw new PsshippingException('An error occured while sending the secret to the API.', 400);
}
$configuration->set('PS_SHIPPING_WEBHOOK_SECRET', $svixSecret);
}
public function deleteSvixEndpoint(): void
{
// if accounts is not installed, we cannot anymore proceed to the deletion
// of svix endpoint, catch and silent the error in this case in order to
// not block the uninstall() process
try {
$jwt = (new AccountsService())->getPsAccountToken($this->module);
} catch (\Exception $exception) {
return;
}
if (empty($jwt)) {
return;
}
$configuration = new Configuration();
$context = LegacyContext::getContext();
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
$response = (new HttpClient($this->module->getApiUrl()))->setHeaders([
'Accept: application/json',
'Authorization: Bearer ' . $jwt,
'Content-Type: application/json',
])->delete('/shipment-status/webhook');
if (substr(strval($response->getStatusCode()), 0, 1) !== '2') {
throw new PsshippingException('An error occured while removing the svix endpoint to the API.', 400, false);
}
}
private function generateSvixSecret(): string
{
return 'whsec_' . base64_encode(random_bytes(24));
}
/**
* @throws PsshippingException
*/
public function saveSvixSecret(): void
{
$this->createSvixEndpoint(
$this->generateSvixSecret()
);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,45 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Billing;
if (!defined('_PS_VERSION_')) {
exit();
}
abstract class AbstractBillingType
{
/**
* @param array<string> $billingOptions
*
* @return array<string, array<string|bool|null>>
*
* @throws BillingContextIsNotAvailableException
*/
abstract public function present($billingOptions): array;
/**
* @return array<string, array<string|bool|null>>
*/
abstract public function getCurrentSubscription(): array;
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Billing;
use PrestaShopExceptionCore;
if (!defined('_PS_VERSION_')) {
exit();
}
class BillingContextIsNotAvailableException extends PrestaShopExceptionCore
{
}

View File

@@ -0,0 +1,80 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Billing;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class BillingService
{
/**
* @param Psshipping $module
*
* @return array<string, string|boolean|null>
*
* @throws BillingContextIsNotAvailableException
*/
public function getBillingContext(Psshipping $module)
{
/** @var AbstractBillingType $billingFacade */
$billingFacade = $module->getService('psshipping.ps_billings_facade');
$shippingLogo = $module->getLocalPath() . 'views/img/shipping-logo.png';
$psBillingContext = $billingFacade->present([
'logo' => $shippingLogo,
'tosLink' => 'https://prestashop.com/prestashop-account-terms-conditions/',
'privacyLink' => 'https://prestashop.com/prestashop-account-privacy/',
'emailSupport' => 'support@prestashop.com',
]);
if (empty($psBillingContext['psBillingContext'])) {
throw new BillingContextIsNotAvailableException('Billing context is empty');
}
return $psBillingContext['psBillingContext'];
}
/**
* @param Psshipping $module
*
* @return bool
**/
public function hasActiveSubscription(Psshipping $module)
{
/** @var AbstractBillingType $billingService */
$billingService = $module->getService('psshipping.ps_billings_service');
$currentSubscription = $billingService->getCurrentSubscription();
$subscription = [];
// We test here the success of the request in the response's body.
if (!empty($currentSubscription['success'])) {
$subscription = $currentSubscription['body'];
}
return !empty($subscription);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,39 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers;
if (!defined('_PS_VERSION_')) {
exit();
}
abstract class CarrierConfiguration implements CarrierConfigurationInterface
{
/** @var string mbe tracking url */
protected $mbe_tracking_url;
public function __construct(string $mbe_tracking_url)
{
$this->mbe_tracking_url = $mbe_tracking_url;
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers;
if (!defined('_PS_VERSION_')) {
exit();
}
interface CarrierConfigurationInterface
{
/**
* @return CarrierDto
*/
public function transform();
}

View File

@@ -0,0 +1,244 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers;
use Carrier;
use Language;
use ZoneCore;
if (!defined('_PS_VERSION_')) {
exit();
}
class CarrierDto
{
/** @var string Name */
private $name;
/** @var string URL with a '@' for */
private $trackingUrl;
/** @var bool */
private $freeShipping;
/** @var string[] */
private $ranges;
/** @var string Delay needed to deliver customer */
private $delay;
/** @var bool */
private $active;
/** @var bool True if carrier has been deleted (staying in database as deleted) */
private $deleted;
/** @var bool Behavior for out-of-range weights: true to disable carrier, false to apply the cost of the highest defined range */
private $rangeBehavior;
/** @var int maximum package width managed by the transporter */
private $maxWidth;
/** @var int maximum package height managed by the transporter */
private $maxHeight;
/** @var int maximum package deep managed by the transporter */
private $maxDepth;
/** @var int maximum package weight managed by the transporter */
private $maxWeight;
/** @var int grade of the shipping delay (0 for longest, 9 for shortest) */
private $grade;
/** @var string */
private $externalModuleName;
/** @var string */
private $type;
/** @var string */
private $provider;
public function __construct(
string $name,
string $trackingUrl,
bool $freeShipping,
bool $active,
bool $deleted,
bool $range_behavior,
int $max_width,
int $max_height,
int $max_depth,
int $max_weight,
int $grade,
string $externalModuleName,
string $type,
string $provider
) {
$this->name = $name;
$this->trackingUrl = $trackingUrl;
$this->freeShipping = $freeShipping;
$this->active = $active;
$this->deleted = $deleted;
$this->rangeBehavior = $range_behavior;
$this->maxWidth = $max_width;
$this->maxHeight = $max_height;
$this->maxDepth = $max_depth;
$this->maxWeight = $max_weight;
$this->name = $name;
$this->trackingUrl = $trackingUrl;
$this->freeShipping = $freeShipping;
$this->setTransitTimeWithLangs();
$this->active = $active;
$this->deleted = $deleted;
$this->rangeBehavior = $range_behavior;
$this->maxWidth = $max_width;
$this->maxHeight = $max_height;
$this->maxDepth = $max_depth;
$this->maxWeight = $max_weight;
$this->grade = $grade;
$this->setShippingZones();
$this->externalModuleName = $externalModuleName;
$this->type = $type;
$this->provider = $provider;
}
/**
* @param Carrier $carrier
*
* @return CarrierDto
*/
public static function toDomain(Carrier $carrier, string $type, string $provider)
{
return new CarrierDto(
$carrier->name,
$carrier->url,
$carrier->is_free,
$carrier->active,
$carrier->deleted,
$carrier->range_behavior,
$carrier->max_width,
$carrier->max_height,
$carrier->max_depth,
$carrier->max_weight,
$carrier->grade,
$carrier->external_module_name,
$type,
$provider
);
}
/**
* @param CarrierDto $carrierDto
*
* @return Carrier
*/
public static function fromDomain(CarrierDto $carrierDto)
{
$carrier = new Carrier();
$carrier->name = $carrierDto->name;
$carrier->url = $carrierDto->trackingUrl;
$carrier->is_free = $carrierDto->freeShipping;
$carrier->delay = $carrierDto->delay;
$carrier->active = $carrierDto->active;
$carrier->deleted = $carrierDto->deleted;
$carrier->range_behavior = $carrierDto->rangeBehavior;
$carrier->max_width = $carrierDto->maxWidth;
$carrier->max_height = $carrierDto->maxHeight;
$carrier->max_depth = $carrierDto->maxDepth;
$carrier->max_weight = $carrierDto->maxWeight;
$carrier->external_module_name = $carrierDto->externalModuleName;
$carrier->active = $carrierDto->active;
$carrier->grade = $carrierDto->grade;
$carrier->shipping_handling = false;
$carrier->is_module = true;
$carrier->need_range = true;
return $carrier;
}
private function setShippingZones(): void
{
$zones = ZoneCore::getZones(true);
foreach ($zones as $zone) {
$this->ranges[] = $zone['id_zone'];
}
}
private function setTransitTimeWithLangs(): void
{
$langs = Language::getLanguages(true);
foreach ($langs as $lang) {
if (!empty($lang['id_lang'])) {
$this->delay[$lang['id_lang']] = '1-4 days';
}
}
}
/**
* @return array<string>
*/
public function getRanges()
{
return $this->ranges;
}
public function getType(): string
{
return $this->type;
}
public function getProvider(): string
{
return $this->provider;
}
/**
* @return array<string, array<string>|bool|int|string>
*/
public function jsonSerialize()
{
return [
'name' => $this->name,
'tracking_url' => $this->trackingUrl,
'free_shipping' => $this->freeShipping,
'ranges' => $this->ranges,
'delay' => $this->delay,
'active' => $this->active,
'deleted' => $this->deleted,
'range_behavior' => $this->rangeBehavior,
'max_width' => $this->maxWidth,
'max_height' => $this->maxHeight,
'max_depth' => $this->maxDepth,
'max_weight' => $this->maxWeight,
'external_module_name' => $this->externalModuleName,
'type' => $this->type,
'provider' => $this->provider,
];
}
}

View File

@@ -0,0 +1,155 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers;
use Carrier;
use Configuration;
use Context;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Statement;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class CarrierRepository
{
/**
* @var Connection
*/
private $connection;
/**
* @var string
*/
private $dbPrefix;
/**
* @var Psshipping
*/
private $module;
const PS_SHIPPING_CARRIER = 'PS_SHIPPING_CARRIER';
/**
* @param Psshipping $module
*/
public function __construct(Psshipping $module)
{
$this->module = $module;
$this->dbPrefix = _DB_PREFIX_;
/** @var Connection $connection */
$connection = $this->module->getService('doctrine.dbal.default_connection');
$this->connection = $connection;
}
/**
* @param bool $active
*
* @return Carrier[]
*/
public function getCarriers($active = false)
{
$context = Context::getContext();
if (!empty($context->language) && !empty($context->language->id)) {
$qb = $this->connection->createQueryBuilder();
$qb->select('c.*, cl.delay');
$qb->from($this->dbPrefix . 'carrier', 'c');
$qb->leftJoin('c', $this->dbPrefix . 'carrier_lang', 'cl', 'c.id_carrier = cl.id_carrier');
$qb->leftJoin('c', $this->dbPrefix . 'carrier_zone', 'cz', 'c.id_carrier = c.id_carrier');
if ($active) {
$qb->where('c.active = 1');
}
$qb->where('c.is_module = 1');
$qb->andWhere("c.external_module_name = 'psshipping'");
$qb->groupBy('c.id_carrier');
$qb->orderBy('c.id_carrier', 'DESC');
$qb->setParameter('id_lang', (int) $context->language->id);
/** @var Statement $execute */
$execute = $qb->execute();
/** @var Carrier[] */
$result = $execute->fetchAll();
return $result;
}
return [];
}
/**
* @return array<int, array{type: string, provider: string}>
*/
public function getShippingCarriersMapping(): array
{
$mapping = Configuration::get(self::PS_SHIPPING_CARRIER);
// Return type is wrong on Configuration::get before PS 1.7.8
// @phpstan-ignore function.alreadyNarrowedType
if (!is_string($mapping)) {
return [];
}
/** @var array<int, array{type: string, provider: string}> $value */
$value = json_decode($mapping, true);
return $value;
}
public function addShippingCarrierMapping(int $carrierId, string $type, string $provider): void
{
$mapping = $this->getShippingCarriersMapping();
$mapping[$carrierId] = [
'type' => $type,
'provider' => $provider,
];
Configuration::updateGlobalValue(self::PS_SHIPPING_CARRIER, json_encode($mapping));
}
/**
* @param array<int, array{type: string, provider: string}> $mapping
*/
public function updateShippingCarrierMapping(array $mapping): void
{
Configuration::updateGlobalValue(self::PS_SHIPPING_CARRIER, json_encode($mapping));
}
public function isPickupCarrierFromMapping(int $currentCarrierId): bool
{
$carrierMapping = $this->getShippingCarriersMapping();
foreach ($carrierMapping as $carrierId => $carrierDetail) {
if ($currentCarrierId === $carrierId && CarrierService::CARRIERS_PICKUP === $carrierDetail['type']) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,241 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers;
use Carrier;
use Configuration;
use Context;
use Group;
use PrestaShop\Module\Psshipping\Domain\Carriers\Exception\CannotAddLogoToCarrierException;
use PrestaShop\Module\Psshipping\Domain\Carriers\Exception\UnableToFindCarrierException;
use PrestaShop\Module\Psshipping\Domain\Legacy\PrestaShopAdapter;
use PrestaShop\PrestaShop\Core\CommandBus\CommandBusInterface;
use PrestaShop\PrestaShop\Core\Domain\Carrier\Command\ToggleCarrierStatusCommand;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class CarrierService
{
/** @var CommandBusInterface */
private $commandBus;
/** @var CarrierRepository */
private $carrierRepository;
/** @var Psshipping */
private $module;
const CARRIERS_STANDARD = 'standard';
const CARRIERS_EXPRESS = 'express';
const CARRIERS_PICKUP = 'pickup';
const PROVIDER_MBE = 'mbe';
const PROVIDER_UPS = 'ups';
public function __construct(Psshipping $module, CarrierRepository $carrierRepository)
{
/** @var CommandBusInterface $commandBus */
$commandBus = $module->getService('prestashop.core.command_bus');
$this->module = $module;
$this->commandBus = $commandBus;
$this->carrierRepository = $carrierRepository;
}
/**
* @param CarrierConfiguration $carrierConfiguration
*
* @return CarrierDto
*/
public function create($carrierConfiguration)
{
$carrierDto = $carrierConfiguration->transform();
$carrier = CarrierDto::fromDomain($carrierDto);
if ($this->isCarrierExists($carrierDto)) {
return CarrierDto::toDomain($carrier, $carrierDto->getType(), $carrierDto->getProvider());
}
$context = \Context::getContext();
$carrier->save();
if (!empty($carrier->id)) {
$this->setLogoToCarrier(intval($carrier->id), $carrierDto->getProvider());
}
$carrier->setTaxRulesGroup((int) Configuration::get('PS_TAX'), false);
$this->carrierRepository->addShippingCarrierMapping((int) $carrier->id, $carrierDto->getType(), $carrierDto->getProvider());
if (!empty($context->language) && !empty($context->language->id)) {
$carrier->setGroups(array_column(Group::getGroups($context->language->id), 'id_group'));
}
return CarrierDto::toDomain($carrier, $carrierDto->getType(), $carrierDto->getProvider());
}
public function update(): void
{
foreach ($this->get() as $carrierDetails) {
foreach ($carrierDetails as $detail) {
if (!empty($detail['id_carrier'])) {
$carrierCore = new Carrier((int) $detail['id_carrier']);
$carrierCore->deleted = false;
$carrierCore->update();
}
}
}
}
public function delete(): void
{
foreach ($this->get() as $carrierDetails) {
foreach ($carrierDetails as $detail) {
if (!empty($detail['id_carrier'])) {
$carrierCore = new Carrier((int) $detail['id_carrier']);
$carrierCore->deleted = true;
$carrierCore->update();
}
}
}
}
/**
* @return array{
* standard: array{mbe: Carrier|null, ups: Carrier|null},
* express: array{mbe: Carrier|null, ups: Carrier|null},
* pickup: array{mbe: Carrier|null, ups: Carrier|null}
* }
*/
public function get()
{
$carrierFromModule = [
'standard' => [
'mbe' => null,
'ups' => null,
],
'express' => [
'mbe' => null,
'ups' => null,
],
'pickup' => [
'mbe' => null,
'ups' => null,
],
];
$context = Context::getContext();
if (!empty($context->link)) {
$findCarriers = $this->carrierRepository->getCarriers();
$mapping = $this->carrierRepository->getShippingCarriersMapping();
foreach ($findCarriers as $carrier) {
$carrier['id_carrier'] = (int) $carrier['id_carrier'];
$carrier['detailLink'] = (new PrestaShopAdapter($this->module))->generateEditCarrierLink((int) $carrier['id_carrier']);
foreach ($mapping as $idCarrier => $carrierType) {
if ((int) $idCarrier === $carrier['id_carrier']) {
$type = $carrierType;
$provider = null;
// need this condition to avoid error when upgrading because the carrier mapping format changed
/* @phpstan-ignore-next-line */
if (is_array($carrierType)) {
$type = $carrierType['type'];
$provider = $carrierType['provider'];
}
if (in_array($type, ['standard', 'express', 'pickup']) && in_array($provider, ['mbe', 'ups'])) {
$carrierFromModule[$type][$provider] = $carrier;
}
}
}
}
}
return $carrierFromModule;
}
public function toggle(int $carrierId): bool
{
try {
if (version_compare(_PS_VERSION_, '1.7.7.0', '>=')) {
$this->commandBus->handle(new ToggleCarrierStatusCommand($carrierId));
return (bool) (new Carrier($carrierId))->active;
} else {
$carrier = new Carrier((int) $carrierId);
$carrier->active = !$carrier->active;
return true;
}
} catch (\Throwable $th) {
throw new UnableToFindCarrierException($th->getMessage(), $th->getCode());
}
}
/**
* @param CarrierDto $carrier
*/
private function isCarrierExists($carrier): bool
{
$allShippingCarriers = $this->get();
$mapping = $this->carrierRepository->getShippingCarriersMapping();
$currentCarrierValue = $allShippingCarriers[$carrier->getType()][$carrier->getProvider()];
if ($currentCarrierValue !== null && in_array($currentCarrierValue['id_carrier'], array_keys($mapping))) {
if (filter_var($currentCarrierValue['deleted'], FILTER_VALIDATE_BOOLEAN) === true) {
$this->setLogoToCarrier($currentCarrierValue['id_carrier'], $carrier->getProvider());
$this->enableCarrier($currentCarrierValue['id_carrier']);
}
return true;
}
return false;
}
/**
* @param int $carrierId
*/
private function enableCarrier($carrierId): void
{
$carrier = new Carrier((int) $carrierId);
$carrier->deleted = false;
$carrier->update();
}
/**
* @param int $carrierId
* @param string $provider
*/
public function setLogoToCarrier(int $carrierId, string $provider): void
{
$imageSource = _PS_MODULE_DIR_ . 'psshipping/views/img/' . $provider . '.png';
$imageDest = _PS_SHIP_IMG_DIR_ . $carrierId . '.jpg';
if (!copy($imageSource, $imageDest)) {
throw new CannotAddLogoToCarrierException('An error occured while copying img');
}
}
}

View File

@@ -0,0 +1,38 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers\Exception;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
if (!defined('_PS_VERSION_')) {
exit();
}
class CannotAddLogoToCarrierException extends PsshippingException
{
public function __construct(string $message, int $code = 0, bool $throwable = true)
{
parent::__construct($message, $code, $throwable);
}
}

View File

@@ -0,0 +1,38 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers\Exception;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
if (!defined('_PS_VERSION_')) {
exit();
}
class UnableToFindCarrierException extends PsshippingException
{
public function __construct(string $message, int $code = 0, bool $throwable = true)
{
parent::__construct($message, $code, $throwable);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,70 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class MbeExpressCarrierConfiguration extends CarrierConfiguration
{
const DEFAULT_CONFIGURATION = [
'name' => 'MBE Express delivery',
'freeShipping' => false,
'active' => false,
'deleted' => false,
'range_behavior' => false,
'max_width' => 0,
'max_height' => 0,
'max_depth' => 0,
'max_weight' => 20,
'grade' => 0,
'external_module_name' => Psshipping::MODULE_TECHNICAL_NAME,
];
/**
* @return CarrierDto
*/
public function transform()
{
return new CarrierDto(
self::DEFAULT_CONFIGURATION['name'],
$this->mbe_tracking_url,
self::DEFAULT_CONFIGURATION['freeShipping'],
self::DEFAULT_CONFIGURATION['active'],
self::DEFAULT_CONFIGURATION['deleted'],
self::DEFAULT_CONFIGURATION['range_behavior'],
self::DEFAULT_CONFIGURATION['max_width'],
self::DEFAULT_CONFIGURATION['max_height'],
self::DEFAULT_CONFIGURATION['max_depth'],
self::DEFAULT_CONFIGURATION['max_weight'],
self::DEFAULT_CONFIGURATION['grade'],
self::DEFAULT_CONFIGURATION['external_module_name'],
CarrierService::CARRIERS_EXPRESS,
CarrierService::PROVIDER_MBE
);
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class MbePickupCarrierConfiguration extends CarrierConfiguration
{
const DEFAULT_CONFIGURATION = [
'name' => 'MBE Pick-up point',
'freeShipping' => false,
'active' => false,
'deleted' => false,
'range_behavior' => false,
'max_width' => 0,
'max_height' => 0,
'max_depth' => 0,
'max_weight' => 20,
'grade' => 5,
'external_module_name' => Psshipping::MODULE_TECHNICAL_NAME,
];
/**
* @return CarrierDto
*/
public function transform()
{
return new CarrierDto(
self::DEFAULT_CONFIGURATION['name'],
$this->mbe_tracking_url,
self::DEFAULT_CONFIGURATION['freeShipping'],
self::DEFAULT_CONFIGURATION['active'],
self::DEFAULT_CONFIGURATION['deleted'],
self::DEFAULT_CONFIGURATION['range_behavior'],
self::DEFAULT_CONFIGURATION['max_width'],
self::DEFAULT_CONFIGURATION['max_height'],
self::DEFAULT_CONFIGURATION['max_depth'],
self::DEFAULT_CONFIGURATION['max_weight'],
self::DEFAULT_CONFIGURATION['grade'],
self::DEFAULT_CONFIGURATION['external_module_name'],
CarrierService::CARRIERS_PICKUP,
CarrierService::PROVIDER_MBE
);
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class MbeStandardCarrierConfiguration extends CarrierConfiguration
{
const DEFAULT_CONFIGURATION = [
'name' => 'MBE Standard delivery',
'freeShipping' => false,
'active' => false,
'deleted' => false,
'range_behavior' => false,
'max_width' => 0,
'max_height' => 0,
'max_depth' => 0,
'max_weight' => 20,
'grade' => 0,
'external_module_name' => Psshipping::MODULE_TECHNICAL_NAME,
];
/**
* @return CarrierDto
*/
public function transform()
{
return new CarrierDto(
self::DEFAULT_CONFIGURATION['name'],
$this->mbe_tracking_url,
self::DEFAULT_CONFIGURATION['freeShipping'],
self::DEFAULT_CONFIGURATION['active'],
self::DEFAULT_CONFIGURATION['deleted'],
self::DEFAULT_CONFIGURATION['range_behavior'],
self::DEFAULT_CONFIGURATION['max_width'],
self::DEFAULT_CONFIGURATION['max_height'],
self::DEFAULT_CONFIGURATION['max_depth'],
self::DEFAULT_CONFIGURATION['max_weight'],
self::DEFAULT_CONFIGURATION['grade'],
self::DEFAULT_CONFIGURATION['external_module_name'],
CarrierService::CARRIERS_STANDARD,
CarrierService::PROVIDER_MBE
);
}
}

View File

@@ -0,0 +1,76 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use PrestaShop\Module\Psshipping\Entity\PsshippingAddressOrders;
/**
* @extends ServiceEntityRepository<PsshippingAddressOrders>
*/
class PsshippingAddressOrdersRepository extends ServiceEntityRepository
{
public function __construct(\Psshipping $module)
{
/** @var ManagerRegistry $registry */
$registry = $module->getService('doctrine');
parent::__construct($registry, PsshippingAddressOrders::class);
}
public function add(PsshippingAddressOrders $mapping, bool $flush = true): PsshippingAddressOrders
{
$em = $this->getEntityManager();
$em->persist($mapping);
if ($flush) {
$em->flush();
}
return $mapping;
}
public function remove(PsshippingAddressOrders $mapping, bool $flush = true): void
{
$em = $this->getEntityManager();
$em->remove($mapping);
if ($flush) {
$em->flush();
}
}
public function findOneByIdOrderAndShop(int $idOrder, int $idShop): ?PsshippingAddressOrders
{
$qb = $this->createQueryBuilder('o')
->andWhere('o.idOrder = :order')
->andWhere('o.idShop = :shop')
->setParameters([
'order' => $idOrder,
'shop' => $idShop,
]);
/** @var PsshippingAddressOrders|null $result */
$result = $qb->getQuery()->getOneOrNullResult();
return $result;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use PrestaShop\Module\Psshipping\Entity\PsshippingAddress;
/**
* @extends ServiceEntityRepository<PsshippingAddress>
*/
class PsshippingAddressRepository extends ServiceEntityRepository
{
public function __construct(\Psshipping $module)
{
/** @var ManagerRegistry $registry */
$registry = $module->getService('doctrine');
parent::__construct($registry, PsshippingAddress::class);
}
public function add(PsshippingAddress $address, bool $flush = true): PsshippingAddress
{
$existing = $this->findOneByPickupPointId($address->getPickupPointId());
if ($existing) {
return $existing;
}
$entityManager = $this->getEntityManager();
$entityManager->persist($address);
if ($flush) {
$entityManager->flush();
}
return $address;
}
public function findOneById(int $id): ?PsshippingAddress
{
return $this->find($id);
}
public function findOneByPickupPointId(int $pickupPointId): ?PsshippingAddress
{
$qb = $this->createQueryBuilder('a')
->andWhere('a.pickupPointId = :ppid')
->setParameter('ppid', $pickupPointId);
/** @var PsshippingAddress|null $result */
$result = $qb->getQuery()->getOneOrNullResult();
return $result;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,70 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class UpsExpressCarrierConfiguration extends CarrierConfiguration
{
const DEFAULT_CONFIGURATION = [
'name' => 'UPS DAP Express delivery',
'freeShipping' => false,
'active' => false,
'deleted' => false,
'range_behavior' => false,
'max_width' => 0,
'max_height' => 0,
'max_depth' => 0,
'max_weight' => 20,
'grade' => 0,
'external_module_name' => Psshipping::MODULE_TECHNICAL_NAME,
];
/**
* @return CarrierDto
*/
public function transform()
{
return new CarrierDto(
self::DEFAULT_CONFIGURATION['name'],
$this->mbe_tracking_url,
self::DEFAULT_CONFIGURATION['freeShipping'],
self::DEFAULT_CONFIGURATION['active'],
self::DEFAULT_CONFIGURATION['deleted'],
self::DEFAULT_CONFIGURATION['range_behavior'],
self::DEFAULT_CONFIGURATION['max_width'],
self::DEFAULT_CONFIGURATION['max_height'],
self::DEFAULT_CONFIGURATION['max_depth'],
self::DEFAULT_CONFIGURATION['max_weight'],
self::DEFAULT_CONFIGURATION['grade'],
self::DEFAULT_CONFIGURATION['external_module_name'],
CarrierService::CARRIERS_EXPRESS,
CarrierService::PROVIDER_UPS
);
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Carriers;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class UpsStandardCarrierConfiguration extends CarrierConfiguration
{
const DEFAULT_CONFIGURATION = [
'name' => 'UPS DAP Standard delivery',
'freeShipping' => false,
'active' => false,
'deleted' => false,
'range_behavior' => false,
'max_width' => 0,
'max_height' => 0,
'max_depth' => 0,
'max_weight' => 20,
'grade' => 0,
'external_module_name' => Psshipping::MODULE_TECHNICAL_NAME,
];
/**
* @return CarrierDto
*/
public function transform()
{
return new CarrierDto(
self::DEFAULT_CONFIGURATION['name'],
$this->mbe_tracking_url,
self::DEFAULT_CONFIGURATION['freeShipping'],
self::DEFAULT_CONFIGURATION['active'],
self::DEFAULT_CONFIGURATION['deleted'],
self::DEFAULT_CONFIGURATION['range_behavior'],
self::DEFAULT_CONFIGURATION['max_width'],
self::DEFAULT_CONFIGURATION['max_height'],
self::DEFAULT_CONFIGURATION['max_depth'],
self::DEFAULT_CONFIGURATION['max_weight'],
self::DEFAULT_CONFIGURATION['grade'],
self::DEFAULT_CONFIGURATION['external_module_name'],
CarrierService::CARRIERS_STANDARD,
CarrierService::PROVIDER_UPS
);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,71 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\GelProximity;
use PrestaShop\Module\Psshipping\Domain\Accounts\AccountsService;
use PrestaShop\Module\Psshipping\Domain\GelProximity\Models\GelProximityCredentials;
use PrestaShop\Module\Psshipping\Domain\Http\HttpClient;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
use Psshipping;
class GelProximityService
{
/** @var Psshipping */
private $module;
public function __construct(Psshipping $module)
{
$this->module = $module;
}
/**
* @throws PsshippingException
*/
public function getGelCredentials(): GelProximityCredentials
{
$jwt = (new AccountsService())->getPsAccountToken($this->module);
$httpClient = new HttpClient($this->module->getApiUrl());
$httpClient->setHeaders([
'Accept: application/json',
'Authorization: Bearer ' . $jwt,
'Content-Type: application/json',
]);
$response = $httpClient->get('/user/gel-config');
if (substr(strval($response->getStatusCode()), 0, 1) !== '2') {
throw new PsshippingException(sprintf('An error occured while sending the secret to the API (details: %s)', $response->getError()), 400);
}
/** @var array{'merchantCode': string, 'apiKey': string} $config */
$config = json_decode($response->getBody(), true);
return GelProximityCredentials::fromArray($config);
}
public static function buildSessionReference(int $cartId): string
{
return 'PickupPointCartId-' . (string) $cartId;
}
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\GelProximity\Models;
if (!defined('_PS_VERSION_')) {
exit();
}
class GelProximityCredentials
{
/**
* @var string
*/
private $merchantCode;
/**
* @var string
*/
private $apiKey;
/**
* @param string $merchantCode
* @param string $apiKey
*/
public function __construct(string $merchantCode, string $apiKey)
{
$this->merchantCode = $merchantCode;
$this->apiKey = $apiKey;
}
/**
* @param array{
* merchantCode: string,
* apiKey: string
* } $data
*
* @return self
*/
public static function fromArray(array $data): self
{
return new self($data['merchantCode'], $data['apiKey']);
}
/**
* @return array{
* merchantCode: string,
* apiKey: string
* }
*/
public function toArray(): array
{
return [
'merchantCode' => $this->merchantCode,
'apiKey' => $this->apiKey,
];
}
public function getMerchantCode(): string
{
return $this->merchantCode;
}
public function setMerchantCode(string $merchantCode): void
{
$this->merchantCode = $merchantCode;
}
public function getApiKey(): string
{
return $this->apiKey;
}
public function setApiKey(string $apiKey): void
{
$this->apiKey = $apiKey;
}
}

View File

@@ -0,0 +1,386 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\GelProximity\Models;
use Exception;
use PrestaShop\Module\Psshipping\Entity\PsshippingAddress;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
if (!defined('_PS_VERSION_')) {
exit();
}
class PickupPoint
{
private const COOKIES_PREFIX = 'ps_shipping_';
/**
* @var int
*/
private $pickupPointId;
/**
* @var string
*/
private $networkCode;
/**
* @var string
*/
private $code;
/**
* @var string
*/
private $description;
/**
* @var string
*/
private $address;
/**
* @var string
*/
private $city;
/**
* @var string
*/
private $zipCode;
/**
* @var string|null
*/
private $department;
/**
* @var string
*/
private $country;
/**
* PickupPoint constructor.
*
* @param array{
* pickupPointId: int,
* networkCode: string,
* code: string,
* address: string,
* description: string,
* city: string,
* zipCode: string,
* department: string|null,
* country: string
* } $data
*/
public function __construct(array $data)
{
$this->pickupPointId = (int) $data['pickupPointId'];
$this->networkCode = $data['networkCode'];
$this->code = $data['code'];
$this->address = $data['address'];
$this->description = $data['description'];
$this->city = $data['city'];
$this->zipCode = $data['zipCode'];
$this->department = isset($data['department']) ? $data['department'] : null;
$this->country = $data['country'];
$this->address = $data['address'];
}
// --- Getters ---
public function getPickupPointId(): int
{
return $this->pickupPointId;
}
public function getNetworkCode(): string
{
return $this->networkCode;
}
public function getCode(): string
{
return $this->code;
}
public function getDescription(): string
{
return $this->description;
}
public function getAddress(): string
{
return $this->address;
}
public function getCity(): string
{
return $this->city;
}
public function getZipCode(): string
{
return $this->zipCode;
}
public function getDepartment(): ?string
{
return $this->department;
}
public function getCountry(): string
{
return $this->country;
}
// --- Setters ---
public function setPickupPointId(int $pickupPointId): void
{
$this->pickupPointId = $pickupPointId;
}
public function setNetworkCode(string $networkCode): void
{
$this->networkCode = $networkCode;
}
public function setCode(string $code): void
{
$this->code = $code;
}
public function setDescription(string $description): void
{
$this->description = $description;
}
public function setAddress(string $address): void
{
$this->address = $address;
}
public function setCity(string $city): void
{
$this->city = $city;
}
public function setZipCode(string $zipCode): void
{
$this->zipCode = $zipCode;
}
public function setDepartment(?string $department): void
{
$this->department = $department;
}
public function setCountry(string $country): void
{
$this->country = $country;
}
/**
* @param array{
* pickupPointId: int,
* networkCode: string,
* code: string,
* address: string,
* description: string,
* city: string,
* zipCode: string,
* department: string|null,
* country: string
* } $data
*/
public static function fromArray(array $data): self
{
return new self($data);
}
/** @return array{
* pickupPointId: int,
* networkCode: string,
* code: string,
* address: string,
* description: string,
* city: string,
* zipCode: string,
* department: string|null,
* country: string
* }
*/
public function toArray(): array
{
return [
'pickupPointId' => $this->pickupPointId,
'networkCode' => $this->networkCode,
'code' => $this->code,
'description' => $this->description,
'city' => $this->city,
'zipCode' => $this->zipCode,
'department' => $this->department,
'country' => $this->country,
'address' => $this->address,
];
}
/**
* @param \Context $context
*
* @return void
*
* @throws Exception
*/
public function injectIntoCookies($context)
{
if ($context->cookie === null) {
throw new PsshippingException("The 'cookie' field is null in the context.");
}
$context->cookie->__set(self::COOKIES_PREFIX . 'pickupPointId', $this->getPickupPointId());
$context->cookie->__set(self::COOKIES_PREFIX . 'networkCode', $this->getNetworkCode());
$context->cookie->__set(self::COOKIES_PREFIX . 'code', $this->getCode());
$context->cookie->__set(self::COOKIES_PREFIX . 'description', $this->getDescription());
$context->cookie->__set(self::COOKIES_PREFIX . 'city', $this->getCity());
$context->cookie->__set(self::COOKIES_PREFIX . 'zipCode', $this->getZipCode());
$context->cookie->__set(self::COOKIES_PREFIX . 'department', $this->getDepartment());
$context->cookie->__set(self::COOKIES_PREFIX . 'country', $this->getCountry());
$context->cookie->__set(self::COOKIES_PREFIX . 'address', $this->getaddress());
}
/**
* @param \Context $context
*
* @return self
*
* @throws PsshippingException
*/
public static function fromCookies($context)
{
if ($context->cookie === null) {
throw new PsshippingException("The 'cookie' field is null in the context.");
}
$requiredKeys = [
'pickupPointId',
'networkCode',
'code',
'city',
'zipCode',
'country',
'address',
];
$optionalKeys = [
'description',
'department',
];
/** @var array{
* pickupPointId: int,
* networkCode: string,
* code: string,
* address: string,
* description: string,
* city: string,
* zipCode: string,
* department: string|null,
* country: string
* } $data
*/
$data = [];
foreach ($requiredKeys as $key) {
$cookieKey = self::COOKIES_PREFIX . $key;
$value = $context->cookie->__get($cookieKey);
// @phpstan-ignore-next-line
if ($value === false) {
throw new PsshippingException(sprintf("Require key from cookie '%s' is not present.", $cookieKey));
}
if ($key === 'pickupPointId') {
$data[$key] = (int) $value;
} else {
$data[$key] = (string) $value;
}
}
foreach ($optionalKeys as $key) {
$cookieKey = self::COOKIES_PREFIX . $key;
$value = $context->cookie->__get($cookieKey);
$data[$key] = $value;
}
return self::fromArray($data);
}
/**
* @param \Context $context
*
* @return void
*
* @throws PsshippingException
*/
public static function unsetFromCookies($context)
{
if ($context->cookie === null) {
throw new PsshippingException("The 'cookie' field is null in the context.");
}
$fields = [
'pickupPointId',
'networkCode',
'code',
'description',
'city',
'zipCode',
'department',
'country',
'address',
];
foreach ($fields as $field) {
$context->cookie->__unset(self::COOKIES_PREFIX . $field);
}
}
public static function fromShippingAddress(PsshippingAddress $address): self
{
$data = [
'pickupPointId' => $address->getPickupPointId(),
'networkCode' => $address->getNetworkCode(),
'code' => $address->getCode(),
'description' => $address->getDescription() ?? '',
'address' => $address->getAddress(),
'city' => $address->getCity(),
'zipCode' => $address->getZipCode(),
'department' => $address->getDepartment(),
'country' => $address->getCountry(),
];
return self::fromArray($data);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,245 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Http;
use RuntimeException;
class HttpClient
{
private $curl;
/** @var array<int|string,string> */
private $headers = [];
/** @var array<int|string,bool|int> */
private $options = [];
/** @var string */
private $baseUrl = '';
/**
* Constructor initializes cURL
*
* @param string $baseUrl Optional base URL for all requests
*
* @throws RuntimeException if cURL extension is not loaded
*/
public function __construct(string $baseUrl = '')
{
if (!extension_loaded('curl')) {
throw new RuntimeException('cURL extension is not loaded');
}
$this->baseUrl = rtrim($baseUrl, '/');
$this->curl = curl_init();
// Set default options
$this->setDefaultOptions();
}
/**
* Set default cURL options
*/
private function setDefaultOptions(): void
{
$this->options = [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
];
}
/**
* Set custom headers for the request
*
* @param array<int|string,string> $headers
*
* @return self
*/
public function setHeaders(array $headers): self
{
$this->headers = $headers;
return $this;
}
/**
* Add a single header
*
* @param string $name
* @param string $value
*
* @return self
*/
public function addHeader(string $name, string $value): self
{
$this->headers[] = "$name: $value";
return $this;
}
/**
* Set custom cURL options
*
* @param array<string,bool|int> $options
*
* @return self
*/
public function setOptions(array $options): self
{
$this->options = $options + $this->options;
return $this;
}
/**
* Execute HTTP request
*
* @param string $method HTTP method
* @param string $url URL endpoint
* @param array<string,string|bool|int>|string|null $data Request data
*
* @return Response
*
* @throws RuntimeException on cURL errors
*/
public function request(string $method, string $url, $data = null)
{
$url = $this->baseUrl . '/' . ltrim($url, '/');
$options = $this->options + [
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => strtoupper($method),
CURLOPT_HEADER => true,
CURLOPT_HTTPHEADER => $this->headers,
];
if ($data !== null) {
if (is_array($data)) {
$data = http_build_query($data);
}
if ($method === 'GET') {
/* @phpstan-ignore-next-line */
$options[CURLOPT_URL] .= '?' . $data;
} else {
$options[CURLOPT_POSTFIELDS] = $data;
}
}
curl_setopt_array($this->curl, $options);
$response = curl_exec($this->curl);
if ($response === false) {
throw new \RuntimeException(sprintf('cURL error (%s): %s', curl_errno($this->curl), curl_error($this->curl)));
}
$headerSize = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
$httpCode = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
// Split response into headers and body
$headerStr = substr((string) $response, 0, $headerSize);
$body = substr((string) $response, $headerSize);
$error = curl_error($this->curl);
// Parse headers
$headers = [];
foreach (explode("\r\n", $headerStr) as $line) {
if (preg_match('/^([^:]+):(.+)$/', $line, $matches)) {
$headers[trim($matches[1])] = trim($matches[2]);
}
}
return new Response(
$httpCode,
$body,
$headers,
$error
);
}
/**
* Convenience method for GET requests
*
* @param string $url
* @param array<string, string> $params Query parameters
*
* @return Response
*/
public function get(string $url, array $params = [])
{
return $this->request('GET', $url, $params);
}
/**
* Convenience method for POST requests
*
* @param string $url
* @param array<string, string>|string $data
*
* @return Response
*/
public function post(string $url, $data = [])
{
return $this->request('POST', $url, $data);
}
/**
* Convenience method for PUT requests
*
* @param string $url
* @param array<string, string>|string $data
*
* @return Response
*/
public function put(string $url, $data = [])
{
return $this->request('PUT', $url, $data);
}
/**
* Convenience method for DELETE requests
*
* @param string $url
* @param array<string, string> $params
*
* @return Response
*/
public function delete(string $url, array $params = [])
{
return $this->request('DELETE', $url, $params);
}
/**
* Destructor closes cURL connection
*/
public function __destruct()
{
if ($this->curl) {
curl_close($this->curl);
}
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Http;
class Response
{
/** @var int */
private $statusCode;
/** @var string */
private $body;
/** @var array<string,string> */
private $headers;
/** @var string|null */
private $error;
/**
* @param int $statusCode
* @param string $body
* @param array<string,string> $headers
* @param string|null $error
*
**/
public function __construct($statusCode, $body, $headers = [], $error = null)
{
$this->statusCode = $statusCode;
$this->body = $body;
$this->headers = $headers;
$this->error = $error;
}
/**
* @return int
*/
public function getStatusCode()
{
return $this->statusCode;
}
/**
* @return array<string,string>
*/
public function getHeaders()
{
return $this->headers;
}
/**
* @return string
*/
public function getBody()
{
return $this->body;
}
/**
* @return string|null
*/
public function getError()
{
return $this->error;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,98 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Legacy;
use PrestaShopBundle\Service\Routing\Router;
use Psshipping;
class PrestaShopAdapter
{
/**
* @var Psshipping
*/
private $module;
public function __construct(Psshipping $module)
{
$this->module = $module;
}
/**
* @param array<string, string> $sfParams
* @param array<string, string> $params
*/
public function generateRoute(string $routeName, array $sfParams = [], array $params = []): string
{
if (version_compare(_PS_VERSION_, '1.7.8.0', '>=')) {
/** @var Router $router */
$router = $this->module->get('router');
return $router->generate($routeName, $params);
}
$context = \Context::getContext();
if (!empty($context->link)) {
return $context->link->getAdminLink($routeName, true, $sfParams, $params);
}
return '';
}
public function generateOrderLink(int $orderId): string
{
if (version_compare(_PS_VERSION_, '1.7.7.0', '>=')) {
/** @var Router $router */
$router = $this->module->get('router');
return $router->generate('admin_orders_view', ['orderId' => $orderId]);
}
$context = \Context::getContext();
if (!empty($context->link)) {
return $context->link->getAdminLink('AdminOrders', true, [], ['vieworder' => '', 'id_order' => $orderId]);
}
return '';
}
public function generateEditCarrierLink(int $carrierId): string
{
if (version_compare(_PS_VERSION_, '1.7.7.0', '>=')) {
/** @var Router $router */
$router = $this->module->get('router');
return $router->generate('admin_carriers_edit', ['carrierId' => $carrierId]);
}
$context = \Context::getContext();
if (!empty($context->link)) {
return $context->link->getAdminLink('AdminCarrierWizard', true, [], ['id_carrier' => $carrierId]);
}
return '';
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,232 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Orders;
if (!defined('_PS_VERSION_')) {
exit();
}
class OrdersDto
{
/** @var int */
private $orderId;
/** @var string */
private $shippingDate;
/** @var string */
private $orderStatus;
/** @var string */
private $orderStatusBadgeColor;
/** @var string */
private $shippingId;
/** @var string */
private $shippingService;
/** @var int */
private $shippingCost;
/** @var string */
private $orderDetailLink;
/** @var string */
private $currency;
/**
* Get the value of orderDetailLink
*/
public function getOrderDetailLink(): string
{
return $this->orderDetailLink;
}
/**
* Set the value of orderDetailLink
*/
public function setOrderDetailLink(string $orderDetailLink): self
{
$this->orderDetailLink = $orderDetailLink;
return $this;
}
/**
* Get the value of orderId
*/
public function getOrderId(): int
{
return $this->orderId;
}
/**
* Set the value of orderId
*/
public function setOrderId(int $orderId): self
{
$this->orderId = $orderId;
return $this;
}
/**
* Get the value of shippingDate
*/
public function getShippingDate(): string
{
return $this->shippingDate;
}
/**
* Set the value of shippingDate
*/
public function setShippingDate(string $shippingDate): self
{
$this->shippingDate = $shippingDate;
return $this;
}
/**
* Get the value of orderStatus
*/
public function getOrderStatus(): string
{
return $this->orderStatus;
}
/**
* Set the value of orderStatus
*/
public function setOrderStatus(string $orderStatus): self
{
$this->orderStatus = $orderStatus;
return $this;
}
/**
* Get the value of shippingId
*/
public function getShippingId(): string
{
return $this->shippingId;
}
/**
* Set the value of shippingId
*/
public function setShippingId(string $shippingId): self
{
$this->shippingId = $shippingId;
return $this;
}
/**
* Get the value of shippingService
*/
public function getShippingService(): string
{
return $this->shippingService;
}
/**
* Set the value of shippingService
*/
public function setShippingService(string $shippingService): self
{
$this->shippingService = $shippingService;
return $this;
}
/**
* Get the value of shippingCost
*
* @return int
*/
public function getShippingCost()
{
return $this->shippingCost;
}
/**
* Set the value of shippingCost
*/
public function setShippingCost(int $shippingCost): self
{
$this->shippingCost = $shippingCost;
return $this;
}
/**
* Get the value of currency
*/
public function getCurrency(): string
{
return $this->currency;
}
/**
* Set the value of currency
*/
public function setCurrency(string $currency): self
{
$this->currency = $currency;
return $this;
}
/**
* @return array<string, int|string>
*/
public function toArray()
{
return [
'orderId' => $this->getOrderId(),
'orderLink' => $this->getOrderDetailLink(),
'orderStatus' => $this->getOrderStatus(),
'shippingCost' => $this->getShippingCost(),
'shippingDate' => $this->getShippingDate(),
'shippingId' => $this->getShippingId(),
'shippingService' => $this->getShippingService(),
'currency' => $this->getCurrency(),
'orderStatusBadgeColor' => $this->getOrderStatusBadgeColor(),
];
}
/**
* Get the value of orderStatusBadgeColor
*/
public function getOrderStatusBadgeColor(): string
{
return $this->orderStatusBadgeColor;
}
/**
* Set the value of orderStatusBadgeColor
*/
public function setOrderStatusBadgeColor(string $orderStatusBadgeColor): self
{
$this->orderStatusBadgeColor = $orderStatusBadgeColor;
return $this;
}
}

View File

@@ -0,0 +1,377 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Orders;
use Context;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Statement;
use PrestaShop\PrestaShop\Adapter\Configuration;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class OrdersRepository
{
/**
* @var Connection
*/
private $connection;
/**
* @var string
*/
private $dbPrefix;
/**
* @var Psshipping
*/
private $module;
/**
* @param Psshipping $module
*/
public function __construct(Psshipping $module)
{
$this->module = $module;
$this->dbPrefix = _DB_PREFIX_;
/** @var Connection $connection */
$connection = $this->module->getService('doctrine.dbal.default_connection');
$this->connection = $connection;
}
/**
* @param int $limit
* @param int $offset
* @param array<int,int> $carriersId
*
* @return array<int, array<string, string|int|bool>>
*/
public function getOrders($limit, $offset, $carriersId)
{
$context = Context::getContext();
$shopId = 0;
$langId = 0;
if (!empty($context) && !empty($context->language)) {
$langId = $context->language->id;
}
if (!empty($context->shop)) {
$shopId = (int) $context->shop->id;
}
if (count($carriersId) === 0) {
return [];
}
$qb = $this->connection->createQueryBuilder()
->select('o.id_order, o.date_add, osl.name, o.reference, o.total_shipping_tax_incl, o.id_currency, os.color, ca.external_module_name, o.id_carrier')
->from($this->dbPrefix . 'orders', 'o')
->innerJoin('o', $this->dbPrefix . 'order_state_lang', 'osl', 'o.current_state = osl.id_order_state AND osl.id_lang = :idLang')
->innerJoin('osl', $this->dbPrefix . 'order_state', 'os', 'osl.id_order_state = os.id_order_state')
->innerJoin('o', $this->dbPrefix . 'carrier', 'ca', 'o.id_carrier = ca.id_carrier')
->leftJoin('o', $this->dbPrefix . 'customer', 'c', 'c.id_customer = o.id_customer')
->where('o.id_carrier IN (:carriersId) AND o.id_shop = :idShop')
->setFirstResult($offset)
->setMaxResults($limit)
->orderBy('o.date_add', 'DESC')
->setParameter('carriersId', $carriersId, Connection::PARAM_INT_ARRAY)
->setParameter('idShop', $shopId)
->setParameter('idLang', $langId);
/** @var Statement $execute */
$execute = $qb->execute();
/** @var array<int, array<string, string|int|bool>> */
$result = $execute->fetchAll();
return $result;
}
/**
* @param array<int,int> $carriersId
*
* @return array<int, array<string, string|int|bool>>
*/
public function getNbOrders($carriersId)
{
$context = Context::getContext();
$langId = 0;
$shopId = 0;
if (!empty($context) && !empty($context->language)) {
$langId = $context->language->id;
}
if (!empty($context->shop)) {
$shopId = (int) $context->shop->id;
}
if (count($carriersId) === 0) {
return [];
}
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->dbPrefix . 'orders', 'o')
->innerJoin('o', $this->dbPrefix . 'order_state_lang', 'osl', 'o.current_state = osl.id_order_state AND osl.id_lang = :idLang')
->innerJoin('osl', $this->dbPrefix . 'order_state', 'os', 'osl.id_order_state = os.id_order_state')
->innerJoin('o', $this->dbPrefix . 'carrier', 'ca', 'o.id_carrier = ca.id_carrier')
->leftJoin('o', $this->dbPrefix . 'customer', 'c', 'c.id_customer = o.id_customer')
->where('o.id_carrier IN (:carriersId) AND o.id_shop = :idShop')
->orderBy('o.date_add', 'DESC')
->setParameter('carriersId', $carriersId, Connection::PARAM_INT_ARRAY)
->setParameter('idShop', $shopId)
->setParameter('idLang', $langId);
/** @var Statement $execute */
$execute = $qb->execute();
/** @var array<int, array<string, string|int|bool>> */
$result = $execute->fetchAll();
return $result;
}
/**
* @return bool
*/
public function saveTrackingNumber(int $orderId, string $trackingNumber): bool
{
$qb = $this->connection->createQueryBuilder();
$qb->update($this->dbPrefix . 'order_carrier', 'oc')
->set('oc.tracking_number', ':trackingNumber')
->where('oc.id_order = :orderId')
->setParameter('trackingNumber', $trackingNumber)
->setParameter('orderId', $orderId)
->execute();
return true;
}
/**
* getLastTrackingNumberByCarrierId
*
* @param array<int,int> $carriersId
*
* @return array<int, array<string, bool|int|string>>
*/
public function getLastTrackingNumberByCarrierId($carriersId)
{
$context = Context::getContext();
$shopId = 0;
if (!empty($context) && !empty($context->shop)) {
$shopId = (int) $context->shop->id;
}
$qb = $this->connection->createQueryBuilder()
->select('oc.tracking_number')
->from($this->dbPrefix . 'orders', 'o')
->innerJoin('o', $this->dbPrefix . 'order_carrier', 'oc', 'oc.id_order = o.id_order')
->where('oc.tracking_number != "" AND o.id_shop = :idShop')
->andWhere('oc.id_carrier IN (:carriersId)')
->orderBy('o.date_upd', 'DESC')
->setMaxResults(1)
->groupBy('oc.id_order')
->setParameter('carriersId', $carriersId, Connection::PARAM_INT_ARRAY)
->setParameter('idShop', $shopId);
/** @var Statement $execute */
$execute = $qb->execute();
/** @var array<int, array<string, bool|int|string>> */
$result = $execute->fetchAll();
return $result;
}
/**
* @return array<int, array<string, int|string>>
*/
public function getOrdersStatus()
{
$context = Context::getContext();
$lang = 0;
$result = [];
if (!empty($context) && !empty($context->language)) {
$lang = $context->language->id;
}
foreach (\OrderState::getOrderStates($lang) as $state) {
$result[] = [
'name' => $state['name'],
'id' => $state['id_order_state'],
];
}
return $result;
}
public function updateOrder(int $orderId, string $status): void
{
$configuration = new Configuration();
$context = Context::getContext();
$mapping = '';
if (is_string($configuration->get('PS_SHIPPING_ORDER_STATUS_MAPPING', '')) && !empty($configuration->get('PS_SHIPPING_ORDER_STATUS_MAPPING', ''))) {
$mapping = json_decode($configuration->get('PS_SHIPPING_ORDER_STATUS_MAPPING', ''));
}
if (!empty($context) && !empty($context->shop)) {
$configuration->restrictUpdatesTo($context->shop);
}
if (empty($context->language)) {
return;
}
$filterStatus = array_filter($mapping, function ($value) use ($status) {
return $value->mbeStatus === $status;
});
if (empty($filterStatus)) {
return;
}
$statusPs = array_values($filterStatus)[0];
if (empty($statusPs->statusMapped)) {
return;
}
$order = new \OrderCore($orderId);
$order->setCurrentState((int) $statusPs->statusMapped);
$order->save();
}
public function updateCarrierForOrders(int $oldCarrierId, int $newCarrierId): void
{
$qb = $this->connection->createQueryBuilder();
$qb->update($this->dbPrefix . 'orders', 'o')
->set('o.id_carrier', ':newCarrierId')
->where('o.id_carrier = :oldCarrierId')
->setParameter('newCarrierId', $newCarrierId)
->setParameter('oldCarrierId', $oldCarrierId)
->execute();
}
/**
* @param int $orderId
*
* @return array<string, mixed>
*/
public function getOrderDetails(int $orderId): array
{
$context = Context::getContext();
$langId = 0;
$shopId = 0;
if (!empty($context) && !empty($context->language)) {
$langId = $context->language->id;
}
if (!empty($context->shop)) {
$shopId = (int) $context->shop->id;
}
$qb = $this->connection->createQueryBuilder()
->select([
'ca.name as carrier_name',
'oc.tracking_number',
'osl.name as order_status',
'a.firstname as delivery_firstname',
'a.lastname as delivery_lastname',
'a.company as delivery_company',
'a.address1 as delivery_address1',
'a.address2 as delivery_address2',
'a.postcode as delivery_postcode',
'a.city as delivery_city',
's.iso_code as delivery_state_code',
'c.iso_code as delivery_country_code',
'cl.name as delivery_country',
'od.product_name',
'od.product_quantity',
'od.product_reference',
'od.product_attribute_id as product_id_product_attribute',
'od.product_id',
'od.unit_price_tax_incl',
'od.total_price_tax_incl',
])
->from($this->dbPrefix . 'orders', 'o')
->innerJoin('o', $this->dbPrefix . 'order_carrier', 'oc', 'oc.id_order = o.id_order')
->innerJoin('o', $this->dbPrefix . 'carrier', 'ca', 'o.id_carrier = ca.id_carrier')
->innerJoin('o', $this->dbPrefix . 'order_state_lang', 'osl', 'o.current_state = osl.id_order_state AND osl.id_lang = :langId')
->innerJoin('o', $this->dbPrefix . 'address', 'a', 'o.id_address_delivery = a.id_address')
->innerJoin('a', $this->dbPrefix . 'country', 'c', 'a.id_country = c.id_country')
->innerJoin('a', $this->dbPrefix . 'country_lang', 'cl', 'a.id_country = cl.id_country AND cl.id_lang = :langId')
->leftJoin('a', $this->dbPrefix . 'state', 's', 'a.id_state = s.id_state')
->innerJoin('o', $this->dbPrefix . 'order_detail', 'od', 'od.id_order = o.id_order')
->where('o.id_order = :orderId AND o.id_shop = :shopId')
->setParameter('orderId', $orderId)
->setParameter('shopId', $shopId)
->setParameter('langId', $langId);
/** @var Statement $execute */
$execute = $qb->execute();
/** @var array<int, array<string, mixed>> */
$result = $execute->fetchAll();
if (empty($result)) {
return [];
}
$orderInfo = $result[0];
$products = [];
foreach ($result as $row) {
$products[] = [
'name' => $row['product_name'],
'quantity' => $row['product_quantity'],
'reference' => $row['product_reference'],
'id_product_attribute' => $row['product_id_product_attribute'],
'id_product' => $row['product_id'],
];
}
return [
'carrier' => $orderInfo['carrier_name'],
'tracking_number' => $orderInfo['tracking_number'],
'status' => $orderInfo['order_status'],
'address' => [
'address_line_1' => $orderInfo['delivery_address1'],
'address_line_2' => $orderInfo['delivery_address2'],
'admin_area_2' => $orderInfo['delivery_city'],
'admin_area_1' => $orderInfo['delivery_state_code'],
'postal_code' => $orderInfo['delivery_postcode'],
'country_code' => $orderInfo['delivery_country_code'],
],
'products' => $products,
];
}
}

View File

@@ -0,0 +1,166 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Orders;
use Carrier;
use Currency;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository;
use PrestaShop\Module\Psshipping\Domain\Legacy\PrestaShopAdapter;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class OrdersService
{
/** @var Psshipping */
private $module;
public function __construct(Psshipping $module)
{
$this->module = $module;
}
/**
* @param array{
* standard: array{mbe: ?Carrier, ups: ?Carrier},
* express: array{mbe: ?Carrier, ups: ?Carrier},
* pickup: array{mbe: ?Carrier, ups: ?Carrier}
* } $carriersFromShop
* @param PrestaShopAdapter $prestashopAdapter
* @param int $limit
* @param int $offset
*
* @return array{orders: array<string, int|string>[], ordersCount: non-negative-int}
*/
public function getOrdersByCustomCarriers($carriersFromShop, $prestashopAdapter, $limit, $offset)
{
$carriersId = [];
$orderRepository = new OrdersRepository($this->module);
foreach ($carriersFromShop as $carrier) {
foreach ($carrier as $carrierDetail) {
if ($carrierDetail && !empty($carrierDetail['id_carrier'])) {
$carriersId[] = $carrierDetail['id_carrier'];
}
}
}
$result = $orderRepository->getOrders($limit, $offset, $carriersId);
$totalOrders = $orderRepository->getNbOrders($carriersId);
/** @var CarrierRepository $carrierRepository */
$carrierRepository = $this->module->getService(CarrierRepository::class);
$carrierMapping = $carrierRepository->getShippingCarriersMapping();
foreach ($result as $key => $value) {
$result[$key]['order_link'] = $prestashopAdapter->generateOrderLink((int) $value['id_order']);
$result[$key]['type'] = $carrierMapping[$value['id_carrier']]['type'];
}
return [
'orders' => array_map([$this, 'convert'], $result),
'ordersCount' => count($totalOrders),
];
}
/**
* @param array<string, string|int|bool> $value
*
* @return array<string, int|string>
*/
public function convert($value)
{
$orderDto = new OrdersDto();
if (!empty($value['id_order'])) {
$orderDto->setOrderId((int) $value['id_order']);
}
if (!empty($value['date_add'])) {
$orderDto->setShippingDate(strval($value['date_add']));
}
if (!empty($value['name'])) {
$orderDto->setOrderStatus(strval($value['name']));
}
if (!empty($value['reference'])) {
$orderDto->setShippingId(strval($value['reference']));
}
if (!empty($value['total_shipping_tax_incl'])) {
$orderDto->setShippingCost((int) round(intval($value['total_shipping_tax_incl']), 0));
}
if (!empty($value['order_link'])) {
$orderDto->setOrderDetailLink(strval($value['order_link']));
}
if (!empty($value['id_currency'])) {
$orderDto->setCurrency((new Currency(intval($value['id_currency'])))->iso_code);
}
if (!empty($value['color'])) {
$orderDto->setOrderStatusBadgeColor(strval($value['color']));
}
if (!empty($value['type'])) {
if ($value['type'] === 'standard') {
$orderDto->setShippingService('Standard');
}
if ($value['type'] === 'express') {
$orderDto->setShippingService('Express');
}
if ($value['type'] === 'pickup') {
$orderDto->setShippingService('Pickup');
}
}
return $orderDto->toArray();
}
/**
* @param int $idOrder
* @param string $trackingNumber
*
* @return bool
*/
public function saveTrackingNumber($idOrder, $trackingNumber)
{
return (new OrdersRepository($this->module))->saveTrackingNumber($idOrder, $trackingNumber);
}
/**
* @param array<int<0, max>, int> $carriersId
*
* @return bool|int|string
*/
public function getLastTrackingNumber($carriersId)
{
$trackingNumber = (new OrdersRepository($this->module))->getLastTrackingNumberByCarrierId($carriersId);
return count($trackingNumber) > 0 ? $trackingNumber[0]['tracking_number'] : '';
}
/**
* @return array<int, array<string, int|string>>
*/
public function getOrdersStatus()
{
return (new OrdersRepository($this->module))->getOrdersStatus();
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,172 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\Psshipping\Domain\Segment;
use Context;
use PrestaShop\Module\Psshipping\Domain\Accounts\AccountsIsNotInstalledException;
use PrestaShop\Module\Psshipping\Domain\Accounts\AccountsService;
use Psshipping;
class Segment
{
/**
* @var string
*/
private $message = '';
/**
* @var array<string, mixed>
*/
private $options = [];
/**
* @var Context|null
*/
private $context;
/**
* @var Psshipping
*/
private $module;
/**
* @var array<string, string|boolean|null>
*/
private $psAccountsContext;
/**
* Segment constructor.
*/
public function __construct(Psshipping $module, bool $onInstall = false)
{
$this->context = Context::getContext();
try {
$this->psAccountsContext = (new AccountsService())->getAccountsContext($module, $onInstall);
} catch (AccountsIsNotInstalledException $e) {
$this->psAccountsContext = [];
}
$this->module = $module;
$this->init();
}
/**
* Init segment client with the api key
*/
private function init(): void
{
\Segment::init($this->module->getSegmentKey());
}
/**
* Track event on segment
*
* @return bool
*
* @throws \PrestaShopException
*/
public function track()
{
if (empty($this->message)) {
throw new \PrestaShopException('Message cannot be empty. Need to set it with setMessage() method.');
}
$this->segmentTrack();
return true;
}
private function segmentTrack(): void
{
$userAgent = array_key_exists('HTTP_USER_AGENT', $_SERVER) === true ? $_SERVER['HTTP_USER_AGENT'] : '';
$ip = array_key_exists('REMOTE_ADDR', $_SERVER) === true ? $_SERVER['REMOTE_ADDR'] : '';
$referer = array_key_exists('HTTP_REFERER', $_SERVER) === true ? $_SERVER['HTTP_REFERER'] : '';
$url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
$isoCode = !empty($this->context->language) ? $this->context->language->iso_code : 'en';
$segmentTrack = [
'event' => $this->message,
'channel' => 'browser',
'context' => [
'ip' => $ip,
'userAgent' => $userAgent,
'locale' => $isoCode,
'page' => [
'referrer' => $referer,
'url' => $url,
],
],
'properties' => array_merge([
'module' => 'psshipping',
], $this->options),
];
if (!empty($this->psAccountsContext['user']) && !empty($this->psAccountsContext['user']['uuid'])) {
$segmentTrack['userId'] = $this->psAccountsContext['user']['uuid'];
} else {
if (!empty($this->context->shop)) {
$segmentTrack['anonymousId'] = hash('sha256', $this->context->shop->domain);
}
}
if (!empty($this->psAccountsContext['currentShop']) && !empty($this->psAccountsContext['currentShop']['uuid'])) {
$segmentTrack['properties']['shopId'] = $this->psAccountsContext['currentShop']['uuid'];
}
\Segment::track($segmentTrack);
\Segment::flush();
}
/**
* @return string
*/
public function getMessage()
{
return $this->message;
}
/**
* @param string $message
*/
public function setMessage($message): void
{
$this->message = $message;
}
/**
* @return array<string, mixed>
*/
public function getOptions()
{
return $this->options;
}
/**
* @param array<string, mixed> $options
*/
public function setOptions($options): void
{
$this->options = $options;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,400 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Shipment;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
/**
* RecipientDTO
*
* A Data Transfer Object (DTO) for MBE recipient information,
* including methods for array conversion.
* This is the format required by MBE API.
*/
class RecipientDTO
{
/**
* @var string the name of the recipient (could be a person's name or company name)
*/
private $name;
/**
* @var string the first line of the address
*/
private $address;
/**
* @var string|null the second line of the address, if available
*/
private $address2;
/**
* @var string the phone number of the recipient, if available
*/
private $phone;
/**
* @var string the postal code or zip code
*/
private $zipCode;
/**
* @var string the city
*/
private $city;
/**
* @var string|null the state or province, if applicable
*/
private $state;
/**
* @var string The country ISO code (e.g., 'US', 'FR').
*/
private $country;
/**
* @var string the email address of the recipient
*/
private $email;
/**
* Constructor for RecipientDTO.
*
* @param string $name the name of the recipient
* @param string $address the first line of the address
* @param string|null $address2 the second line of the address
* @param string $phone the phone number
* @param string $zipCode the postal/zip code
* @param string $city the city
* @param string|null $state the state/province
* @param string $country the country ISO code
* @param string $email the email address
*/
public function __construct(
string $name,
string $address,
?string $address2,
string $phone,
string $zipCode,
string $city,
?string $state,
string $country,
string $email
) {
$this->name = $name;
$this->address = $address;
$this->address2 = $address2;
$this->phone = $phone;
$this->zipCode = $zipCode;
$this->city = $city;
$this->state = $state;
$this->country = $country;
$this->email = $email;
}
// --- Getters ---
/**
* Get the recipient's name.
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Get the first address line.
*
* @return string
*/
public function getAddress(): string
{
return $this->address;
}
/**
* Get the second address line.
*
* @return string
*/
public function getAddress2(): string
{
return $this->address2 ?? '';
}
/**
* Get the phone number.
*
* @return string
*/
public function getPhone(): string
{
return $this->phone;
}
/**
* Get the zip/postal code.
*
* @return string
*/
public function getZipCode(): string
{
return $this->zipCode;
}
/**
* Get the city.
*
* @return string
*/
public function getCity(): string
{
return $this->city;
}
/**
* Get the state/province.
*
* @return string
*/
public function getState(): string
{
return $this->state ?? '';
}
/**
* Get the country ISO code.
*
* @return string
*/
public function getCountry(): string
{
return $this->country;
}
/**
* Get the email address.
*
* @return string
*/
public function getEmail(): string
{
return $this->email;
}
// --- Setters ---
/**
* Set the recipient's name.
*
* @param string $name
*
* @return self
*/
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* Set the first address line.
*
* @param string $address
*
* @return self
*/
public function setAddress(string $address): self
{
$this->address = $address;
return $this;
}
/**
* Set the second address line.
*
* @param string|null $address2
*
* @return self
*/
public function setAddress2(?string $address2): self
{
$this->address2 = $address2;
return $this;
}
/**
* Set the phone number.
*
* @param string $phone
*
* @return self
*/
public function setPhone(string $phone): self
{
$this->phone = $phone;
return $this;
}
/**
* Set the zip/postal code.
*
* @param string $zipCode
*
* @return self
*/
public function setZipCode(string $zipCode): self
{
$this->zipCode = $zipCode;
return $this;
}
/**
* Set the city.
*
* @param string $city
*
* @return self
*/
public function setCity(string $city): self
{
$this->city = $city;
return $this;
}
/**
* Set the state/province.
*
* @param string|null $state
*
* @return self
*/
public function setState(?string $state): self
{
$this->state = $state;
return $this;
}
/**
* Set the country ISO code.
*
* @param string $country
*
* @return self
*/
public function setCountry(string $country): self
{
$this->country = $country;
return $this;
}
/**
* Set the email address.
*
* @param string $email
*
* @return self
*/
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* Converts the DTO object to an associative array.
*
* @return array{
* name: string,
* address: string,
* address2: string,
* phone: string,
* zipCode: string,
* state: string,
* city: string,
* country: string,
* email: string,
* }
*/
public function toArray(): array
{
return [
'name' => $this->getName(),
'address' => $this->getAddress(),
'address2' => $this->getAddress2(),
'phone' => $this->getPhone(),
'zipCode' => $this->getZipCode(),
'city' => $this->getCity(),
'state' => $this->getState(),
'country' => $this->getCountry(),
'email' => $this->getEmail(),
];
}
/**
* Creates a RecipientDTO object from an associative array.
*
* @param array{
* name: string,
* address: string,
* address2: string|null,
* phone: string,
* zipCode: string,
* state: string|null,
* city: string,
* country: string,
* email: string,
* } $data
*
* @return self
*
* @throws PsshippingException if a required key is missing from the array
*/
public static function fromArray(array $data): self
{
return new self(
$data['name'],
$data['address'],
$data['address2'] ?? null,
$data['phone'],
$data['zipCode'],
$data['city'],
$data['state'] ?? null,
$data['country'],
$data['email']
);
}
}

View File

@@ -0,0 +1,188 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Domain\Shipment;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
/**
* RecipientPickupPointDTO
*
* A Data Transfer Object (DTO) for MBE recipient information,
* including methods for array conversion.
* This is the format required by MBE API.
*/
final class RecipientPickupPointDTO extends RecipientDTO
{
/**
* WARNING - on MBE API, gelPudoPointID does not mean pickupPointID return by
* gel proximity SDK but the "code" property instead.
*
* @var string pickup point id (gel proximity)
*/
private $gelPudoPointId;
/**
* @var string gel proximity network code
*/
private $gelNetworkCode;
/**
* Constructor for RecipientDTO.
*
* @param string $gelPudoPointId pickup point id (gel proximity)
* @param string $gelNetworkCode gel network code
*/
public function __construct(
string $gelPudoPointId,
string $gelNetworkCode,
string $name,
string $address,
?string $address2,
string $phone,
string $zipCode,
string $city,
?string $state,
string $country,
string $email
) {
parent::__construct($name, $address, $address2, $phone, $zipCode, $city, $state, $country, $email);
$this->gelPudoPointId = $gelPudoPointId;
$this->gelNetworkCode = $gelNetworkCode;
}
// --- Getters ---
/**
* Get the gel proximity pickup point id.
*
* @return string
*/
public function getGelPudoPointId(): string
{
return $this->gelPudoPointId;
}
/**
* Get the gel proximity network code.
*
* @return string
*/
public function getGelNetworkCode(): string
{
return $this->gelNetworkCode;
}
// --- Setters ---
/**
* Get the gel proximity pickup point id.
*
* @param string $gelPudoPointId
*
* @return self
*/
public function setGelPudoPointId(string $gelPudoPointId): self
{
$this->gelPudoPointId = $gelPudoPointId;
return $this;
}
/**
* Get the gel proximity network code.
*
* @param string $gelNetworkCode
*
* @return self
*/
public function setGelNetworkCode(string $gelNetworkCode): self
{
$this->gelNetworkCode = $gelNetworkCode;
return $this;
}
/**
* Converts the DTO object to an associative array.
*
* @return array{
* gelPudoPointId: string,
* gelNetworkCode: string,
* name: string,
* address: string,
* address2: string|null,
* phone: string,
* zipCode: string,
* state: string|null,
* city: string,
* country: string,
* email: string,
* }
*/
public function toArray(): array
{
return array_merge(parent::toArray(), [
'gelPudoPointId' => $this->gelPudoPointId,
'gelNetworkCode' => $this->gelNetworkCode,
]);
}
/**
* Creates a RecipientDTO object from an associative array.
*
* @param array{
* gelPudoPointId: string,
* gelNetworkCode: string,
* name: string,
* address: string,
* address2: string|null,
* phone: string,
* zipCode: string,
* state: string|null,
* city: string,
* country: string,
* email: string,
* } $data
*
* @return static
*
* @throws PsshippingException if a required key is missing from the array
*/
public static function fromPickupPointArray(array $data)
{
return new static(
$data['gelPudoPointId'],
$data['gelNetworkCode'],
$data['name'],
$data['address'],
$data['address2'] ?? null,
$data['phone'],
$data['zipCode'],
$data['city'],
$data['state'] ?? null,
$data['country'],
$data['email']
);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,237 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table()
* @ORM\Entity(repositoryClass="PrestaShop\Module\Psshipping\Domain\PickupPoints\PsshippingAddressRepository")
*/
class PsshippingAddress
{
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id_address", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* ID that the gel proximity SDK return. It's the ID of the pickup point
* on GEL PROXIMITY side.
*
* @var int
*
* @ORM\Column(name="pickup_point_id", type="integer", unique=true, nullable=false)
*/
private $pickupPointId;
/**
* @var string
*
* @ORM\Column(name="network_code", type="string", length=20, nullable=false)
*/
private $networkCode;
/**
* This var is the var to use on MBE side for the "gelPudoPointId"
* On MBE side gelPudoPointId = "code" coming from gel proximity SDK.
* This code looks like something like PUP_XXXXXX
*
* @var string
*
* @ORM\Column(name="code", type="string", length=255)
*/
private $code;
/**
* @var string|null
*
* @ORM\Column(name="description", type="string", length=255, nullable=true)
*/
private $description;
/**
* @var string
*
* @ORM\Column(name="address", type="string", length=255, nullable=false)
*/
private $address;
/**
* @var string
*
* @ORM\Column(name="city", type="string", length=255)
*/
private $city;
/**
* @var string
*
* @ORM\Column(name="zip_code", type="string", length=255)
*/
private $zipCode;
/**
* @var string|null
*
* @ORM\Column(name="department", type="string", length=255, nullable=true)
*/
private $department;
/**
* @var string
*
* @ORM\Column(name="country", type="string", length=255)
*/
private $country;
public function getPickupPointId(): int
{
return $this->pickupPointId;
}
public function setPickupPointId(int $pickupPointId): self
{
$this->pickupPointId = $pickupPointId;
return $this;
}
public function getNetworkCode(): string
{
return $this->networkCode;
}
public function setNetworkCode(string $networkCode): self
{
$this->networkCode = $networkCode;
return $this;
}
public function getCode(): string
{
return $this->code;
}
public function setCode(string $code): self
{
$this->code = $code;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
public function getAddress(): string
{
return $this->address;
}
public function setAddress(string $address): self
{
$this->address = $address;
return $this;
}
public function getCity(): string
{
return $this->city;
}
public function setCity(string $city): self
{
$this->city = $city;
return $this;
}
public function getZipCode(): string
{
return $this->zipCode;
}
public function setZipCode(string $zipCode): self
{
$this->zipCode = $zipCode;
return $this;
}
public function getDepartment(): ?string
{
return $this->department;
}
public function setDepartment(?string $department): self
{
$this->department = $department;
return $this;
}
public function getCountry(): string
{
return $this->country;
}
public function setCountry(string $country): self
{
$this->country = $country;
return $this;
}
/**
* @return array<string, mixed>
*/
public function toArray(): array
{
return [
'id' => $this->id,
'pickup_point_id' => $this->pickupPointId,
'code' => $this->code,
'address' => $this->address,
'city' => $this->city,
'zip_code' => $this->zipCode,
'department' => $this->department,
'country' => $this->country,
];
}
}

View File

@@ -0,0 +1,93 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table()
* @ORM\Entity(repositoryClass="PrestaShop\Module\Psshipping\Domain\PickupPoints\PsshippingAddressOrdersRepository")
*/
class PsshippingAddressOrders
{
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id_order", type="integer", nullable=false)
*/
private $idOrder;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id_shop", type="integer", nullable=false)
*/
private $idShop;
/**
* @var PsshippingAddress
*
* @ORM\Id
* @ORM\ManyToOne(targetEntity=PsshippingAddress::class)
* @ORM\JoinColumn(name="id_address", referencedColumnName="id_address", nullable=false)
*/
private $address;
public function getIdOrder(): int
{
return $this->idOrder;
}
public function setIdOrder(int $idOrder): self
{
$this->idOrder = $idOrder;
return $this;
}
public function getIdShop(): int
{
return $this->idShop;
}
public function setIdShop(int $idShop): self
{
$this->idShop = $idShop;
return $this;
}
public function getAddress(): PsshippingAddress
{
return $this->address;
}
public function setAddress(PsshippingAddress $address): self
{
$this->address = $address;
return $this;
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Exception;
if (!defined('_PS_VERSION_')) {
exit();
}
class BadRequestException extends PsshippingException
{
public function __construct(string $message, int $code = 0, bool $throwable = true)
{
parent::__construct($message, $code, $throwable);
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Exception;
use PrestaShop\Module\Psshipping\Handler\ErrorHandler;
use PrestaShopException;
if (!defined('_PS_VERSION_')) {
exit();
}
class PsshippingException extends PrestaShopException
{
public function __construct(string $message, int $code = 0, bool $throwable = true)
{
parent::__construct($message, $code);
(new ErrorHandler())->handle($this, $code, $throwable);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,102 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Handler;
use Module;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class ErrorHandler
{
/**
* @var ModuleFilteredRavenClient
*/
protected $client;
public function __construct()
{
/** @var Psshipping $module */
$module = Module::getInstanceByName('psshipping');
$this->client = new ModuleFilteredRavenClient(
$module->getSentryDsn(),
[
'level' => 'warning',
'tags' => [
'php_version' => phpversion(),
'psshipping_version' => $module->version,
'prestashop_version' => _PS_VERSION_,
'psshipping_is_enabled' => \Module::isEnabled('psshipping'),
'psshipping_is_installed' => \Module::isInstalled('psshipping'),
'env' => $module->getSentryEnv(),
],
'release' => "v{$module->version}",
]
);
// We use realpath to get errors even if module is behind a symbolic link
$this->client->setAppPath(realpath(_PS_MODULE_DIR_ . $module->name . '/'));
// - Do no not add the shop root folder, it will exclude everything even if specified in the app path.
// - Excluding vendor/ avoids errors comming from one of your libraries library when called by another module.
$this->client->setExcludedAppPaths([
realpath(_PS_MODULE_DIR_ . $module->name . '/vendor/'),
]);
// $this->client->setExcludedDomains(['127.0.0.1', 'localhost', '.local']);
if (version_compare(phpversion(), '7.4.0', '>=') && version_compare(_PS_VERSION_, '8.0', '<')) {
return;
}
$this->client->install();
}
/**
* @param \Exception $error
* @param int $code
* @param bool|null $throw
* @param array<string>|null $data
*
* @return void
*
* @throws \Exception
*/
public function handle($error, $code = null, $throw = true, $data = null)
{
$this->client->captureException($error, $data);
if ($code && true === $throw) {
http_response_code($code);
throw $error;
}
}
/**
* @return void
*/
private function __clone()
{
}
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Handler;
use Raven_Client;
if (!defined('_PS_VERSION_')) {
exit();
}
class ModuleFilteredRavenClient extends Raven_Client
{
/**
* @var string[]|null
*/
protected $excluded_domains;
/**
* @param array<string, object>|null $data
* @param string[]|null $stack
* @param mixed[]|null $vars
*
* @return self|null
*/
public function capture($data, $stack = null, $vars = null)
{
if (!isset($data['exception']['values'][0]['stacktrace']['frames'])) {
return null;
}
if ($this->isErrorFilteredByContext()) {
return null;
}
$allowCapture = false;
foreach ($data['exception']['values'] as $errorValues) {
$allowCapture = $allowCapture || $this->isErrorInApp($errorValues);
}
if (!$allowCapture) {
return null;
}
return parent::capture($data, $stack, $vars);
}
/**
* @param array<int, string> $domains
*
* @return self
*/
public function setExcludedDomains(array $domains)
{
$this->excluded_domains = $domains;
return $this;
}
/**
* @param array<string, iterable<string>> $data
*
* @return bool
*/
private function isErrorInApp(array $data)
{
$atLeastOneFileIsInApp = false;
$stacktrace = $data['stacktrace'];
if (!isset($stacktrace['frames'])) {
return false;
}
foreach ($stacktrace['frames'] as $frame) {
$atLeastOneFileIsInApp = $atLeastOneFileIsInApp || ((isset($frame['in_app']) && $frame['in_app']));
}
return $atLeastOneFileIsInApp;
}
/**
* Check the conditions in which the error is thrown, so we can apply filters
*
* @return bool
*/
private function isErrorFilteredByContext()
{
if ($this->excluded_domains && !empty($_SERVER['REMOTE_ADDR'])) {
foreach ($this->excluded_domains as $domain) {
if (is_string($_SERVER['REMOTE_ADDR']) && strpos($_SERVER['REMOTE_ADDR'], $domain) !== false) {
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,60 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Helper;
if (!defined('_PS_VERSION_')) {
exit();
}
class ConfigHelper
{
/** @var string shipping APIs URL */
public $api_url;
/** @var string vue app dev mode activation */
public $mbe_tracking_url;
/** @var string segment_key */
public $segment_key;
/** @var string sentry_dsn */
public $sentry_dsn;
/** @var string sentry_env */
public $sentry_env;
public function __construct(
string $api_url,
string $mbe_tracking_url,
string $segment_key,
string $sentry_dsn,
string $sentry_env
) {
$this->api_url = $api_url;
$this->mbe_tracking_url = $mbe_tracking_url;
$this->segment_key = $segment_key;
$this->sentry_dsn = $sentry_dsn;
$this->sentry_env = $sentry_env;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,159 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Hooks;
use Carrier;
use Context;
use PrestaShop\Module\Psshipping\Domain\Accounts\AccountsService;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository;
use PrestaShop\Module\Psshipping\Domain\Orders\OrdersRepository;
use PrestaShop\Module\Psshipping\Domain\Segment\Segment;
use Psshipping;
use Tools;
if (!defined('_PS_VERSION_')) {
exit();
}
class HookActionObjectCarrierUpdateAfter
{
/** @var Psshipping */
private $psshipping;
/** @var CarrierRepository */
private $carrierRepository;
/** @var OrdersRepository */
private $orderRepository;
/** @var ?int */
private $oldCarrierIdCache = null;
public function __construct(
Psshipping $psshipping,
CarrierRepository $carrierRepository,
OrdersRepository $orderRepository
) {
$this->psshipping = $psshipping;
$this->carrierRepository = $carrierRepository;
$this->orderRepository = $orderRepository;
}
/**
* @param array<string, string> $params
*/
public function run(array $params): void
{
/** @var Carrier $carrier */
$carrier = $params['object'];
if ($carrier->external_module_name !== Psshipping::MODULE_TECHNICAL_NAME) {
return;
}
$this->updateShippingCarrierMapping($carrier);
$this->listenerUpdateFromStatusButton();
$this->listenerUpdateFromEditButton($carrier);
}
/**
* This function is used for listening changes if the user enabled or disabled the status carrier
* from on the grid carrier page.
*/
private function listenerUpdateFromStatusButton(): void
{
if (!empty(Context::getContext()->controller->controller_name) && Context::getContext()->controller->controller_name !== 'AdminCarriers') {
return;
}
$carrierId = is_numeric(Tools::getValue('id_carrier')) ? (int) Tools::getValue('id_carrier') : null;
if (Tools::getValue('statuscarrier') === '' && $carrierId) {
$this->trackCarrierActiveChanges($carrierId);
return;
}
}
/**
* This function is used for listening changes if the user enabled or disabled the status carrier
* from the carrier page itself.
*/
private function listenerUpdateFromEditButton(Carrier $carrier): void
{
if (!empty(Context::getContext()->controller->controller_name) && Context::getContext()->controller->controller_name !== 'AdminCarrierWizard') {
return;
}
$oldCarrierId = is_numeric(Tools::getValue('id_carrier')) ? (int) Tools::getValue('id_carrier') : null;
// When an edit is made on a carrier, the old one is set to 'deleted' in the database.
// The new one, we only want to track the new one witch is a duplicated from the other one.
if ($oldCarrierId === $carrier->id) {
return;
}
$oldCarrier = new Carrier($oldCarrierId);
if ($oldCarrier->active !== $carrier->active && $carrier->id) {
$this->trackCarrierActiveChanges($carrier->id);
}
}
private function trackCarrierActiveChanges(int $carrierId): void
{
$carrier = new Carrier($carrierId);
$eventAction = $carrier->active ? 'Enabled' : 'Disabled';
$account = (new AccountsService())->getAccountsContext($this->psshipping);
$segment = new Segment($this->psshipping);
$segment->setMessage('[SHI] Carrier ' . $eventAction);
$segment->setOptions([
'date' => date('Ymd'),
'enabled' => (bool) $carrier->active,
'email' => !empty($account['user']['email']) ? $account['user']['email'] : null,
'carrier_name' => $carrier->name,
'mbe_shipping_service' => explode('_', $carrier->external_module_name)[1],
]);
$segment->track();
}
private function updateShippingCarrierMapping(Carrier $carrier): void
{
$oldCarrierId = is_numeric(Tools::getValue('id_carrier')) ? (int) Tools::getValue('id_carrier') : null;
if ($oldCarrierId === $carrier->id && filter_var($carrier->deleted, FILTER_VALIDATE_BOOLEAN) === true) {
$this->oldCarrierIdCache = $oldCarrierId;
return;
}
if ($this->oldCarrierIdCache && !empty($carrier->id)) {
$mapping = $this->carrierRepository->getShippingCarriersMapping();
$carrierDetail = $mapping[$this->oldCarrierIdCache];
unset($mapping[$this->oldCarrierIdCache]);
$mapping[$carrier->id] = ['type' => $carrierDetail['type'], 'provider' => $carrierDetail['provider']];
$this->carrierRepository->updateShippingCarrierMapping($mapping);
$this->orderRepository->updateCarrierForOrders($this->oldCarrierIdCache, (int) $carrier->id);
$this->oldCarrierIdCache = null;
}
}
}

View File

@@ -0,0 +1,132 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Hooks;
use Cart;
use Context;
use Order;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository;
use PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressOrdersRepository;
use PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressRepository;
use PrestaShop\Module\Psshipping\Domain\GelProximity\Models\PickupPoint;
use PrestaShop\Module\Psshipping\Entity\PsshippingAddress;
use PrestaShop\Module\Psshipping\Entity\PsshippingAddressOrders;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
if (!defined('_PS_VERSION_')) {
exit();
}
class HookActionValidateOrder
{
/** @var CarrierRepository */
private $carrierRepository;
/** @var PsshippingAddressRepository */
private $psshippingAddressRepository;
/** @var PsshippingAddressOrdersRepository */
private $psshippingAddressOrdersRepository;
/** @var Context */
private $context;
public function __construct(
CarrierRepository $carrierRepository,
PsshippingAddressRepository $psshippingAddressRepository,
PsshippingAddressOrdersRepository $psshippingAddressOrdersRepository,
Context $context
) {
$this->carrierRepository = $carrierRepository;
$this->psshippingAddressRepository = $psshippingAddressRepository;
$this->psshippingAddressOrdersRepository = $psshippingAddressOrdersRepository;
$this->context = $context;
}
/**
* @param array{
* cart: Cart,
* order: Order,
* } $params
*/
public function run(array $params): void
{
if ($params['order']->id_carrier === null) {
throw new PsshippingException("The 'order->id_carrier' field is null.");
}
$currentCarrierId = (int) $params['order']->id_carrier;
if (!$this->carrierRepository->isPickupCarrierFromMapping($currentCarrierId)) {
return;
}
if ($params['order']->id === null) {
throw new PsshippingException("The 'order->id' field is null.");
}
if ($this->context->shop === null) {
throw new PsshippingException("The 'shop' field is not null in the context.");
}
if ($this->context->shop->id === null) {
throw new PsshippingException("The 'shop->id' field is not null in the context.");
}
$id_order = (int) $params['order']->id;
$shopId = $this->context->shop->id;
$shippingAddress = $this->getOrCreatePsshippingAddress();
$shippingAddressOrder = new PsshippingAddressOrders();
$shippingAddressOrder->setIdOrder($id_order);
$shippingAddressOrder->setIdShop($shopId);
$shippingAddressOrder->setAddress($shippingAddress);
$this->psshippingAddressOrdersRepository->add($shippingAddressOrder);
}
private function getOrCreatePsshippingAddress(): PsshippingAddress
{
$pickupPoint = PickupPoint::fromCookies($this->context);
$shippingAddress = $this->psshippingAddressRepository->findOneByPickupPointId($pickupPoint->getPickupPointId());
if ($shippingAddress === null) {
$shippingAddress = new PsshippingAddress();
$shippingAddress->setPickupPointId($pickupPoint->getPickupPointId());
$shippingAddress->setPickupPointId($pickupPoint->getPickupPointId());
$shippingAddress->setNetworkCode($pickupPoint->getNetworkCode());
$shippingAddress->setCode($pickupPoint->getCode());
$shippingAddress->setAddress($pickupPoint->getAddress());
$shippingAddress->setDescription($pickupPoint->getDescription());
$shippingAddress->setCity($pickupPoint->getCity());
$shippingAddress->setZipCode($pickupPoint->getZipCode());
$shippingAddress->setDepartment($pickupPoint->getDepartment());
$shippingAddress->setCountry($pickupPoint->getCountry());
$shippingAddress = $this->psshippingAddressRepository->add($shippingAddress);
}
return $shippingAddress;
}
}

View File

@@ -0,0 +1,97 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Hooks;
use Carrier;
use Context;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository;
use PrestaShop\Module\Psshipping\Domain\GelProximity\Models\PickupPoint;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class HookDisplayCarrierExtraContent
{
/** @var Psshipping */
private $psshipping;
/** @var CarrierRepository */
private $carrierRepository;
/** @var Context */
private $context;
public function __construct(
Psshipping $psshipping,
CarrierRepository $carrierRepository,
Context $context
) {
$this->psshipping = $psshipping;
$this->carrierRepository = $carrierRepository;
$this->context = $context;
}
/**
* @param array{
* carrier: array{
* id: int,
* }
* } $params
*/
public function run(array $params): string
{
if ($this->context->smarty === null) {
throw new PsshippingException("The 'smarty' field is null in the context.");
}
$currentCarrierId = $params['carrier']['id'];
if (!$this->carrierRepository->isPickupCarrierFromMapping($currentCarrierId)) {
return '';
}
$pickupPointDetail = null;
try {
$pickupPoint = PickupPoint::fromCookies($this->context);
$template = $this->context->smarty->createTemplate(_PS_MODULE_DIR_ . 'psshipping/views/templates/hook/pickUpPointDetails.tpl');
$template->assign([
'detailsTitle' => $this->psshipping->getTranslator()->trans('Pick-up point selected:', [], 'Modules.Psshipping.Admin'),
'btnText' => $this->psshipping->getTranslator()->trans('Change pick-up point', [], 'Modules.Psshipping.Admin'),
'pickupPoint' => $pickupPoint->toArray(),
]);
$pickupPointDetail = $template->fetch();
} catch (PsshippingException $th) {
}
$template = $this->context->smarty->createTemplate(_PS_MODULE_DIR_ . 'psshipping/views/templates/hook/gelProximityCarrierExtraContent.tpl');
$template->assign([
'pickupSelectionError' => $this->psshipping->getTranslator()->trans('An error occurred while selecting the pickup location, please try again.', [], 'Modules.Psshipping.Admin'),
'pickupPointDetail' => $pickupPointDetail,
]);
return $template->fetch();
}
}

View File

@@ -0,0 +1,137 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Hooks;
use Context;
use Media;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierService;
use PrestaShop\Module\Psshipping\Domain\GelProximity\GelProximityService;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
use Psshipping;
use Tools;
if (!defined('_PS_VERSION_')) {
exit();
}
class HookDisplayHeader
{
private const ALLOWED_CONTROLLERS = ['order'];
/** @var Psshipping */
private $psshipping;
/** @var CarrierRepository */
private $carrierRepository;
/** @var GelProximityService */
private $gelProximityService;
/** @var Context */
private $context;
/** @var string */
private $gelEndUserUrl;
public function __construct(
Psshipping $psshipping,
GelProximityService $gelProximityService,
CarrierRepository $carrierRepository,
Context $context,
string $gelEndUserUrl
) {
$this->psshipping = $psshipping;
$this->gelProximityService = $gelProximityService;
$this->carrierRepository = $carrierRepository;
$this->gelEndUserUrl = $gelEndUserUrl;
$this->context = $context;
}
public function run(): void
{
if ($this->context->controller === null) {
throw new PsshippingException("The 'controller' field is not null in the context.");
}
if (empty($this->context->controller->php_self) || (isset($this->context->controller->ajax) && $this->context->controller->ajax === true)) {
return;
}
$controller = Tools::getValue('controller', $this->context->controller->php_self);
if (in_array($controller, self::ALLOWED_CONTROLLERS, true)) {
if ($this->context->cart === null) {
throw new PsshippingException("The 'cart' field is null in the context.");
}
if ($this->context->link === null) {
throw new PsshippingException("The 'link' field is null in the context.");
}
if ($this->context->language === null) {
throw new PsshippingException("The 'language' field is null in the context.");
}
if ($this->context->cart->id === null) {
throw new PsshippingException("The 'cart->id' field is null in the context.");
}
$carrierId = null;
$carrierMapping = $this->carrierRepository->getShippingCarriersMapping();
foreach ($carrierMapping as $id => $carrier) {
if ($carrier['type'] === CarrierService::CARRIERS_PICKUP) {
$carrierId = $id;
break;
}
}
// only call gel proximity if the module is configured and the pickup up carrier is set up
if ($carrierId !== null) {
try {
$gelConfig = $this->gelProximityService->getGelCredentials();
} catch (\Throwable $th) {
Media::addJsDef([
'pickupCarrierError' => $this->psshipping->getTranslator()->trans('Unable to use this carrier at the moment.', [], 'Modules.Psshipping.Admin'),
]);
}
}
if (!isset($gelConfig)) {
return;
}
$moduleLink = $this->context->link->getModuleLink(Psshipping::MODULE_TECHNICAL_NAME, 'GelProximityNotificationHandler');
Media::addJsDef([
'gelProximityConfig' => [
'ajaxUrl' => $moduleLink,
'merchantCode' => $gelConfig->getMerchantCode(),
'apiKey' => $gelConfig->getApiKey(),
'urlEndUser' => $this->gelEndUserUrl,
'reference' => GelProximityService::buildSessionReference($this->context->cart->id),
'carrierId' => $carrierId,
'selectPickupCarrierBtnText' => $this->psshipping->getTranslator()->trans('Select pick-up point', [], 'Modules.Psshipping.Admin'),
'locale' => str_replace('-', '_', $this->context->language->locale),
],
]);
}
}
}

View File

@@ -0,0 +1,103 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Psshipping\Hooks;
use Context;
use Order;
use PrestaShop\Module\Psshipping\Domain\Carriers\CarrierRepository;
use PrestaShop\Module\Psshipping\Domain\Carriers\PickupPoints\PsshippingAddressOrdersRepository;
use PrestaShop\Module\Psshipping\Domain\GelProximity\Models\PickupPoint;
use PrestaShop\Module\Psshipping\Exception\PsshippingException;
use Psshipping;
if (!defined('_PS_VERSION_')) {
exit();
}
class HookDisplayOrderConfirmation
{
/** @var Psshipping */
private $psshipping;
/** @var CarrierRepository */
private $carrierRepository;
/** @var PsshippingAddressOrdersRepository */
private $psshippingAddressOrdersRepository;
/** @var Context */
private $context;
public function __construct(
Psshipping $psshipping,
CarrierRepository $carrierRepository,
PsshippingAddressOrdersRepository $psshippingAddressOrdersRepository,
Context $context
) {
$this->psshipping = $psshipping;
$this->carrierRepository = $carrierRepository;
$this->psshippingAddressOrdersRepository = $psshippingAddressOrdersRepository;
$this->context = $context;
}
/**
* @param array{
* order: Order,
* } $params
*/
public function run(array $params): string
{
$currentCarrierId = (int) $params['order']->id_carrier;
if (!$this->carrierRepository->isPickupCarrierFromMapping($currentCarrierId)) {
return '';
}
try {
$pickupPoint = PickupPoint::fromCookies($this->context);
PickupPoint::unsetFromCookies($this->context);
} catch (PsshippingException $e) {
$orderId = (int) $params['order']->id;
$shopId = (int) $params['order']->id_shop;
$shippingAddress = $this->psshippingAddressOrdersRepository->findOneByIdOrderAndShop($orderId, $shopId);
if ($shippingAddress === null) {
return '';
}
$pickupPoint = PickupPoint::fromShippingAddress($shippingAddress->getAddress());
}
if ($this->context->smarty === null) {
throw new PsshippingException("The 'smarty' field is null in the context.");
}
$template = $this->context->smarty->createTemplate(_PS_MODULE_DIR_ . 'psshipping/views/templates/hook/pickUpPointDetailsOrderConfirmation.tpl');
$template->assign([
'detailsTitle' => $this->psshipping->getTranslator()->trans('Your order will be ready at the selected pick-up point:', [], 'Modules.Psshipping.Admin'),
'pickupPoint' => $pickupPoint->toArray(),
]);
return $template->fetch();
}
}

Some files were not shown because too many files have changed in this diff Show More