Changeset View
Changeset View
Standalone View
Standalone View
src/app/Providers/PaymentProvider.php
Show First 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | protected function storePayment(array $payment, $wallet_id): Payment | ||||
$db_payment->currency = $payment['currency']; | $db_payment->currency = $payment['currency']; | ||||
$db_payment->currency_amount = $payment['currency_amount']; | $db_payment->currency_amount = $payment['currency_amount']; | ||||
$db_payment->save(); | $db_payment->save(); | ||||
return $db_payment; | return $db_payment; | ||||
} | } | ||||
/** | /** | ||||
* Retrieve an exchange rate. | |||||
* | |||||
* @param string $sourceCurrency Currency from which to convert | |||||
* @param string $targetCurrency Currency to convert to | |||||
* | |||||
* @return float Exchange rate | |||||
*/ | |||||
protected function exchangeRate(string $sourceCurrency, string $targetCurrency): float | |||||
{ | |||||
if (strcasecmp($sourceCurrency, $targetCurrency)) { | |||||
throw new \Exception("Currency conversion is not yet implemented."); | |||||
//FIXME Not yet implemented | |||||
} | |||||
return 1.0; | |||||
} | |||||
/** | |||||
* Convert a value from $sourceCurrency to $targetCurrency | * Convert a value from $sourceCurrency to $targetCurrency | ||||
* | * | ||||
* @param int $amount Amount in cents of $sourceCurrency | * @param int $amount Amount in cents of $sourceCurrency | ||||
* @param string $sourceCurrency Currency from which to convert | * @param string $sourceCurrency Currency from which to convert | ||||
* @param string $targetCurrency Currency to convert to | * @param string $targetCurrency Currency to convert to | ||||
* | * | ||||
* @return int Exchanged amount in cents of $targetCurrency | * @return int Exchanged amount in cents of $targetCurrency | ||||
*/ | */ | ||||
protected function exchange(int $amount, string $sourceCurrency, string $targetCurrency): int | protected function exchange(int $amount, string $sourceCurrency, string $targetCurrency): int | ||||
{ | { | ||||
return intval(round($amount * $this->exchangeRate($sourceCurrency, $targetCurrency))); | return intval(round($amount * \App\Utils::exchangeRate($sourceCurrency, $targetCurrency))); | ||||
} | } | ||||
/** | /** | ||||
* Deduct an amount of pecunia from the wallet. | * Deduct an amount of pecunia from the wallet. | ||||
* Creates a payment and transaction records for the refund/chargeback operation. | * Creates a payment and transaction records for the refund/chargeback operation. | ||||
* | * | ||||
* @param \App\Wallet $wallet A wallet object | * @param \App\Wallet $wallet A wallet object | ||||
* @param array $refund A refund or chargeback data (id, type, amount, description) | * @param array $refund A refund or chargeback data (id, type, amount, description) | ||||
* | * | ||||
* @return void | * @return void | ||||
*/ | */ | ||||
protected function storeRefund(Wallet $wallet, array $refund): void | protected function storeRefund(Wallet $wallet, array $refund): void | ||||
{ | { | ||||
if (empty($refund) || empty($refund['amount'])) { | if (empty($refund) || empty($refund['amount'])) { | ||||
return; | return; | ||||
} | } | ||||
// Preserve originally refunded amount | // Preserve originally refunded amount | ||||
$refund['currency_amount'] = $refund['amount']; | $refund['currency_amount'] = $refund['amount'] * -1; | ||||
// Convert amount to wallet currency | // Convert amount to wallet currency | ||||
// TODO We should possibly be using the same exchange rate as for the original payment? | // TODO We should possibly be using the same exchange rate as for the original payment? | ||||
$amount = $this->exchange($refund['amount'], $refund['currency'], $wallet->currency); | $amount = $this->exchange($refund['amount'], $refund['currency'], $wallet->currency); | ||||
machniak: This code does not look nice. We should make exchange() to be able to work with any exchange… | |||||
$wallet->balance -= $amount; | $wallet->balance -= $amount; | ||||
$wallet->save(); | $wallet->save(); | ||||
if ($refund['type'] == self::TYPE_CHARGEBACK) { | if ($refund['type'] == self::TYPE_CHARGEBACK) { | ||||
$transaction_type = Transaction::WALLET_CHARGEBACK; | $transaction_type = Transaction::WALLET_CHARGEBACK; | ||||
} else { | } else { | ||||
$transaction_type = Transaction::WALLET_REFUND; | $transaction_type = Transaction::WALLET_REFUND; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | abstract class PaymentProvider | ||||
* Return an array of whitelisted payment methods with override values. | * Return an array of whitelisted payment methods with override values. | ||||
* | * | ||||
* @param string $type The payment type for which we require a method. | * @param string $type The payment type for which we require a method. | ||||
* | * | ||||
* @return array Array of methods | * @return array Array of methods | ||||
*/ | */ | ||||
protected static function paymentMethodsWhitelist($type): array | protected static function paymentMethodsWhitelist($type): array | ||||
{ | { | ||||
$methods = []; | |||||
switch ($type) { | switch ($type) { | ||||
case self::TYPE_ONEOFF: | case self::TYPE_ONEOFF: | ||||
return [ | $methods = explode(',', \config('app.payment.methods_oneoff')); | ||||
self::METHOD_CREDITCARD => [ | break; | ||||
'id' => self::METHOD_CREDITCARD, | |||||
'icon' => self::$paymentMethodIcons[self::METHOD_CREDITCARD] | |||||
], | |||||
self::METHOD_PAYPAL => [ | |||||
'id' => self::METHOD_PAYPAL, | |||||
'icon' => self::$paymentMethodIcons[self::METHOD_PAYPAL] | |||||
], | |||||
// TODO Enable once we're ready to offer them | |||||
// self::METHOD_BANKTRANSFER => [ | |||||
// 'id' => self::METHOD_BANKTRANSFER, | |||||
// 'icon' => self::$paymentMethodIcons[self::METHOD_BANKTRANSFER] | |||||
// ] | |||||
]; | |||||
case PaymentProvider::TYPE_RECURRING: | case PaymentProvider::TYPE_RECURRING: | ||||
return [ | $methods = explode(',', \config('app.payment.methods_recurring')); | ||||
self::METHOD_CREDITCARD => [ | break; | ||||
'id' => self::METHOD_CREDITCARD, | default: | ||||
'icon' => self::$paymentMethodIcons[self::METHOD_CREDITCARD] | |||||
] | |||||
]; | |||||
} | |||||
\Log::error("Unknown payment type: " . $type); | \Log::error("Unknown payment type: " . $type); | ||||
return []; | } | ||||
$methods = array_map('strtolower', array_map('trim', $methods)); | |||||
return $methods; | |||||
} | } | ||||
/** | /** | ||||
* Return an array of whitelisted payment methods with override values. | * Return an array of whitelisted payment methods with override values. | ||||
* | * | ||||
* @param string $type The payment type for which we require a method. | * @param string $type The payment type for which we require a method. | ||||
* | * | ||||
* @return array Array of methods | * @return array Array of methods | ||||
*/ | */ | ||||
private static function applyMethodWhitelist($type, $availableMethods): array | private static function applyMethodWhitelist($type, $availableMethods): array | ||||
{ | { | ||||
$methods = []; | $methods = []; | ||||
// Use only whitelisted methods, and apply values from whitelist (overriding the backend) | // Use only whitelisted methods, and apply values from whitelist (overriding the backend) | ||||
$whitelistMethods = self::paymentMethodsWhitelist($type); | $whitelistMethods = self::paymentMethodsWhitelist($type); | ||||
foreach ($whitelistMethods as $id => $whitelistMethod) { | foreach ($whitelistMethods as $id) { | ||||
if (array_key_exists($id, $availableMethods)) { | if (array_key_exists($id, $availableMethods)) { | ||||
$methods[] = array_merge($availableMethods[$id], $whitelistMethod); | $method = $availableMethods[$id]; | ||||
$method['icon'] = self::$paymentMethodIcons[$id]; | |||||
$methods[] = $method; | |||||
} | } | ||||
} | } | ||||
return $methods; | return $methods; | ||||
} | } | ||||
/** | /** | ||||
* List supported payment methods for $wallet | * List supported payment methods for $wallet | ||||
Show All 18 Lines | public static function paymentMethods(Wallet $wallet, $type): array | ||||
if ($methods = Cache::get($cacheKey)) { | if ($methods = Cache::get($cacheKey)) { | ||||
\Log::debug("Using payment method cache" . var_export($methods, true)); | \Log::debug("Using payment method cache" . var_export($methods, true)); | ||||
return $methods; | return $methods; | ||||
} | } | ||||
$provider = PaymentProvider::factory($providerName); | $provider = PaymentProvider::factory($providerName); | ||||
$methods = self::applyMethodWhitelist($type, $provider->providerPaymentMethods($type)); | $methods = self::applyMethodWhitelist($type, $provider->providerPaymentMethods($type)); | ||||
\Log::debug("Loaded payment methods" . var_export($methods, true)); | |||||
Cache::put($cacheKey, $methods, now()->addHours(1)); | Cache::put($cacheKey, $methods, now()->addHours(1)); | ||||
return $methods; | return $methods; | ||||
} | } | ||||
/** | /** | ||||
* Returns the full URL for the wallet page, used when returning from an external payment page. | * Returns the full URL for the wallet page, used when returning from an external payment page. | ||||
* Depending on the request origin it will return a URL for the User or Reseller UI. | * Depending on the request origin it will return a URL for the User or Reseller UI. | ||||
Show All 15 Lines |
This code does not look nice. We should make exchange() to be able to work with any exchange direction. Actually exchangeRate() should.
Also, how about adding a couple of simple tests for exchange() and/or exchangeRate() itself? Also maybe remove exchangeRate() from the payment provider and use the one from Utils directly, the wrapper should not be needed.