Skip to content

Commit e3b1e73

Browse files
initial commit
1 parent 1f2cbfa commit e3b1e73

File tree

14 files changed

+496
-2
lines changed

14 files changed

+496
-2
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
/**
3+
* @author Amasty Team
4+
* @copyright Copyright (c) Amasty (https://www.amasty.com)
5+
* @package Smart Discounts Hook
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Amasty\SmartDiscountsHook\Block\Adminhtml\System\Config;
11+
12+
use Magento\AdobeCommerceWebhooks\Model\Signature\DigitalSignature;
13+
use Magento\Backend\Block\Template\Context;
14+
use Magento\Config\Block\System\Config\Form\Field;
15+
use Magento\Framework\Data\Form\Element\AbstractElement;
16+
use Magento\Framework\Serialize\Serializer\Json;
17+
18+
class ConnectionChecker extends Field
19+
{
20+
/**
21+
* @var string
22+
*/
23+
protected $_template = 'Amasty_SmartDiscountsHook::system/config/connection.phtml';
24+
25+
/**
26+
* @var DigitalSignature
27+
*/
28+
private DigitalSignature $digitalSignature;
29+
30+
/**
31+
* @var Json
32+
*/
33+
private Json $serializer;
34+
35+
/**
36+
* @var array
37+
*/
38+
private array $testBodyData = [
39+
'connection' => [
40+
'test_form_key=' => true
41+
]
42+
];
43+
44+
public function __construct(
45+
Context $context,
46+
DigitalSignature $digitalSignature,
47+
Json $serializer,
48+
array $data = []
49+
) {
50+
parent::__construct($context, $data);
51+
$this->digitalSignature = $digitalSignature;
52+
$this->serializer = $serializer;
53+
}
54+
55+
public function render(AbstractElement $element)
56+
{
57+
$element = clone $element;
58+
$element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue();
59+
60+
return parent::render($element);
61+
}
62+
63+
/**
64+
* @inheritDoc
65+
*/
66+
protected function _getElementHtml(AbstractElement $element): string
67+
{
68+
$this->addData([
69+
'xAdobeCommerceWebhookSignature' => $this->getXAdobeCommerceWebhookSignature(),
70+
'body' => $this->serializer->serialize($this->testBodyData)
71+
]);
72+
73+
return $this->_toHtml();
74+
}
75+
76+
private function getXAdobeCommerceWebhookSignature(): string
77+
{
78+
try {
79+
return $this->digitalSignature->sign($this->testBodyData);
80+
} catch (\Exception $e) {
81+
return '';
82+
}
83+
}
84+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
/**
3+
* @author Amasty Team
4+
* @copyright Copyright (c) Amasty (https://www.amasty.com)
5+
* @package Smart Discounts Hook
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Amasty\SmartDiscountsHook\Block\Adminhtml\System\Config;
11+
12+
use Magento\Config\Block\System\Config\Form\Fieldset;
13+
14+
class InfoNotice extends Fieldset
15+
{
16+
protected function _getHeaderHtml($element)
17+
{
18+
return $this->getMessage() . parent::_getHeaderHtml($element);
19+
}
20+
21+
private function getMessage()
22+
{
23+
return '<div class="message message-notice info">'
24+
. __(
25+
'Please make sure to accurately copy the webhook URL from the Smart Discounts app settings page. '
26+
. 'If the URL is incorrect, the app may show errors when products are added to the cart. '
27+
. 'Once you’ve verified that the connection is successful, generate the module by running '
28+
. '<code>bin/magento webhooks:generate:module</code>.'
29+
)
30+
. '</div>';
31+
}
32+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
/**
3+
* @author Amasty Team
4+
* @copyright Copyright (c) Amasty (https://www.amasty.com)
5+
* @package Smart Discounts Hook
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Amasty\SmartDiscountsHook\Model\Webhook\HookField;
11+
12+
use Magento\AdobeCommerceWebhooks\Model\Filter\Converter\FieldConverterInterface;
13+
use Magento\AdobeCommerceWebhooks\Model\Webhook\HookField;
14+
use Magento\Framework\Pricing\PriceCurrencyInterface;
15+
16+
class TotalConverter implements FieldConverterInterface
17+
{
18+
public const COLLECTOR_TYPE_CODE = 'discount';
19+
20+
/**
21+
* @var PriceCurrencyInterface
22+
*/
23+
private PriceCurrencyInterface $priceCurrency;
24+
25+
public function __construct(
26+
PriceCurrencyInterface $priceCurrency
27+
) {
28+
$this->priceCurrency = $priceCurrency;
29+
}
30+
31+
/**
32+
* @inheritDoc
33+
*/
34+
public function toExternalFormat(mixed $value, HookField $field, array $pluginData)
35+
{
36+
return $value;
37+
}
38+
39+
/**
40+
* @inheritDoc
41+
*/
42+
public function fromExternalFormat(mixed $value, HookField $field, array $pluginData)
43+
{
44+
if (isset($value['amsd_base_discount']) && $value['amsd_base_discount'] !== 0) {
45+
$this->setTotalAmount($pluginData, $value);
46+
$this->setDiscountToValue($pluginData, $value);
47+
$this->updateDiscountAmountForQuoteItems($pluginData);
48+
}
49+
50+
return $value;
51+
}
52+
53+
/**
54+
* @param array $pluginData
55+
* @param array $value
56+
* @return void
57+
*/
58+
private function setTotalAmount(array $pluginData, $value): void
59+
{
60+
$total = $pluginData['total'];
61+
$quote = $pluginData['quote'];
62+
$discount = $this->priceCurrency->convert($value['amsd_base_discount'], $quote->getStore());
63+
64+
$total->addTotalAmount(self::COLLECTOR_TYPE_CODE, -$discount);
65+
$total->addBaseTotalAmount(self::COLLECTOR_TYPE_CODE, -$value['amsd_base_discount']);
66+
}
67+
68+
/**
69+
* @param array $pluginData
70+
* @param array $value
71+
* @return void
72+
*/
73+
private function setDiscountToValue(array $pluginData, &$value): void
74+
{
75+
$total = $pluginData['total'];
76+
77+
$value['discount_amount'] = $total->getDiscountAmount();
78+
$value['base_discount_amount'] = $total->getBaseDiscountAmount();
79+
}
80+
81+
/**
82+
* The webhook sets base discount amount for quote items.
83+
* We should convert it to discount amount with correct currency.
84+
* This logic should be in a separate converter.
85+
* But due to the limitations of applying converters on the array we have to do it here.
86+
*
87+
* @param array $pluginData
88+
* @return void
89+
*/
90+
private function updateDiscountAmountForQuoteItems(array $pluginData): void
91+
{
92+
$quote = $pluginData['quote'];
93+
$shippingAssignment = $pluginData['shippingAssignment'];
94+
$items = $shippingAssignment->getItems();
95+
foreach ($items as $item) {
96+
if ($item->getBaseDiscountAmount() > 0) {
97+
$discountAmount = $this->priceCurrency->convert($item->getBaseDiscountAmount(), $quote->getStore());
98+
$item->setDiscountAmount($discountAmount);
99+
}
100+
}
101+
}
102+
}

