Skip to content

Commit 5db4757

Browse files
[ECP-9289] Adding Installament options in payment Links request databuilder. (#3232)
1 parent f73ba6d commit 5db4757

File tree

3 files changed

+432
-0
lines changed

3 files changed

+432
-0
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<?php
2+
3+
namespace Adyen\Payment\Gateway\Request;
4+
5+
use Adyen\Payment\Helper\Config;
6+
use Adyen\Payment\Helper\Data as AdyenDataHelper;
7+
use Magento\Framework\Serialize\SerializerInterface;
8+
use Magento\Payment\Gateway\Data\PaymentDataObject;
9+
use Magento\Payment\Gateway\Helper\SubjectReader;
10+
use Magento\Payment\Gateway\Request\BuilderInterface;
11+
use Magento\Store\Model\StoreManagerInterface;
12+
13+
class InstallmentOptionsDataBuilder implements BuilderInterface
14+
{
15+
public function __construct(
16+
private readonly Config $configHelper,
17+
private readonly SerializerInterface $serializer,
18+
private readonly StoreManagerInterface $storeManager,
19+
private readonly AdyenDataHelper $adyenHelper
20+
) {
21+
}
22+
23+
public function build(array $buildSubject): array
24+
{
25+
/** @var PaymentDataObject $paymentDataObject */
26+
$paymentDataObject = SubjectReader::readPayment($buildSubject);
27+
$orderAmount = $paymentDataObject->getOrder()->getGrandTotalAmount();
28+
29+
$storeId = $this->storeManager->getStore()->getId();
30+
31+
if (!$this->configHelper->getAdyenCcConfigData('enable_installments', $storeId)) {
32+
return [];
33+
}
34+
35+
$raw = $this->configHelper->getAdyenCcConfigData('installments', $storeId);
36+
if (empty($raw)) {
37+
return [];
38+
}
39+
40+
$installmentsConfig = $this->serializer->unserialize($raw);
41+
42+
$installmentOptions = $this->formatInstallmentOptions($installmentsConfig, $orderAmount);
43+
44+
return empty($installmentOptions)
45+
? []
46+
: ['body' => ['installmentOptions' => $installmentOptions]];
47+
}
48+
49+
private function formatInstallmentOptions(array $config, float $orderAmount): array
50+
{
51+
$brandMap = $this->getBrandMapFromXml();
52+
$result = [];
53+
54+
foreach ($config as $brandCode => $rules) {
55+
$pm = $brandMap[$brandCode] ?? null;
56+
if (!$pm || !is_array($rules)) {
57+
continue;
58+
}
59+
60+
$thresholds = $this->parseThresholds($rules);
61+
if (!$thresholds) {
62+
continue;
63+
}
64+
65+
$values = $this->collectEligibleValues($thresholds, $orderAmount);
66+
67+
$values[] = 1;
68+
69+
$values = array_values(array_unique(array_filter($values, static fn($v) => $v > 0)));
70+
sort($values, SORT_NUMERIC);
71+
72+
if ($values) {
73+
$result[$pm] = ['values' => $values];
74+
}
75+
}
76+
77+
return $result;
78+
}
79+
80+
/**
81+
* Converts config rules into a sorted map: [minAmount(float) => values(int[])]
82+
* Accepts common shapes:
83+
* - [minAmount => [2,3]]
84+
* - [minAmount => ['values' => [2,3]]]
85+
* - [minAmount => 3]
86+
*/
87+
private function parseThresholds(array $rules): array
88+
{
89+
$thresholds = [];
90+
91+
foreach ($rules as $minAmount => $installments) {
92+
$values = $this->normalizeInstallmentValues($installments);
93+
if (!$values) {
94+
continue;
95+
}
96+
97+
$thresholds[(float)$minAmount] = $values;
98+
}
99+
100+
if (!$thresholds) {
101+
return [];
102+
}
103+
104+
ksort($thresholds, SORT_NUMERIC);
105+
return $thresholds;
106+
}
107+
108+
private function collectEligibleValues(array $thresholds, float $orderAmount): array
109+
{
110+
$values = [];
111+
112+
foreach ($thresholds as $minAmount => $tierValues) {
113+
if ($orderAmount < (float)$minAmount) {
114+
break;
115+
}
116+
// Append values from each eligible tier
117+
$values = array_merge($values, $tierValues);
118+
}
119+
120+
return $values;
121+
}
122+
123+
private function normalizeInstallmentValues(mixed $installments): array
124+
{
125+
// If admin config stores something like ['values' => [2,3]]
126+
if (is_array($installments) && isset($installments['values']) && is_array($installments['values'])) {
127+
$installments = $installments['values'];
128+
}
129+
130+
if (is_numeric($installments)) {
131+
return [(int)$installments];
132+
}
133+
134+
if (is_array($installments)) {
135+
$out = [];
136+
foreach ($installments as $v) {
137+
if (is_numeric($v)) {
138+
$out[] = (int)$v;
139+
}
140+
}
141+
return $out;
142+
}
143+
144+
return [];
145+
}
146+
147+
private function getBrandMapFromXml(): array
148+
{
149+
$altData = $this->adyenHelper->getCcTypesAltData();
150+
151+
$map = [];
152+
foreach ($altData as $altCode => $data) {
153+
if (!empty($data['code'])) {
154+
$map[$data['code']] = $altCode;
155+
}
156+
}
157+
158+
return $map;
159+
}
160+
}

0 commit comments

Comments
 (0)