diff --git a/.distignore b/.distignore new file mode 100644 index 0000000000000000000000000000000000000000..e06a04781c032573c660a3a26a7c9f47fd8bff93 --- /dev/null +++ b/.distignore @@ -0,0 +1,12 @@ +*.pdf +node_modules +.git +package.json +.husky +package-lock.json +.distignore +make-zip.sh +update-version.js +.gitlab-ci.yml +.gitignore +package diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6450684a14697f89950e7eadd9aaa21fbd8369ff --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules +*.zip +.idea +/.idea/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index de5cdd5e509b31e9302f902adec4fb53deba29ed..bc49012c4a4845e2dab9257ac8c1ce1be67dd98b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,24 +4,20 @@ variables: GIT_SUBMODULE_STRATEGY: recursive stages: - - tagged_release + - deploy -tagged_deploy: - stage: tagged_release - only: - - tags +deploy: + stage: deploy before_script: - # - AWS_ACCESS_KEY_ID_KEY=$(echo "$AWS_ACCESS_KEY_ID") - # - AWS_SECRET_ACCESS_KEY_KEY=$(echo "$AWS_SECRET_ACCESS_KEY") - # - AWS_ACCESS_KEY_ID=$(eval echo -e "\$$AWS_ACCESS_KEY_ID_KEY") - # - AWS_SECRET_ACCESS_KEY=$(eval echo -e "\$$AWS_SECRET_ACCESS_KEY_KEY") - # - export AWS_ACCESS_KEY_ID - # - export AWS_SECRET_ACCESS_KEY + - AWS_ACCESS_KEY_ID_KEY=$(echo "$CI_COMMIT_BRANCH"_"AWS_ACCESS_KEY_ID") + - AWS_ACCESS_KEY_ID=$(eval echo -e "\$$AWS_ACCESS_KEY_ID_KEY") + - AWS_SECRET_ACCESS_KEY_KEY=$(echo "$CI_COMMIT_BRANCH"_"AWS_SECRET_ACCESS_KEY") + - AWS_SECRET_ACCESS_KEY=$(eval echo -e "\$$AWS_SECRET_ACCESS_KEY_KEY") + - export AWS_ACCESS_KEY_ID + - export AWS_SECRET_ACCESS_KEY script: - # - echo $AWS_ACCESS_KEY_ID - # - echo $AWS_SECRET_ACCESS_KEY - - wget https://gitlab.bob.co.za/bob-public-utils/bobgo-magento-extension/-/archive/"$CI_COMMIT_TAG"/bobgo-magento-extension-"$CI_COMMIT_TAG".tar.gz - - ls -al - - aws s3 cp bobgo-magento-extension-"$CI_COMMIT_TAG".tar.gz s3://bobgo-s3-magento-plugin/ --region=af-south-1 - allow_failure: false - when: on_success \ No newline at end of file + - ./make-zip.sh + - aws s3 cp bobgo-magento-plugin.zip s3://bobgo-s3-magento-plugin/ --region=af-south-1 + rules: + - if: '$CI_COMMIT_BRANCH == "dev" && $CI_COMMIT_TAG == null' + when: always diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000000000000000000000000000000000000..0e8cbb02c99d4ef73e87ef96554f3c0f4e3db95f --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npm config set git-tag-version false && npm version patch && npm run update-version-files && git add package.json etc/module.xml composer.json diff --git a/Block/TrackOrderLink.php b/Block/TrackOrderLink.php new file mode 100644 index 0000000000000000000000000000000000000000..ada8c220e6cfa6c217f6caf5ce949885487b5470 --- /dev/null +++ b/Block/TrackOrderLink.php @@ -0,0 +1,41 @@ +<?php + +namespace BobGroup\BobGo\Block; + +use Magento\Framework\View\Element\Html\Link\Current; +use Magento\Framework\App\Config\ScopeConfigInterface; + +class TrackOrderLink extends Current +{ + protected $scopeConfig; + + public function __construct( + \Magento\Framework\View\Element\Template\Context $context, + ScopeConfigInterface $scopeConfig, + \Magento\Framework\App\DefaultPathInterface $defaultPath, + array $data = [] + ) { + $this->scopeConfig = $scopeConfig; + parent::__construct($context, $defaultPath, $data); + } + + protected function _toHtml() + { + // Check if the Track My Order feature is enabled + $isEnabled = $this->scopeConfig->isSetFlag( + 'carriers/bobgo/enable_track_order', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + + // Return an empty string if the feature is disabled + if (!$isEnabled) { + return ''; + } + + // Use the parent class's rendering method + return parent::_toHtml(); + } +} + + + diff --git a/Block/TrackingBlock.php b/Block/TrackingBlock.php new file mode 100644 index 0000000000000000000000000000000000000000..647cb3dbec3f6b0e662c5b75389566ab5e77894e --- /dev/null +++ b/Block/TrackingBlock.php @@ -0,0 +1,26 @@ +<?php + +namespace BobGroup\BobGo\Block; + +use Magento\Framework\View\Element\Template; +use Magento\Framework\Registry; + +class TrackingBlock extends \Magento\Framework\View\Element\Template +{ + protected $registry; + + public function __construct( + Template\Context $context, + Registry $registry, + array $data = [] + ) { + $this->registry = $registry; + parent::__construct($context, $data); + } + + public function getResponse() + { + return $this->registry->registry('shipment_data'); + } +} + diff --git a/Controller/Tracking/Index.php b/Controller/Tracking/Index.php new file mode 100644 index 0000000000000000000000000000000000000000..78e527f3cf741512ba42d898c378fe839204254a --- /dev/null +++ b/Controller/Tracking/Index.php @@ -0,0 +1,108 @@ +<?php +namespace BobGroup\BobGo\Controller\Tracking; + +use Magento\Framework\App\Action\Context; +use Magento\Framework\View\Result\PageFactory; +use Magento\Framework\Registry; +use Psr\Log\LoggerInterface; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Controller\Result\RedirectFactory; +use Magento\Framework\Controller\Result\JsonFactory; +use Magento\Framework\HTTP\Client\Curl; +use Magento\Store\Model\StoreManagerInterface; +use BobGroup\BobGo\Model\Carrier\UData; + +class Index extends \Magento\Framework\App\Action\Action +{ + protected $resultPageFactory; + protected $jsonFactory; + protected $curl; + protected $logger; + protected $scopeConfig; + protected $redirectFactory; + protected $registry; + protected StoreManagerInterface $storeManager; + + public function __construct( + Context $context, + PageFactory $resultPageFactory, + JsonFactory $jsonFactory, + LoggerInterface $logger, + ScopeConfigInterface $scopeConfig, + RedirectFactory $redirectFactory, + StoreManagerInterface $storeManager, + Curl $curl, + Registry $registry + ) { + $this->resultPageFactory = $resultPageFactory; + $this->jsonFactory = $jsonFactory; + $this->logger = $logger; + $this->scopeConfig = $scopeConfig; + $this->redirectFactory = $redirectFactory; + $this->storeManager = $storeManager; + $this->curl = $curl; + $this->registry = $registry; + parent::__construct($context); + } + + public function execute() + { + // This is only an extra check after the TrackOrderLink block + // Check if the "Track My Order" feature is enabled + $isEnabled = $this->scopeConfig->isSetFlag( + 'carriers/bobgo/enable_track_order', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + + if (!$isEnabled) { + // If the feature is disabled, redirect to home page or show a 404 error + return $this->redirectFactory->create()->setPath('noroute'); + } + + $trackingReference = $this->getRequest()->getParam('order_reference'); + + $channel = $this->getStoreUrl(); + + if ($trackingReference) { + $trackingUrl = sprintf(UData::TRACKING, $channel, $trackingReference); + $this->curl->get($trackingUrl); + $response = $this->curl->getBody(); + + $decodedResponse = json_decode($response, true); + + if (is_array($decodedResponse) && isset($decodedResponse[0])) { + $shipmentData = $decodedResponse[0]; + + // Save data to the registry + $this->registry->register('shipment_data', $shipmentData); + + } else { + // Return early the response is not valid + return $this->resultPageFactory->create(); + } + } + + return $this->resultPageFactory->create(); + } + + private function getStoreUrl(): string + { + $url = $this->storeManager->getStore()->getBaseUrl(); + + // Remove protocol (http:// or https://) + $host = preg_replace('#^https?://#', '', $url); + + // Ensure $host is a string before using it in explode + $host = $host ?? ''; + + // Remove everything after the host (e.g., paths, query strings) + $host = explode('/', $host)[0]; + + // If the host starts with 'www.', remove it + if (strpos($host, 'www.') === 0) { + $host = substr($host, 4); + } + + return $host; + } +} diff --git a/Installation guide - Bob Go shipping extension for Magento 2.pdf b/Installation guide - Bob Go shipping extension for Magento 2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2b410bed7e7f035526b31166ae6838292cd7d39b Binary files /dev/null and b/Installation guide - Bob Go shipping extension for Magento 2.pdf differ diff --git a/Model/Carrier/BobGo.php b/Model/Carrier/BobGo.php index 386e4cbc07cd86549a73eaed2cfa25fa22a35185..12e46e69ab6fe302edc536fd7bf791d7ecf49fea 100644 --- a/Model/Carrier/BobGo.php +++ b/Model/Carrier/BobGo.php @@ -527,141 +527,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car } } - /** - * Get tracking - * - * @param string|string[] $trackings - * @return \Magento\Shipping\Model\Tracking\Result|null - */ - public function getTracking($trackings) - { - $this->setTrackingRequest(); // Ensure this method is correctly defined - - if (!is_array($trackings)) { - $trackings = [$trackings]; - } - - foreach ($trackings as $tracking) { - $this->_getXMLTracking([$tracking]); // Ensure _getXMLTracking processes tracking correctly - } - - return $this->_result; // Ensure _result is a \Magento\Shipping\Model\Tracking\Result - } - - /** - * Set tracking request - * - * @return void - */ - protected function setTrackingRequest() - { - $r = new \Magento\Framework\DataObject(); - - $account = $this->getConfigData('account'); - $r->setData('account', $account); // Using setData with the key 'account' - - $this->_rawTrackingRequest = $r; - } - - /** - * Get tracking request - * - * @return \Magento\Framework\DataObject|null - */ - protected function getTrackingRequest(): ?\Magento\Framework\DataObject - { - return $this->_rawTrackingRequest; - } - - /** - * Send request for tracking - * - * @param string[] $tracking - * @return void - */ - protected function _getXMLTracking($tracking) - { - $this->_parseTrackingResponse($tracking); - } - - /** - * Parse tracking response - * - * @param string|array<int,string> $trackingValue - * @return void - */ - protected function _parseTrackingResponse($trackingValue) - { - $result = $this->getResult(); - $carrierTitle = $this->getConfigData('title'); - $counter = 0; - - if (!is_array($trackingValue)) { - $trackingValue = [$trackingValue]; - } - - foreach ($trackingValue as $trackingReference) { - $tracking = $this->_trackStatusFactory->create(); - - $tracking->setCarrier(self::CODE); - $tracking->setCarrierTitle($carrierTitle); - - // Adjust as needed based on the environment - $tracking->setUrl(UData::TRACKING . $trackingReference); - $tracking->setTracking($trackingReference); - $tracking->addData($this->processTrackingDetails($trackingReference)); - - if ($result) { - $result->append($tracking); - $counter++; - } - } - - // Tracking Details Not Available - if ($counter === 0) { - $this->appendTrackingError( - $trackingValue[0] ?? '', - (string)__('For some reason we can\'t retrieve tracking info right now.') - ); - } - } - - /** - * Get tracking response - * - * @return string - */ - public function getResponse(): string - { - $statuses = ''; - - // If $_result is of type \Magento\Shipping\Model\Tracking\Result, handle it - if ($this->_result instanceof \Magento\Shipping\Model\Tracking\Result) { - if ($trackings = $this->_result->getAllTrackings()) { - foreach ($trackings as $tracking) { - if ($data = $tracking->getAllData()) { - if (!empty($data['status'])) { - $statuses .= __($data['status']) . "\n<br/>"; - } else { - $statuses .= __('Empty response') . "\n<br/>"; - } - } - } - } - } - -// // Handle \Magento\Shipping\Model\Rate\Result if needed -// if ($this->_result instanceof \Magento\Shipping\Model\Rate\Result) { -// // Implement the logic for Rate\Result if applicable -// } - - if (trim($statuses) === '') { - $statuses = (string)__('Empty response'); - } - - return $statuses; - } - /** * Get allowed shipping methods * @@ -670,7 +535,7 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car public function getAllowedMethods(): array { $allowedMethods = $this->getConfigData('allowed_methods'); - if ($allowedMethods === false) { + if (empty($allowedMethods)) { return []; // Return an empty array if no allowed methods are configured } @@ -773,55 +638,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car return $data; } - /** - * Parse track details response from Bob Go. - * - * @param string $trackInfo - * @return array<string, array<int, array<string, string>>> - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - private function processTrackingDetails(string $trackInfo): array - { - $result = [ - 'shippeddate' => [], // Initializing as an array of arrays - 'deliverydate' => [], // Initializing as an array of arrays - 'deliverytime' => [], // Initializing as an array of arrays - 'deliverylocation' => [], // Initializing as an array of arrays - 'weight' => [], // Initializing as an array of arrays - 'progressdetail' => [], // This will be populated with an array of arrays - ]; - - $result = $this->_requestTracking($trackInfo, $result); - - return $result; - } - - /** - * Append error message to rate result instance. - * - * @param string $trackingValue - * @param string $errorMessage - * @return void - */ - private function appendTrackingError(string $trackingValue, string $errorMessage): void - { - $error = $this->_trackErrorFactory->create(); - $error->setCarrier(self::CODE); - $error->setCarrierTitle($this->getConfigData('title')); - $error->setTracking($trackingValue); - $error->setErrorMessage($errorMessage); - - $result = $this->getResult(); - - if ($result !== null) { - $result->append($error); - } else { - // Handle the case where $result is null, such as logging an error - $this->_logger->error('Failed to append tracking error: Result object is null.'); - } - } - /** * Format a date to 'd M Y'. * @@ -864,6 +680,11 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car return UData::RATES_ENDPOINT; } + private function getWebhookUrl(): string + { + return UData::WEBHOOK_URL; + } + /** * Perform API Request to Bob Go API and return response. * @@ -883,26 +704,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car } } - /** - * Perform API Request for Shipment Tracking to Bob Go API and return response. - * - * @param string $trackInfo The tracking information or tracking ID. - * @param array<string,array<int,array<string,string>>> $result The result array to be - * populated with tracking details. - * @return array<string, array<int, array<string, string>>> The updated result array with tracking details. - */ - private function _requestTracking(string $trackInfo, array $result): array - { - $response = $this->trackBobGoShipment($trackInfo); - - // Validate that the response is an array and contains at least one element - if (is_array($response) && isset($response[0]) && is_array($response[0])) { - $result = $this->prepareActivity($response[0], $result); - } - - return $result; - } - /** * Format rates from Bob Go API response and append to rate result instance of carrier. * @@ -976,35 +777,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car } } - /** - * Prepare received checkpoints and activity from Bob Go Shipment Tracking API. - * - * @param array<string,mixed> $response The API response containing tracking checkpoints. - * @param array<string,array<int,array<string,string>>> $result The result array to be - * populated with activity details. - * @return array<string, array<int, array<string, string>>> The updated result array with activity details. - */ - private function prepareActivity(array $response, array $result): array - { - if (isset($response['checkpoints']) && is_array($response['checkpoints'])) { - foreach ($response['checkpoints'] as $checkpoint) { - if (is_array($checkpoint) && - isset($checkpoint['status'], $checkpoint['time']) && - is_string($checkpoint['status']) && - is_string($checkpoint['time']) - ) { - $result['progressdetail'][] = [ - 'activity' => $checkpoint['status'], - 'deliverydate' => $this->formatDate($checkpoint['time']), - 'deliverytime' => $this->formatTime($checkpoint['time']), - ]; - } - } - } - - return $result; - } - /** * Get Working Days between time of checkout and delivery date (min and max). * @@ -1037,21 +809,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car return $no_days - $weekends; } - /** - * Curl request to Bob Go Shipment Tracking API. - * - * @param string $trackInfo The tracking information or tracking ID. - * @return mixed The decoded API response. - */ - private function trackBobGoShipment(string $trackInfo): mixed - { - $this->curl->get(UData::TRACKING . $trackInfo); - - $response = $this->curl->getBody(); - - return json_decode($response, true); - } - /** * Build the payload for Bob Go API request and return the response. * @@ -1199,27 +956,6 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car return $itemsArray; } - /** - * Checks if the required data fields are present in the request. - * - * @param \Magento\Framework\DataObject $request The data object containing the request information. - * @return bool True if all required fields are present, otherwise false. - */ - public function hasRequiredData(\Magento\Framework\DataObject $request): bool - { - $requiredFields = [ - 'dest_country_id', - 'dest_region_id', - ]; - - foreach ($requiredFields as $field) { - if (!$request->getData($field)) { - return false; - } - } - return true; - } - /** * Trigger a test for rates. * @@ -1310,4 +1046,72 @@ class BobGo extends AbstractCarrierOnline implements \Magento\Shipping\Model\Car } return false; } + + public function isWebhookEnabled(): bool + { + $enabled = $this->scopeConfig->getValue( + 'carriers/bobgo/enable_webhooks', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + + // Cast the value to a boolean + return filter_var($enabled, FILTER_VALIDATE_BOOLEAN); + } + + + public function triggerWebhookTest(): bool + { + $webhookKey = $this->scopeConfig->getValue( + 'carriers/bobgo/webhook_key', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + + // Check if the webhook key is empty and return false + if (empty($webhookKey)) { + return false; + } + + // Convert the string to a boolean value + $isEnabled = $this->isWebhookEnabled(); + + $storeId = strval($this->_storeManager->getStore()->getId()); + + $payload = [ + 'event' => 'webhook_validation', + 'channel_identifier' => $this->getBaseUrl(), + 'store_id' => $storeId, + 'webhooks_enabled' => $isEnabled, + ]; + + try { + $this->encodeWebhookAndPostRequest($this->getWebhookUrl(), $payload, $storeId, $webhookKey); + $statusCode = $this->curl->getStatus(); + $responseBody = $this->curl->getBody(); + + if ($statusCode != 200) { + throw new LocalizedException(__('Status code from BobGo: %1', $statusCode)); + } + } catch (\Exception $e) { + return false; + } + return true; + } + + public function encodeWebhookAndPostRequest($url, $data, $storeId, $webhookKey) { + // Generate the HMAC-SHA256 hash as raw binary data + $rawSignature = hash_hmac('sha256', $storeId, $webhookKey, true); + // Encode the binary data in Base64 + $signature = base64_encode($rawSignature); + // Set headers and post the data + $this->curl->addHeader('Content-Type', 'application/json'); + $this->curl->addHeader('x-m-webhook-signature', $signature); + + $payloadJson = json_encode($data); + if ($payloadJson === false) { + throw new \RuntimeException('Failed to encode payload to JSON.'); + } + + $this->curl->addHeader('Content-Type', 'application/json'); + $this->curl->post($url, $payloadJson); + } } diff --git a/Model/Carrier/UData.php b/Model/Carrier/UData.php index 47b5d8b050f519a4e96f2ae432f3a0ea6ab70e0d..bbb17ddfbad6bffbb33cd3baab5e139ab6581cb4 100644 --- a/Model/Carrier/UData.php +++ b/Model/Carrier/UData.php @@ -20,4 +20,11 @@ class UData * @var string */ public const RATES_ENDPOINT = 'https://api.bobgo.co.za/rates-at-checkout/magento'; + + /** + * Order create/update webhook URL + * + * @var string + */ + public const WEBHOOK_URL = 'https://api.bobgo.co.za/webhook/channel/magento'; } diff --git a/Observer/ConfigChangeObserver.php b/Observer/ConfigChangeObserver.php index 1b6c07214501db7cd9ba19dc325fe3bbade643a5..efc0179a7bd1288e9f61931fae30f25f63597569 100644 --- a/Observer/ConfigChangeObserver.php +++ b/Observer/ConfigChangeObserver.php @@ -52,6 +52,7 @@ class ConfigChangeObserver implements ObserverInterface { $changedPaths = $observer->getEvent()->getData('changed_paths'); + // Test for rates at checkout if (is_array($changedPaths) && in_array('carriers/bobgo/active', $changedPaths)) { if ($this->bobGo->isActive()) { $result = $this->bobGo->triggerRatesTest(); @@ -70,5 +71,23 @@ class ConfigChangeObserver implements ObserverInterface } } } + + // Test for webhooks + if ((is_array($changedPaths) && in_array('carriers/bobgo/enable_webhooks', $changedPaths)) || (is_array($changedPaths) && in_array('carriers/bobgo/webhook_key', $changedPaths))) { + $result = $this->bobGo->triggerWebhookTest(); + + if ($this->bobGo->isWebhookEnabled()) { + if ($result) { + $this->messageManager->addSuccessMessage( + __('Webhook validation successful.') + ); + } else { + $this->messageManager->addErrorMessage( + __('Webhook validation failed. Please check your internet connection + and use your Bob Go integration consumer secret key for webhook validation.') + ); + } + } + } } } diff --git a/Observer/ModifyShippingDescription.php b/Observer/ModifyShippingDescription.php new file mode 100644 index 0000000000000000000000000000000000000000..2e443aff7dc7af482ec5ae4630129244e080b95c --- /dev/null +++ b/Observer/ModifyShippingDescription.php @@ -0,0 +1,58 @@ +<?php + +namespace BobGroup\BobGo\Observer; + +use Magento\Framework\Event\ObserverInterface; +use Magento\Framework\Event\Observer; +use Psr\Log\LoggerInterface; + +class ModifyShippingDescription implements ObserverInterface +{ + public const CODE = 'bobgo'; + + protected $logger; + + public function __construct(LoggerInterface $logger) + { + $this->logger = $logger; + } + + public function execute(Observer $observer) + { + // Get the order object from the event + $order = $observer->getEvent()->getOrder(); + + // Get the current shipping description + $shippingDescription = $order->getShippingDescription(); + + // Get the method title from the shipping description + $methodTitle = $this->extractMethodTitle($shippingDescription); + + // Set the new shipping description based only on MethodTitle + $newDescription = $methodTitle; + + // Update the shipping description in the order + $order->setShippingDescription($newDescription); + } + + /** + * Helper function to extract the method title from the original shipping description + * + * @param string $shippingDescription + * @return string + */ + private function extractMethodTitle($shippingDescription) + { + // Find the position of the last dash in the string + $lastDashPosition = strrpos($shippingDescription, ' - '); + + // If a dash is found, extract the part after the last dash + if ($lastDashPosition !== false) { + return trim(substr($shippingDescription, $lastDashPosition + 3)); // +3 to skip the ' - ' part + } + + // If no dash is found, return the full description (fallback) + return $shippingDescription; + } + +} diff --git a/Observer/OrderCreateWebhook.php b/Observer/OrderCreateWebhook.php new file mode 100644 index 0000000000000000000000000000000000000000..74f1ce4520155ee9b072cd2b6d0d2c6e00ea89a8 --- /dev/null +++ b/Observer/OrderCreateWebhook.php @@ -0,0 +1,19 @@ +<?php + +namespace BobGroup\BobGo\Observer; + +use Magento\Framework\Event\Observer; + +class OrderCreateWebhook extends OrderWebhookBase +{ + public function execute(Observer $observer) + { + $order = $observer->getEvent()->getOrder(); + if (!$order) { + return; + } + + // Extract order data and send to the webhook URL + $this->sendWebhook($order); + } +} diff --git a/Observer/OrderWebhookBase.php b/Observer/OrderWebhookBase.php new file mode 100644 index 0000000000000000000000000000000000000000..311daa7b64f0d512d79bf94f2e6af3f894a3deac --- /dev/null +++ b/Observer/OrderWebhookBase.php @@ -0,0 +1,74 @@ +<?php + +namespace BobGroup\BobGo\Observer; + +use BobGroup\BobGo\Model\Carrier\UData; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Event\ObserverInterface; +use Magento\Framework\HTTP\Client\Curl; +use Magento\Store\Model\StoreManagerInterface; +use Psr\Log\LoggerInterface; +use BobGroup\BobGo\Model\Carrier\BobGo; + +abstract class OrderWebhookBase implements ObserverInterface +{ + protected Curl $curl; + protected LoggerInterface $logger; + protected StoreManagerInterface $storeManager; + protected ScopeConfigInterface $scopeConfig; + protected $bobGo; + + public function __construct(LoggerInterface $logger, Curl $curl, StoreManagerInterface $storeManager, ScopeConfigInterface $scopeConfig, BobGo $bobGo) + { + $this->logger = $logger; + $this->curl = $curl; + $this->storeManager = $storeManager; + $this->scopeConfig = $scopeConfig; + $this->bobGo = $bobGo; + } + + protected function sendWebhook($order) + { + // Return early if not enabled + if (!$this->bobGo->isWebhookEnabled()) { + return; + } + + // Webhook URL + $url = $this->getWebhookUrl(); + + $storeId = $this->getStoreId(); + + $orderId = $order->getId(); + + // Prepare payload + $data = [ + 'event' => 'order_updated', + 'order_id' => $orderId, + 'channel_identifier' => $this->bobGo->getBaseUrl(), + 'store_id' => $storeId, + 'webhooks_enabled' => true, // If we get to this point webhooks are enabled + ]; + + // Generate the signature using the webhook key saved in config + $webhookKey = $this->scopeConfig->getValue('carriers/bobgo/webhook_key', \Magento\Store\Model\ScopeInterface::SCOPE_STORE); + // Check if the webhook key is empty and return false + if (empty($webhookKey)) { + return; + } + + // Send the webhook + $this->bobGo->encodeWebhookAndPostRequest($url, $data, $storeId, $webhookKey); + } + + private function getWebhookUrl(): string + { + return UData::WEBHOOK_URL; + } + + private function getStoreId(): string + { + $storeId = $this->storeManager->getStore()->getId(); + return $storeId; + } +} diff --git a/Plugin/Block/DataProviders/Tracking/ChangeTitle.php b/Plugin/Block/DataProviders/Tracking/ChangeTitle.php deleted file mode 100644 index a035d238ef81b90a649f0b7ae33541f6b7c6e7ee..0000000000000000000000000000000000000000 --- a/Plugin/Block/DataProviders/Tracking/ChangeTitle.php +++ /dev/null @@ -1,31 +0,0 @@ -<?php - -namespace BobGroup\BobGo\Plugin\Block\DataProviders\Tracking; - -use BobGroup\BobGo\Model\Carrier; -use Magento\Shipping\Model\Tracking\Result\Status; -use Magento\Shipping\Block\DataProviders\Tracking\DeliveryDateTitle as Subject; - -/** - * Plugin to change delivery date title with bobgo customized value - */ - -class ChangeTitle -{ - /** - * Title modification in case if bobgo used as carrier - * - * @param Subject $subject - * @param \Magento\Framework\Phrase|string $result - * @param Status $trackingStatus - * @return \Magento\Framework\Phrase|string - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function afterGetTitle(Subject $subject, $result, Status $trackingStatus) - { - if ($trackingStatus->getCarrier() === \BobGroup\BobGo\Model\Carrier\BobGo::CODE) { - $result = __('Expected delivery:'); - } - return $result; - } -} diff --git a/Plugin/Block/Tracking/PopUpDeliveryDate.php b/Plugin/Block/Tracking/PopUpDeliveryDate.php deleted file mode 100644 index bb375285de7c84f6104c1b4014689803c4e9365f..0000000000000000000000000000000000000000 --- a/Plugin/Block/Tracking/PopUpDeliveryDate.php +++ /dev/null @@ -1,53 +0,0 @@ -<?php - -namespace BobGroup\BobGo\Plugin\Block\Tracking; - -use Magento\Shipping\Block\Tracking\Popup; -use Magento\Shipping\Model\Tracking\Result\Status; - -/* - * Plugin to update delivery date value in case if Bob Go is a carrier used - */ -class PopupDeliveryDate -{ - /** - * Bob Go carrier code - */ - private const BOB_GO_CARRIER_CODE = 'bobgo_carrier_code'; // Replace with your actual carrier code - - /** - * Show only date for expected delivery in case if Bob Go is a carrier - * - * @param Popup $subject - * @param string $result - * @param string $date - * @param string $time - * @return string - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function afterFormatDeliveryDateTime(Popup $subject, $result, $date, $time) - { - if ($this->getCarrier($subject) === self::BOB_GO_CARRIER_CODE) { - $result = $subject->formatDeliveryDate($date); - } - return $result; - } - - /** - * Retrieve carrier name from tracking info - * - * @param Popup $subject - * @return string - */ - private function getCarrier(Popup $subject): string - { - foreach ($subject->getTrackingInfo() as $trackingData) { - foreach ($trackingData as $trackingInfo) { - if ($trackingInfo instanceof Status) { - return $trackingInfo->getCarrier() ?? ''; - } - } - } - return ''; - } -} diff --git a/Readme.md b/Readme.md index fcb6fb88a897b0fe65141ac458fc1de46b5f6343..e85f78fa7cbd9a3da16ba3f9a342e2ef2726e4d9 100644 --- a/Readme.md +++ b/Readme.md @@ -1,97 +1,3 @@ -# Magento 2 Bob Go Shipping Extension +# Bob Go shipping extension for Magento 2 -## Introduction - -A complete guide to install Magento Bob Go Shipping extension in Magento 2. - -## Features ->This extension allows you to get real-time shipping rates from Bob Go shipping services and display them to your customers during checkout. - ->This extension also allows you to track shipments and get delivery status updates from Bob Go shipping services. - -## How to install Magento 2 Bob Go Shipping Extension - -### Option 1 (recommended): Install via composer - -Run the following command in Magento 2 root folder:</br> - ->_Note: You must have composer installed on your server for this option_ - -#### 1. Execute the following command to install the module: - -``` -composer require bobgo/bobgo-magento-extension -``` -#### 2. Enter following commands to enable the module: - -``` -bin/magento module:enable BobGroup_BobGo -bin/magento cache:clean -bin/magento cache:flush -bin/magento setup:upgrade -bin/magento setup:di:compile -bin/magento setup:static-content:deploy -``` - -### Option 2: Install via zip file - -1. Download the extension zip file from the link below: </br> - - <a href="https://gitlab.bob.co.za/bob-public-utils/bobgo-magento-extension/-/archive/prod/bobgo-magento-extension-prod.zip"> Download Magento 2 Bob Go Shipping Extension </a> - -2. Unzip the file and copy contents - -3. Create `BobGroup/BobGo` <em>Directory</em> - -**It should look like this:** </br> ->{Magento root}/app/code/BobGroup/BobGo/ - - ->**{Magento root}**`/app/code/BobGroup/BobGo/`**{Paste here}** - - -4. Go to Magento root folder and run all commands below to install `BobGroup_BobGo`: </br> -``` -bin/magento cache:clean -bin/magento cache:flush -bin/magento setup:upgrade -bin/magento setup:di:compile -bin/magento setup:static-content:deploy -``` -_____________________________________________________________________________________________________________________ -# After installation - - -## How to configure Magento 2 Bob Go Shipping Extension - -### ✓ Step 1: Create an account on Bob Go - -You need to create an account on Bob Go to get your store identified by the API. - -Please visit [Bob Go](https://bobgo.co.za) to create an account. - -### ✓ Step 2: Integrate Magento and Bob Go - -1. In the Magento admin portal click on `System > Integrations` and click on `Add New Integration` -2. Under `Basic Settings > Integration Info` fill in the name of the integration eg. Bob Go -3. Under `Basic Settings > API` select `All` for Resource access -4. Click `Save` and enter your Magento admin portal password -5. The `Integration Details` will be displayed on the page -6. On [Bob Go](https://bobgo.co.za) go to `Sales channels > Add channel > Magento` and enter the Magento integration details from step 5 and click `Grant access` -7. On Bob Go go to `Rates at checkout > Settings > Installed channels` and enable your channel for rates at checkout -8. Make sure you have service levels configured and enabled on Bob Go `Rates at checkout > Service levels` - -### ✓ Step 3: Login to Magento Admin - -1. In the Magento admin portal click on `Stores > Configuration > Sales > Delivery Methods` -2. Go to the Bob Go delivery method and enable Bob Go rates at checkout -3. Click `Save Config` -4. A message at the top of the screen will confirm that rates at checkout is enabled correctly: `Bob Go rates at checkout connected.` - -#### Admin Configurations: Update Store Information* - -When the extension is **installed** and **enabled**, a new field will be created in `Store Information` : `Suburb`. Enter the necessary details: - -1. `Stores`> `Configuration`> `General`>`General` -2. `Store Information`>`Suburb` -3. Update the store information and click `Save config` +See the installation guide for information: [Installation Guide](./Installation guide - Bob Go shipping extension for Magento 2.pdf) \ No newline at end of file diff --git a/Test/Unit/Plugin/Block/DataProviders/Tracking/ChangeTitleTest.php b/Test/Unit/Plugin/Block/DataProviders/Tracking/ChangeTitleTest.php deleted file mode 100644 index 4d8bd9d0a66447160396590cc4b878cb8acfad25..0000000000000000000000000000000000000000 --- a/Test/Unit/Plugin/Block/DataProviders/Tracking/ChangeTitleTest.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php - -namespace BobGroup\BobGo\Test\Unit\Plugin\Block\DataProviders\Tracking; - -use BobGroup\BobGo\Plugin\Block\DataProviders\Tracking\ChangeTitle; -use BobGroup\BobGo\Model\Carrier\BobGo; -use Magento\Shipping\Model\Tracking\Result\Status; -use Magento\Shipping\Block\DataProviders\Tracking\DeliveryDateTitle as Subject; -use PHPUnit\Framework\TestCase; - -class ChangeTitleTest extends TestCase -{ - /** - * @var ChangeTitle - */ - private $plugin; - - protected function setUp(): void - { - // Instantiate the ChangeTitle plugin - $this->plugin = new ChangeTitle(); - } - - public function testAfterGetTitleWithBobGoCarrier(): void - { - // Create a custom Status object with BobGo carrier - $status = $this->getMockBuilder(Status::class) - ->setMethods(['getCarrier']) - ->getMock(); - - $status->method('getCarrier')->willReturn(BobGo::CODE); - - // Mock the Subject class - $subjectMock = $this->createMock(Subject::class); - - // Call the plugin method afterGetTitle - $result = $this->plugin->afterGetTitle($subjectMock, 'Original Title', $status); - - // Assert that the title was changed for BobGo carrier - $this->assertEquals('Expected delivery:', $result); - } - - public function testAfterGetTitleWithOtherCarrier(): void - { - // Create a custom Status object with a different carrier - $status = $this->getMockBuilder(Status::class) - ->setMethods(['getCarrier']) - ->getMock(); - - $status->method('getCarrier')->willReturn('other_carrier_code'); - - // Mock the Subject class - $subjectMock = $this->createMock(Subject::class); - - // Call the plugin method afterGetTitle - $originalTitle = 'Original Title'; - $result = $this->plugin->afterGetTitle($subjectMock, $originalTitle, $status); - - // Assert that the title was not changed for other carriers - $this->assertEquals($originalTitle, $result); - } -} diff --git a/Test/Unit/Plugin/Block/Tracking/PopUpDeliveryDateTest.php b/Test/Unit/Plugin/Block/Tracking/PopUpDeliveryDateTest.php deleted file mode 100644 index 6c01770254cd04592f5fbafa8bfccacd4d6bfd27..0000000000000000000000000000000000000000 --- a/Test/Unit/Plugin/Block/Tracking/PopUpDeliveryDateTest.php +++ /dev/null @@ -1,92 +0,0 @@ -<?php - -namespace BobGroup\BobGo\Test\Unit\Plugin\Block\Tracking; - -use BobGroup\BobGo\Plugin\Block\Tracking\PopupDeliveryDate; -use Magento\Shipping\Block\Tracking\Popup; -use Magento\Shipping\Model\Tracking\Result\Status; -use PHPUnit\Framework\TestCase; - -class PopupDeliveryDateTest extends TestCase -{ - /** - * @var PopupDeliveryDate - */ - private $plugin; - - protected function setUp(): void - { - // Instantiate the PopupDeliveryDate plugin - $this->plugin = new PopupDeliveryDate(); - } - - public function testAfterFormatDeliveryDateTimeWithBobGoCarrier(): void - { - // Create an instance of the Status class - $status = new Status(); - $status->setCarrier('bobgo_carrier_code'); - - // Mock the Popup class - $popupMock = $this->createMock(Popup::class); - $popupMock->method('getTrackingInfo')->willReturn([ - ['tracking_info' => $status], - ]); - - // Mock the formatDeliveryDate method - $popupMock->method('formatDeliveryDate') - ->with('2024-08-19') - ->willReturn('Aug 19, 2024'); - - // Call the plugin method afterFormatDeliveryDateTime - $result = $this->plugin->afterFormatDeliveryDateTime( - $popupMock, - 'Aug 19, 2024 10:00 AM', - '2024-08-19', - '10:00 AM' - ); - - // Assert that the time was stripped for BobGo carrier - $this->assertEquals('Aug 19, 2024', $result); - } - - public function testAfterFormatDeliveryDateTimeWithOtherCarrier(): void - { - // Create an instance of the Status class - $status = new Status(); - $status->setCarrier('other_carrier_code'); - - // Mock the Popup class - $popupMock = $this->createMock(Popup::class); - $popupMock->method('getTrackingInfo')->willReturn([ - ['tracking_info' => $status], - ]); - - // Call the plugin method afterFormatDeliveryDateTime - $result = $this->plugin->afterFormatDeliveryDateTime( - $popupMock, - 'Aug 19, 2024 10:00 AM', - '2024-08-19', - '10:00 AM' - ); - - // Assert that the time remains unchanged for other carriers - $this->assertEquals('Aug 19, 2024 10:00 AM', $result); - } - - public function testGetCarrierWithNoTrackingInfo(): void - { - // Mock the Popup class with no tracking info - $popupMock = $this->createMock(Popup::class); - $popupMock->method('getTrackingInfo')->willReturn([]); - - // Call the getCarrier method directly - $reflection = new \ReflectionClass($this->plugin); - $method = $reflection->getMethod('getCarrier'); - $method->setAccessible(true); - - $result = $method->invokeArgs($this->plugin, [$popupMock]); - - // Assert that an empty string is returned when no tracking info is available - $this->assertEquals('', $result); - } -} diff --git a/composer.json b/composer.json index 637ad878c7781f367b045144816252b0b374fec8..83317accc96cd68c7d9ad9191e5806418670b9e0 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "bobgo/bobgo-magento-extension", "description": "Smart shipping and order management solution in South Africa", "type": "magento2-module", - "version": "1.0.33", + "version": "1.0.41", "authors": [ { "name": "Bob Go", diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 410c2c2b9a14e1ecfe406f498fb95d51783d9206..03d77876036cd97ffb817ff3211d9a31767af471 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -20,7 +20,7 @@ </field> <field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0"> <label>Enable Bob Go rates at checkout</label> - <comment>When this setting is enabled, your customers will be presented with shipping rates at checkout, as configured on the Bob Go platform under Rates at checkout.</comment> + <comment>When enabled, your customers will be presented with shipping rates at checkout, as configured on the Bob Go platform under Rates at checkout.</comment> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> </field> <field id="additional_info" translate="label" type="select" sortOrder="7" showInDefault="1" showInWebsite="1"> @@ -28,6 +28,25 @@ <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> <comment>Displays the delivery timeframe and additional service level description, as configured on Bob Go.</comment> </field> + + <!-- Enable Webhooks Checkbox --> + <field id="enable_webhooks" translate="label" type="select" sortOrder="8" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Enable webhooks</label> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + <comment>When this setting is enabled, webhooks will be sent to Bob Go to notify about order creation and updates, ensuring real-time synchronization between your store and Bob Go.</comment> + </field> + + <!-- Webhook Key Input Field --> + <field id="webhook_key" translate="label" type="text" sortOrder="9" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Webhook authentication key</label> + <comment>Enter your Bob Go integration API consumer secret key for webhook authentication.</comment> + </field> +<!-- Hiding the `Enable Track My Order` setting for now--> + <field id="enable_track_order" translate="label" type="select" sortOrder="10" showInDefault="0" showInWebsite="0" showInStore="0"> + <label>Enable Track my order</label> + <comment>When this setting is enabled, your customers will be presented with a page to track orders.</comment> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + </field> </group> </section> </system> diff --git a/etc/events.xml b/etc/events.xml index bfb5e9669522f329879ecc96da2ca4a571ea8b2e..a6fab5c7c81c3fe6dd4331d91aaa71bd88848158 100644 --- a/etc/events.xml +++ b/etc/events.xml @@ -1,3 +1,11 @@ <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> + <event name="sales_order_save_after"> + <observer name="order_create_webhook" instance="BobGroup\BobGo\Observer\OrderCreateWebhook"/> + </event> + <!-- app/code/Vendor/Module/etc/events.xml --> + <event name="sales_order_place_before"> + <observer name="modify_shipping_description" instance="BobGroup\BobGo\Observer\ModifyShippingDescription"/> + </event> + </config> diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml index bc1aaebb43890432e80d8e9d27bfd5838b7c8e8b..25a80a9bc5c7b63aad2741c99339161717ede977 100644 --- a/etc/frontend/di.xml +++ b/etc/frontend/di.xml @@ -13,4 +13,12 @@ <argument name="logger" xsi:type="object">Psr\Log\LoggerInterface</argument> </arguments> </type> + <type name="BobGroup\BobGo\Observer\OrderCreateWebhook"> + <arguments> + <argument name="logger" xsi:type="object">Psr\Log\LoggerInterface</argument> + <argument name="curl" xsi:type="object">Magento\Framework\HTTP\Client\Curl</argument> + <argument name="storeManager" xsi:type="object">Magento\Store\Model\StoreManagerInterface</argument> + </arguments> + </type> + </config> diff --git a/etc/frontend/routes.xml b/etc/frontend/routes.xml new file mode 100644 index 0000000000000000000000000000000000000000..d6d10467741f62ea0f0f24d7fba12bc9e921e814 --- /dev/null +++ b/etc/frontend/routes.xml @@ -0,0 +1,9 @@ +<?xml version="1.0"?> + +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> + <router id="standard"> + <route id="bobgo" frontName="bobgo"> + <module name="BobGroup_BobGo" /> + </route> + </router> +</config> diff --git a/etc/module.xml b/etc/module.xml index fe2b36da4d6bad5e35cb60c85d1f1ff05d245001..a79063f98eb5a146f6f34d8de1fa087c52a2042f 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -7,7 +7,7 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="BobGroup_BobGo" setup_version="1.0.0"> + <module name="BobGroup_BobGo" setup_version="1.0.41"> <sequence> <module name="Magento_Webapi"/> <module name="Magento_Catalog"/> diff --git a/make-zip.sh b/make-zip.sh new file mode 100755 index 0000000000000000000000000000000000000000..6385066a926187eb2b6734463bd258256cd2cfe1 --- /dev/null +++ b/make-zip.sh @@ -0,0 +1,153 @@ +#!/bin/bash + +# Exit immediately if a command exits with a non-zero status +# +set -e + +# Function to log messages +log() { + echo "** $1" +} + +# Function to install jq if not installed +install_jq() { + if command -v jq >/dev/null 2>&1; then + log "jq is already installed." + else + log "jq is not installed. Attempting to install..." + + if [[ "$OSTYPE" == "darwin"* ]]; then + if command -v brew >/dev/null 2>&1; then + log "Installing jq using Homebrew..." + brew install jq + else + log "Homebrew is not installed. Please install Homebrew first:" + log "https://brew.sh/" + exit 1 + fi + elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + if command -v apt-get >/dev/null 2>&1; then + log "Installing jq using apt-get..." + sudo apt-get update + sudo apt-get install -y jq + else + log "apt-get not found. Please install jq manually." + exit 1 + fi + else + log "Unsupported OS. Please install jq manually." + exit 1 + fi + + if command -v jq >/dev/null 2>&1; then + log "jq installed successfully." + else + log "Failed to install jq. Please install it manually." + exit 1 + fi + fi +} + +# Function to ensure Perl is installed +install_perl() { + if command -v perl >/dev/null 2>&1; then + log "Perl is already installed." + else + log "Perl is not installed. Please install Perl to proceed." + exit 1 + fi +} + +# Function to extract version using jq +get_version() { + if command -v jq >/dev/null 2>&1; then + jq -r '.version' package.json + else + # Fallback to grep and awk if jq is not available + grep '"version":' package.json | head -1 | awk -F'"' '{print $4}' + fi +} + +# Function to update the 'Version:' header in bobpay-plugin.php using Perl +update_version_header() { + local VERSION=$1 + local FILE="composer.json" + + log "Updating 'version:' header in ${FILE} using Perl..." + + # Use Perl to update the 'Version:' line + perl -pi -e "s/(\"version\":\s*\")([0-9.]+)(\"\,)/\${1}${VERSION}\"\,/g" "$FILE" + log "'version:' header updated to ${VERSION}." +} + +update_define_constant() { + local VERSION=$1 + local FILE="etc/module.xml" + + log "Updating 'version' constant in ${FILE} using Perl..." + + # Use Perl to replace the version constant + perl -pi -e "s/(setup_version=\")([^\"]*)/\${1}${VERSION}/g" "$FILE" + log "'setup_version' constant updated to ${VERSION}." +} + +# Function to build the plugin +build_plugin() { + log "Building plugin..." + npm install + log "Plugin built successfully." +} + +# Function to create the zip package +create_zip() { + local VERSION=$1 + local ZIPNAME="bobgo-magento-plugin.zip" + local PACKAGE_DIR="package" + + log "Creating zip file: ${ZIPNAME}..." + + # Remove any existing package directory and zip file + rm -rf "${PACKAGE_DIR}" + rm -f "${ZIPNAME}" + + # Create the package directory + mkdir -p "${PACKAGE_DIR}" + + # Use rsync to copy files, excluding those in .distignore + log "Copying files to package directory..." + rsync -av --exclude-from='.distignore' ./ "${PACKAGE_DIR}/" + + # Create the zip file from the package directory + log "Creating zip file..." + cd "${PACKAGE_DIR}" + zip -r "../${ZIPNAME}" . + cd .. + + # Clean up the package directory + log "Cleaning up..." + rm -rf "${PACKAGE_DIR}" + + log "Zip file '${ZIPNAME}' created successfully." +} + +# Main script execution +main() { + log "Starting build process..." + + install_jq + install_perl + + VERSION=$(get_version) + log "Extracted version: ${VERSION}" + + build_plugin + update_version_header "${VERSION}" + update_define_constant "${VERSION}" + create_zip "${VERSION}" + + log "Build process completed successfully." +} + +# Execute the main function +main + diff --git a/package.json b/package.json new file mode 100644 index 0000000000000000000000000000000000000000..e44822d7d797846f0186f039f9565bc09c05df2e --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "bobgo-magento-plugin", + "description": "Bob Go magento plugin", + "version": "1.0.41", + "license": "GPL-2.0-or-later", + "scripts": { + "prepare": "husky install", + "update-version-files": "node update-version.js" + }, + "husky": { + "hooks": { + "pre-commit": "npm config set git-tag-version false && npm version patch && npm run update-version-files && git add package.json etc/module.xml composer.json && pretty-quick --staged" + } + }, + "devDependencies": { + "husky": "^8.0.1", + "npm-run-all": "^4.1.5" + } +} diff --git a/update-version.js b/update-version.js new file mode 100644 index 0000000000000000000000000000000000000000..f5a9606305502bad56e35c586a0f27771e4d1c3c --- /dev/null +++ b/update-version.js @@ -0,0 +1,36 @@ +const fs = require('fs'); + +// Read version from package.json +const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')); +const version = packageJson.version; + +// Files to update +const filesToUpdate = ['composer.json', 'etc/module.xml']; + +// Function to update version in files +function updateVersionInFile(filePath) { + let content = fs.readFileSync(filePath, 'utf8'); + + if (filePath === 'composer.json') { + // Update the Version header in the plugin file + // Update the version in composer.json + content = content.replace( + /(\"version\":\s*\")([0-9.]+)(\"\,)/g, + `$1${version}$3` + ); + } + + if (filePath === 'etc/module.xml') { + // Update the version tag in etc/module.xml + content = content.replace( + /(setup_version=")([^"]*)/g, + `$1${version}` + ); + + } + + fs.writeFileSync(filePath, content); +} + +// Update each file +filesToUpdate.forEach(updateVersionInFile); diff --git a/view/frontend/layout/bobgo_tracking_index.xml b/view/frontend/layout/bobgo_tracking_index.xml new file mode 100644 index 0000000000000000000000000000000000000000..e36faa5492b864f1f27524486ba0ce148a364b64 --- /dev/null +++ b/view/frontend/layout/bobgo_tracking_index.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> + <update handle="customer_account"/> + <head> + <title> + Track my order + </title> + </head> + <body> + <referenceContainer name="content"> + <block class="BobGroup\BobGo\Block\TrackingBlock" name="bobgo.tracking.index" template="BobGroup_BobGo::tracking/index.phtml" cacheable="false" /> + </referenceContainer> + </body> +</page> diff --git a/view/frontend/layout/customer_account.xml b/view/frontend/layout/customer_account.xml new file mode 100644 index 0000000000000000000000000000000000000000..701335df1dc4d481523171edc19e24bbac950feb --- /dev/null +++ b/view/frontend/layout/customer_account.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="customer_account_navigation"> + <!-- Add conditional menu to the end of the sidebar --> + <block class="BobGroup\BobGo\Block\TrackOrderLink" name="customer-account-navigation-tracking"> + <arguments> + <argument name="path" xsi:type="string">bobgo/tracking/index</argument> + <argument name="label" xsi:type="string">Track my order</argument> + </arguments> + </block> + </referenceBlock> + </body> +</page> diff --git a/view/frontend/templates/tracking/index.phtml b/view/frontend/templates/tracking/index.phtml new file mode 100644 index 0000000000000000000000000000000000000000..5895f01a27f33217c05c2519b14a57435511d8bf --- /dev/null +++ b/view/frontend/templates/tracking/index.phtml @@ -0,0 +1,127 @@ +<?php +$shipmentData = $this->getResponse(); +?> + +<style> + .track-order-container { + max-width: 600px; + margin: auto; + padding: 20px; + border: 1px solid #ddd; + background-color: #f9f9f9; + } + + .tracking-details h2 { + margin-top: 20px; + } + + .tracking-details p { + margin: 5px 0; + } + + footer { + margin-top: 20px; + font-size: 0.9em; + text-align: center; + } + + footer img { + display: block; + margin: 10px auto; + } +</style> + +<div class="track-order-container"> + <?php if (empty($shipmentData)) : ?> + <form action="<?php echo $this->getUrl('bobgo/tracking/index'); ?>" method="post" class="track-order-form"> + <div class="field"> + <label for="order_reference"><?php echo __('Order Number/Tracking Reference:'); ?></label> + <input type="text" id="order_reference" name="order_reference" required> + </div> + <br> + <div class="actions-toolbar"> + <button type="submit" class="action submit primary"><?php echo __('Track Order'); ?></button> + </div> + </form> + <?php endif; ?> + + <?php if ($shipmentData && is_array($shipmentData)) : ?> + <div class="tracking-details"> + <h2><?php echo __('Shipping Details'); ?></h2> + + <?php if (isset($shipmentData['shipment_tracking_reference'])) : ?> + <p><strong><?php echo __('Shipment:'); ?></strong> <?php echo $shipmentData['shipment_tracking_reference']; ?></p> + <?php endif; ?> + + <?php if (isset($shipmentData['order_number'])) : ?> + <p><strong><?php echo __('Order:'); ?></strong> <?php echo ltrim($shipmentData['order_number'], '0'); ?></p> + <?php endif; ?> + + <?php if (isset($shipmentData['courier_name'])) : ?> + <p><strong><?php echo __('Courier:'); ?></strong> <?php echo $shipmentData['courier_name']; ?></p> + <?php endif; ?> + + <br> + <h2><?php echo __('Tracking Details'); ?></h2> + + <?php if (isset($shipmentData['status']) && isset($shipmentData['status_friendly'])) : ?> + <?php if ($shipmentData['status'] == 'pending-collection') : ?> + <p><?php echo 'Your shipment will be collected soon. Please check back later for more information.' ?></p> + <p><strong><?php echo __('Current Status:'); ?></strong> <?php echo $shipmentData['status_friendly']; ?></p> + <?php elseif (in_array($shipmentData['status'], ['cancelled-by-courier', 'cancelled'])) : ?> + <p><?php echo 'The shipment has been cancelled.'; ?></p> + <p><strong><?php echo __('Current Status:'); ?></strong> <?php echo $shipmentData['status_friendly']; ?></p> + <?php else : ?> + <?php if (empty($shipmentData['checkpoints'])) : ?> + <p><?php echo 'Tracking information is not yet available. Please check back later for more information.'; ?></p> + <?php else : ?> + <p><?php echo 'Tracking information is available below:'; ?></p> + <table id="table_checkpoints"> + <thead> + <tr> + <th><?php echo __('Date and Time'); ?></th> + <th><?php echo __('Status'); ?></th> + <th><?php echo __('Message'); ?></th> + </tr> + </thead> + <tbody> + <?php foreach ($shipmentData['checkpoints'] as $checkpoint) : ?> + <tr> + <td> + <?php + $timeDate = new DateTime($checkpoint['time']); + echo $timeDate->format('Y M d, H:i'); + ?> + </td> + <td><strong><?php echo $checkpoint['status_friendly']; ?></strong></td> + <td><?php echo $checkpoint['message']; ?></td> + </tr> + <?php endforeach; ?> + </tbody> + </table> + <?php endif; ?> + <?php endif; ?> + <?php endif; ?> + </div> + + <br> + <footer> + <p> + <?php + echo sprintf( + __('For additional information, please contact %s (%s) and quote tracking reference %s.'), + $shipmentData['courier_name'], + $shipmentData['courier_phone'], + $shipmentData['id'] + ); + ?> + </p> + <img id="show_branding" class="image" + src="https://ik.imagekit.io/z1viz85yxs/prod-v3/bobgo/corporate-identity/bobgo_logo_smart_shipping.png?tr=w-400" + alt="Bob Go logo" style="width: 200px;"> + </footer> + <?php else : ?> + <br> + <p><?php echo __('No tracking data available.'); ?></p> + <?php endif; ?> +</div>