README.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,34 @@
1-
# module-smart-discounts-hook
2-
Smart Discounts Hook by Amasty
1+
# Smart Discounts Hook by Amasty
2+
## Overview
3+
The extension is required for Magento 2 compatibility with the **Smart Discounts** extension on **App Builder**.
4+
5+
### Key Features:
6+
- Verifies the connection to the Smart Discounts application via a provided URL input;
7+
- Adds the relevant discount to the order total;
8+
- Converts the applied discount into the store’s set currency.
9+
10+
## Installation
11+
### Installation via Composer
12+
1. Open your terminal and navigate to the root directory of your Magento installation.
13+
2. Run the following command to install the module:
14+
```
15+
composer require amasty/module-smart-discounts-hook
16+
```
17+
3. Enable the module by running:
18+
```
19+
php bin/magento setup:upgrade
20+
php bin/magento setup:di:compile
21+
php bin/magento cache:flush
22+
```
23+
24+
## Requirenements
25+
This module requires:
26+
- PHP version 7.4 and higher
27+
- Magento_AdobeCommerceWebhooks module
28+
29+
## Configuration
30+
Navigate to **Stores > System > Configuration > Amasty Smart Discounts > Settings** and insert the webhook URL into the
31+
**Webhook URL field**. Once you’ve verified that the connection is successful, generate the module by running
32+
`bin/magento webhooks:generate:module`.
33+
Please make sure to accurately copy the webhook URL from the Smart Discounts app settings page.
34+
If the URL is incorrect, the app may show errors when products are added to the cart.

composer.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "amasty/module-smart-discounts-hook",
3+
"description": "Smart Discounts Hook by Amasty",
4+
"require": {
5+
"php": ">=7.4",
6+
"magento/module-adobe-commerce-webhooks": "*"
7+
},
8+
"homepage": "https://amasty.com/",
9+
"type": "magento2-module",
10+
"version": "1.0.0",
11+
"license": "proprietary",
12+
"autoload": {
13+
"files": [
14+
"registration.php"
15+
],
16+
"psr-4": {
17+
"Amasty\\SmartDiscountsHook\\": ""
18+
}
19+
}
20+
}

