-
Notifications
You must be signed in to change notification settings - Fork 3
IMP-424: Extended net terms and surcharge configuration #78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
dgjlindsay
wants to merge
13
commits into
main
from
doug/ABN-xxx-Magento-admin-controls-for-extended-net-terms
Closed
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
7abec50
IMP-424/feat: add extended net terms and surcharge configuration
dgjlindsay bc80034
IMP-424/feat: checkout term selection, surcharge line item, and tests
dgjlindsay bc58d83
Merge branch 'main' into doug/ABN-xxx-Magento-admin-controls-for-exte…
dgjlindsay 6e35489
IMP-424/feat: surcharge tax defaults to store VAT rate, red warning w…
dgjlindsay a00d7ad
IMP-424/test: add E2E tests for pricing fee endpoint (surcharge flow)
dgjlindsay 3e5f09d
IMP-424/fix: use merchant pricing endpoint and fix curl header accumu…
dgjlindsay c26ef8a
IMP-424/fix: replace named arguments with positional for PHP 7.4 compat
dgjlindsay 4fb24be
IMP-424/feat: dev tooling — FRP proxy, Xdebug, debug mode, README rew…
dgjlindsay 38ecba5
IMP-424/fix: Xdebug WSL2 fixes, auto-detect env, remove Docker port c…
dgjlindsay ec083be
IMP-424/feat: surcharge config grid replaces sequential per-term fields
dgjlindsay 17b4e25
IMP-424/fix: handle empty scope string in SurchargeGrid Block
dgjlindsay 4c0bc4d
IMP-424/fix: surcharge grid visibility, dynamic term rows, title
dgjlindsay 03a5d85
IMP-424/fix: surcharge grid HTML table nesting and label improvements
dgjlindsay File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ composer.lock | |
|
|
||
| # Local dev config | ||
| .env.local | ||
| .frpc.pid | ||
|
|
||
| # Python | ||
| *.venv | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,195 @@ | ||
| <?php | ||
| /** | ||
| * Copyright © Two.inc All rights reserved. | ||
| * See COPYING.txt for license details. | ||
| */ | ||
| declare(strict_types=1); | ||
|
|
||
| namespace Two\Gateway\Block\Adminhtml\System\Config\Field; | ||
|
|
||
| use Magento\Backend\Block\Template\Context; | ||
| use Magento\Config\Block\System\Config\Form\Field; | ||
| use Magento\Framework\App\Config\ScopeConfigInterface; | ||
| use Magento\Framework\Data\Form\Element\AbstractElement; | ||
| use Two\Gateway\Api\Config\RepositoryInterface as ConfigRepository; | ||
|
|
||
| /** | ||
| * Renders a grid of surcharge inputs (fixed, percentage, limit) per payment term. | ||
| * | ||
| * Replaces the individual per-term surcharge fields with a compact table. | ||
| * Reads available terms from the multiselect + custom duration config, | ||
| * and the limits from RepositoryInterface constants (fork-friendly). | ||
| */ | ||
| class SurchargeGrid extends Field | ||
| { | ||
| /** @var string */ | ||
| protected $_template = 'Two_Gateway::system/config/field/surcharge-grid.phtml'; | ||
|
|
||
| /** @var ScopeConfigInterface */ | ||
| private $scopeConfig; | ||
|
|
||
| /** @var string */ | ||
| private $scope = 'default'; | ||
|
|
||
| /** @var int */ | ||
| private $scopeId = 0; | ||
|
|
||
| public function __construct( | ||
| Context $context, | ||
| ScopeConfigInterface $scopeConfig, | ||
| array $data = [] | ||
| ) { | ||
| parent::__construct($context, $data); | ||
| $this->scopeConfig = $scopeConfig; | ||
| } | ||
|
|
||
| /** | ||
| * @inheritDoc | ||
| */ | ||
| public function render(AbstractElement $element): string | ||
| { | ||
| $this->resolveScope($element); | ||
| $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue(); | ||
| return parent::render($element); | ||
| } | ||
|
|
||
| /** | ||
| * @inheritDoc | ||
| */ | ||
| protected function _getElementHtml(AbstractElement $element): string | ||
| { | ||
| return $this->_toHtml(); | ||
| } | ||
|
|
||
| /** | ||
| * Get the sorted list of active payment terms (standard + custom). | ||
| */ | ||
| public function getActiveTerms(): array | ||
| { | ||
| $selected = $this->getConfigValue(ConfigRepository::XML_PATH_PAYMENT_TERMS); | ||
| $terms = array_filter(array_map('intval', explode(',', (string)$selected))); | ||
|
|
||
| $custom = (int)$this->getConfigValue(ConfigRepository::XML_PATH_PAYMENT_TERMS_DURATION_DAYS); | ||
| if ($custom > 0) { | ||
| $terms[] = $custom; | ||
| } | ||
|
|
||
| $terms = array_unique($terms); | ||
| sort($terms); | ||
| return array_values($terms); | ||
| } | ||
|
|
||
| /** | ||
| * Get the saved surcharge value for a given term and field. | ||
| */ | ||
| public function getSavedValue(int $days, string $field): string | ||
| { | ||
| $path = sprintf('payment/two_payment/surcharge_%d_%s', $days, $field); | ||
| $value = $this->getConfigValue($path); | ||
| return $value !== null ? (string)$value : ''; | ||
| } | ||
|
|
||
| /** | ||
| * Get the default payment term (for differential mode highlighting). | ||
| */ | ||
| public function getDefaultTerm(): int | ||
| { | ||
| return (int)$this->getConfigValue(ConfigRepository::XML_PATH_DEFAULT_PAYMENT_TERM); | ||
| } | ||
|
|
||
| /** | ||
| * Get the surcharge type (none, percentage, fixed, fixed_and_percentage). | ||
| */ | ||
| public function getSurchargeType(): string | ||
| { | ||
| return (string)$this->getConfigValue(ConfigRepository::XML_PATH_SURCHARGE_TYPE); | ||
| } | ||
|
|
||
| public function getMaxFixed(): int | ||
| { | ||
| return ConfigRepository::SURCHARGE_FIXED_MAX; | ||
| } | ||
|
|
||
| public function getMaxPercentage(): int | ||
| { | ||
| return ConfigRepository::SURCHARGE_PERCENTAGE_MAX; | ||
| } | ||
|
|
||
| /** | ||
| * Get the HTML field name for a surcharge input. | ||
| * | ||
| * Nests under the surcharge_grid field's value so the backend model receives it: | ||
| * groups[payment_terms][fields][surcharge_grid][value][{days}][{field}] | ||
| */ | ||
| public function getFieldName(int $days, string $field): string | ||
| { | ||
| return sprintf( | ||
| 'groups[payment_terms][fields][surcharge_grid][value][%d][%s]', | ||
| $days, | ||
| $field | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Get the "inherit" checkbox name for scope override. | ||
| */ | ||
| public function getInheritName(int $days, string $field): string | ||
| { | ||
| return sprintf( | ||
| 'groups[payment_terms][fields][surcharge_grid][inherit][%d][%s]', | ||
| $days, | ||
| $field | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Check if a field is using the inherited (default/website) value at current scope. | ||
| */ | ||
| public function isInherited(int $days, string $field): bool | ||
| { | ||
| if ($this->scope === 'default') { | ||
| return false; | ||
| } | ||
| $path = sprintf('payment/two_payment/surcharge_%d_%s', $days, $field); | ||
| // Check if a value exists at this specific scope | ||
| $value = $this->scopeConfig->getValue($path, $this->scope, $this->scopeId); | ||
| $defaultValue = $this->scopeConfig->getValue($path); | ||
| // If the scope-specific value equals the default, it's likely inherited | ||
| // (Magento doesn't expose "is this overridden" directly for system config) | ||
| return $value === $defaultValue; | ||
| } | ||
|
|
||
| /** | ||
| * Whether we're at a non-default scope (website or store). | ||
| */ | ||
| public function isNonDefaultScope(): bool | ||
| { | ||
| return $this->scope !== 'default'; | ||
| } | ||
|
|
||
| /** | ||
| * Available term constants (for JS to know which terms are standard). | ||
| */ | ||
| public function getAvailablePaymentTerms(): array | ||
| { | ||
| return ConfigRepository::AVAILABLE_PAYMENT_TERMS; | ||
| } | ||
|
|
||
| private function resolveScope(AbstractElement $element): void | ||
| { | ||
| $form = $element->getForm(); | ||
| if ($form) { | ||
| $scope = (string)$form->getScope(); | ||
| $this->scope = ($scope !== '') ? $scope : 'default'; | ||
| $this->scopeId = (int)$form->getScopeId(); | ||
| } | ||
| } | ||
|
|
||
| private function getConfigValue(string $path) | ||
| { | ||
| if ($this->scope !== 'default') { | ||
| return $this->scopeConfig->getValue($path, $this->scope, $this->scopeId); | ||
| } | ||
| return $this->scopeConfig->getValue($path); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| <?php | ||
| /** | ||
| * Copyright © Two.inc All rights reserved. | ||
| * See COPYING.txt for license details. | ||
| */ | ||
| declare(strict_types=1); | ||
|
|
||
| namespace Two\Gateway\Block\Adminhtml\System\Config\Field; | ||
|
|
||
| use Magento\Backend\Block\Template\Context; | ||
| use Magento\Config\Block\System\Config\Form\Field; | ||
| use Magento\Framework\Data\Form\Element\AbstractElement; | ||
| use Two\Gateway\Api\Config\RepositoryInterface as ConfigRepository; | ||
|
|
||
| /** | ||
| * Surcharge Tax Rate field with dynamic comment. | ||
| * | ||
| * Shows the store's default tax rate when available, or a red warning | ||
| * when no tax rules are configured. | ||
| */ | ||
| class SurchargeTaxRate extends Field | ||
| { | ||
| /** | ||
| * @var ConfigRepository | ||
| */ | ||
| private $configRepository; | ||
|
|
||
| public function __construct( | ||
| Context $context, | ||
| ConfigRepository $configRepository, | ||
| array $data = [] | ||
| ) { | ||
| parent::__construct($context, $data); | ||
| $this->configRepository = $configRepository; | ||
| } | ||
|
|
||
| /** | ||
| * @inheritDoc | ||
| */ | ||
| protected function _getElementHtml(AbstractElement $element): string | ||
| { | ||
| $defaultRate = $this->configRepository->getDefaultTaxRate(); | ||
|
|
||
| if ($defaultRate > 0) { | ||
| $element->setComment( | ||
| (string)__( | ||
| 'Leave empty to use your store\'s default tax rate (%1%%). Enter 0 for tax-exempt.', | ||
| number_format($defaultRate, 1) | ||
| ) | ||
| ); | ||
| } else { | ||
| $element->setComment( | ||
| '<span style="color: #e22626; font-weight: bold;">' | ||
| . (string)__('Warning: No tax rules are configured for your store. ' | ||
| . 'Configure tax rules in Stores → Tax Rules to ensure correct surcharge tax calculation. ' | ||
| . 'Enter a rate manually, or enter 0 for tax-exempt.') | ||
| . '</span>' | ||
| ); | ||
| } | ||
|
|
||
| return parent::_getElementHtml($element); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Defining data arrays like
AVAILABLE_PAYMENT_TERMS,SURCHARGE_FIXED_MAX, andSURCHARGE_PERCENTAGE_MAXdirectly as constants in an interface can make the interface less abstract. While the comment "override in fork" suggests this is the intended mechanism for customization, a more flexible approach might be to define methods that return these values, allowing implementing classes to provide their own logic or data sources. This would keep the interface purely behavioral.