| 1 |
<?php |
| 2 |
|
| 3 |
namespace Payplug\PayplugWoocommerce\Gateway\Oney; |
| 4 |
|
| 5 |
/** |
| 6 |
* Normalizes the `configuration.oney` block of GET /account plus the plugin's admin Oney |
| 7 |
* settings into config the official Oney widget (loader.min.js / oneyMerchantApp.*) expects. |
| 8 |
* |
| 9 |
* Fee-mode combinations are NOT filtered by a per-x3/x4 admin checkbox - there isn't one. |
| 10 |
* The single admin toggle (`payment_methods.configuration.oney.with_fees`) picks between the |
| 11 |
* "with_fees" pair (x3_with_fees + x4_with_fees) and the "without_fees" pair, matching the |
| 12 |
* PDP/cart pop-in ("3x by default, switch to 4x"). Checkout resolves a single code per |
| 13 |
* gateway id instead, since each of the 4 WooCommerce Oney gateways already encodes its own |
| 14 |
* fee mode in its id. |
| 15 |
*/ |
| 16 |
class OneyAccountMapper |
| 17 |
{ |
| 18 |
private const GATEWAY_TO_BUSINESS_CODE_KEY = [ |
| 19 |
'oney_x3_with_fees' => 'x3_with_fees', |
| 20 |
'oney_x3_without_fees' => 'x3_without_fees', |
| 21 |
'oney_x4_with_fees' => 'x4_with_fees', |
| 22 |
'oney_x4_without_fees' => 'x4_without_fees', |
| 23 |
]; |
| 24 |
|
| 25 |
private bool $enabled = false; |
| 26 |
|
| 27 |
private ?string $merchant_guid = null; |
| 28 |
|
| 29 |
/** @var array<string, string> */ |
| 30 |
private array $business_codes = []; |
| 31 |
|
| 32 |
/** @var string[] */ |
| 33 |
private array $allowed_countries = ['ALL']; |
| 34 |
|
| 35 |
private int $min_amount = 0; |
| 36 |
|
| 37 |
private int $max_amount = 0; |
| 38 |
|
| 39 |
private bool $show_legal_notices = true; |
| 40 |
|
| 41 |
/** |
| 42 |
* @param array $account The raw GET /account response (or the relevant subset - |
| 43 |
* only `configuration.oney` is read). |
| 44 |
* @param array $oney_settings `payment_methods.configuration.oney` from the plugin's own |
| 45 |
* options (active, with_fees, custom_amounts, ...). |
| 46 |
* @param string $country Merchant/shop country (as resolved elsewhere in this plugin |
| 47 |
* by `PayplugWoocommerceHelper::getISOCountryCode()`), used to |
| 48 |
* pick the right `countries_metadata` entry - the live account |
| 49 |
* API nests `merchant_guid`/`oney_business_codes` per country |
| 50 |
* (a merchant can have distinct Oney registrations across its |
| 51 |
* `allowed_countries`), not flat at the top level as an earlier |
| 52 |
* revision of this class assumed. |
| 53 |
*/ |
| 54 |
public static function map(array $account, array $oney_settings, string $country = ''): self |
| 55 |
{ |
| 56 |
$mapper = new self(); |
| 57 |
|
| 58 |
$oney = $account['configuration']['oney'] ?? null; |
| 59 |
if (empty($oney) || empty($oney_settings['active'])) { |
| 60 |
return $mapper; |
| 61 |
} |
| 62 |
|
| 63 |
$mapper->enabled = true; |
| 64 |
|
| 65 |
$country_metadata = $oney['countries_metadata'][$country] ?? []; |
| 66 |
$mapper->merchant_guid = $country_metadata['merchant_guid'] ?? $oney['merchant_guid'] ?? null; |
| 67 |
$mapper->business_codes = $country_metadata['oney_business_codes'] ?? $oney['oney_business_codes'] ?? []; |
| 68 |
$mapper->allowed_countries = !empty($oney['allowed_countries']) ? $oney['allowed_countries'] : ['ALL']; |
| 69 |
$mapper->show_legal_notices = array_key_exists('show_legal_notices', $oney) |
| 70 |
? (bool) $oney['show_legal_notices'] |
| 71 |
: true; |
| 72 |
|
| 73 |
[$mapper->min_amount, $mapper->max_amount] = self::effective_bounds($oney, $oney_settings); |
| 74 |
|
| 75 |
return $mapper; |
| 76 |
} |
| 77 |
|
| 78 |
/** |
| 79 |
* Merges Oney's own min/max (account) with the merchant's optional local override |
| 80 |
* (custom_amounts), the effective range never widening beyond what Oney allows. |
| 81 |
* |
| 82 |
* Public so checkout-time eligibility (PayplugGatewayOney3x::do_check_oney_is_available()) |
| 83 |
* can share this exact computation instead of re-deriving its own min/max from |
| 84 |
* custom_amounts alone - see PRE-3457 review discussion. |
| 85 |
* |
| 86 |
* @param array $oney `account.configuration.oney` (or the relevant subset - |
| 87 |
* `min_amounts`/`max_amounts` are read) |
| 88 |
* @param array $oney_settings `payment_methods.configuration.oney` from the plugin's own |
| 89 |
* options (`custom_amounts` is read) |
| 90 |
* |
| 91 |
* @return array{0: int, 1: int} [min_cents, max_cents] |
| 92 |
*/ |
| 93 |
public static function effective_bounds(array $oney, array $oney_settings): array |
| 94 |
{ |
| 95 |
$account_min = (int) ($oney['min_amounts']['EUR'] ?? 0); |
| 96 |
$account_max = (int) ($oney['max_amounts']['EUR'] ?? 0); |
| 97 |
|
| 98 |
$custom = json_decode($oney_settings['custom_amounts'] ?? '{}', true); |
| 99 |
$custom = is_array($custom) ? $custom : []; |
| 100 |
|
| 101 |
$min = isset($custom['min']) ? max($account_min, (int) $custom['min']) : $account_min; |
| 102 |
$max = isset($custom['max']) ? min($account_max, (int) $custom['max']) : $account_max; |
| 103 |
|
| 104 |
return [$min, $max]; |
| 105 |
} |
| 106 |
|
| 107 |
public function is_enabled(): bool |
| 108 |
{ |
| 109 |
return $this->enabled; |
| 110 |
} |
| 111 |
|
| 112 |
public function get_merchant_guid(): ?string |
| 113 |
{ |
| 114 |
return $this->merchant_guid; |
| 115 |
} |
| 116 |
|
| 117 |
/** |
| 118 |
* @return string[] |
| 119 |
*/ |
| 120 |
public function get_allowed_countries(): array |
| 121 |
{ |
| 122 |
return $this->allowed_countries; |
| 123 |
} |
| 124 |
|
| 125 |
public function get_min_amount(): int |
| 126 |
{ |
| 127 |
return $this->min_amount; |
| 128 |
} |
| 129 |
|
| 130 |
public function get_max_amount(): int |
| 131 |
{ |
| 132 |
return $this->max_amount; |
| 133 |
} |
| 134 |
|
| 135 |
public function get_show_legal_notices(): bool |
| 136 |
{ |
| 137 |
return $this->show_legal_notices; |
| 138 |
} |
| 139 |
|
| 140 |
/** |
| 141 |
* @param string $fee_mode 'with_fees' or 'without_fees' |
| 142 |
* |
| 143 |
* @return string[] |
| 144 |
*/ |
| 145 |
public function business_transaction_codes(string $fee_mode): array |
| 146 |
{ |
| 147 |
$keys = 'without_fees' === $fee_mode |
| 148 |
? ['x3_without_fees', 'x4_without_fees'] |
| 149 |
: ['x3_with_fees', 'x4_with_fees']; |
| 150 |
|
| 151 |
$codes = []; |
| 152 |
foreach ($keys as $key) { |
| 153 |
if (!empty($this->business_codes[$key])) { |
| 154 |
$codes[] = $this->business_codes[$key]; |
| 155 |
} |
| 156 |
} |
| 157 |
|
| 158 |
return $codes; |
| 159 |
} |
| 160 |
|
| 161 |
public function business_transaction_code_for_gateway(string $gateway_id): ?string |
| 162 |
{ |
| 163 |
$key = self::GATEWAY_TO_BUSINESS_CODE_KEY[$gateway_id] ?? null; |
| 164 |
|
| 165 |
return $key ? ($this->business_codes[$key] ?? null) : null; |
| 166 |
} |
| 167 |
|
| 168 |
public function is_eligible(string $country, int $amount_in_cents): bool |
| 169 |
{ |
| 170 |
if (!$this->enabled) { |
| 171 |
return false; |
| 172 |
} |
| 173 |
|
| 174 |
if (!in_array('ALL', $this->allowed_countries, true) && !in_array($country, $this->allowed_countries, true)) { |
| 175 |
return false; |
| 176 |
} |
| 177 |
|
| 178 |
return $amount_in_cents >= $this->min_amount && $amount_in_cents <= $this->max_amount; |
| 179 |
} |
| 180 |
} |
| 181 |
|