etc/adminhtml/system.xml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* @author Amasty Team
5+
* @copyright Copyright (c) Amasty (https://www.amasty.com)
6+
* @package Smart Discounts Hook
7+
*/-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/system_file.xsd">
10+
<system>
11+
<tab id="amasty_smart_discounts" translate="label" sortOrder="999999" class="amasty-smart-discounts-tab">
12+
<label>amasty smart discounts</label>
13+
</tab>
14+
<section id="amasty_smart_discounts_hook" translate="label" type="text" showInDefault="1" showInWebsite="0" showInStore="0">
15+
<label>Settings</label>
16+
<tab>amasty_smart_discounts</tab>
17+
<resource>Amasty_SmartDiscountsHook::settings</resource>
18+
<group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
19+
<label>General</label>
20+
<frontend_model>Amasty\SmartDiscountsHook\Block\Adminhtml\System\Config\InfoNotice</frontend_model>
21+
<field id="webhook_url" translate="label" type="text" sortOrder="5" showInDefault="1" showInWebsite="0" showInStore="0">
22+
<label>Webhook URL</label>
23+
<comment><![CDATA[Please, refer to our <a href="https://amasty.com/docs/doku.php?id=magento_2:smart_discounts#getting_started" target="_blank">user guide</a> for an instruction on how to retrieve a webhook URL.]]></comment>
24+
<validate>required-entry url2</validate>
25+
</field>
26+
<field id="test_connect" sortOrder="20" showInDefault="1" showInWebsite="0" showInStore="0">
27+
<frontend_model>Amasty\SmartDiscountsHook\Block\Adminhtml\System\Config\ConnectionChecker</frontend_model>
28+
</field>
29+
</group>
30+
</section>
31+
</system>
32+
</config>

etc/module.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* @author Amasty Team
5+
* @copyright Copyright (c) Amasty (https://www.amasty.com)
6+
* @package Smart Discounts Hook
7+
*/-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
10+
<module name="Amasty_SmartDiscountsHook">
11+
<sequence>
12+
<module name="Magento_AdobeCommerceWebhooks"/>
13+
</sequence>
14+
</module>
15+
</config>

etc/webhooks.xml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<!--
2+
/**
3+
* @author Amasty Team
4+
* @copyright Copyright (c) Amasty (https://www.amasty.com)
5+
* @package Smart Discounts Hook
6+
*/-->
7+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
8+
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_AdobeCommerceWebhooks:etc/webhooks.xsd">
9+
<method name="plugin.magento.quote.model.quote.address.total.collector.collect" type="after">
10+
<hooks>
11+
<batch name="amasty_smart_discounts">
12+
<hook name="amasty_smart_discounts"
13+
url="{config:amasty_smart_discounts_hook/general/webhook_url}/api/v1/web/dx-excshell-1/hook-discount-collector"
14+
method="POST"
15+
timeout="5000"
16+
softTimeout="1000"
17+
fallbackErrorMessage="We encountered an issue while calculating your discounts. Please contact the store owner for further assistance.">
18+
<fields>
19+
<field name="total" converter="Amasty\SmartDiscountsHook\Model\Webhook\HookField\TotalConverter" />
20+
<field name="quote.customer_group_id" />
21+
<field name="quote.items_count" />
22+
<field name="quote.items_qty" />
23+
<field name="shippingAssignment.items[].item_id" />
24+
<field name="shippingAssignment.items[].product_id" />
25+
<field name="shippingAssignment.items[].sku" />
26+
<field name="shippingAssignment.items[].name" />
27+
<field name="shippingAssignment.items[].qty" />
28+
<field name="shippingAssignment.items[].price" />
29+
<field name="shippingAssignment.items[].base_price" />
30+
<field name="shippingAssignment.items[].base_discount_amount" />
31+
<field name="shippingAssignment.items[].base_discount_calculation_price" />
32+
<field name="shippingAssignment.items[].base_calculation_price" />
33+
<field name="shippingAssignment.items[].product_type" />
34+
<field name="shippingAssignment.items[].parent_item_id" />
35+
<field name="shippingAssignment.items[].product.type_id" />
36+
<field name="shippingAssignment.items[].product.sku" />
37+
<field name="shippingAssignment.items[].product.special_price" />
38+
<field name="shippingAssignment.items[].product.parent_product_id" />
39+
</fields>
40+
<rules>
41+
<rule field="subject.code" operator="equal" value="discount" />
42+
<rule field="shippingAssignment.items" operator="notEmpty" />
43+
</rules>
44+
</hook>
45+
</batch>
46+
</hooks>
47+
</method>
48+
</config>

i18n/en_US.csv

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"Please make sure to accurately copy the webhook URL from the Smart Discounts app settings page. If the URL is incorrect, the app may show errors when products are added to the cart. Once you’ve verified that the connection is successful, generate the module by running <code>bin/magento webhooks:generate:module</code>.","Please make sure to accurately copy the webhook URL from the Smart Discounts app settings page. If the URL is incorrect, the app may show errors when products are added to the cart. Once you’ve verified that the connection is successful, generate the module by running <code>bin/magento webhooks:generate:module</code>."
2+
"Test Connection","Test Connection"
3+
"Successful! Test again?","Successful! Test again?"
4+
"Connection failed! Test again?","Connection failed! Test again?"
5+
"amasty smart discounts","amasty smart discounts"
6+
Settings,Settings
7+
General,General
8+
"Webhook URL","Webhook URL"

registration.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
\Magento\Framework\Component\ComponentRegistrar::register(
4+
\Magento\Framework\Component\ComponentRegistrar::MODULE,
5+
'Amasty_SmartDiscountsHook',
6+
__DIR__
7+
);

0 commit comments

Comments
 (0)