brokeyourbike/yogupay-api-client-php

View on GitHub
src/Client.php

Summary

Maintainability
A
1 hr
Test Coverage
A
100%
<?php

// Copyright (C) 2024 Ivan Stasiuk <ivan@stasi.uk>.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

namespace BrokeYourBike\YoguPay;

use Psr\SimpleCache\CacheInterface;
use GuzzleHttp\ClientInterface;
use BrokeYourBike\YoguPay\Responses\TransactionResponse;
use BrokeYourBike\YoguPay\Responses\TokenResponse;
use BrokeYourBike\YoguPay\Responses\PayoutResponse;
use BrokeYourBike\YoguPay\Responses\EstimateResponse;
use BrokeYourBike\YoguPay\Interfaces\TransactionInterface;
use BrokeYourBike\YoguPay\Interfaces\ConfigInterface;
use BrokeYourBike\YoguPay\Enums\CollectionNetworkEnum;
use BrokeYourBike\YoguPay\Enums\ChannelEnum;
use BrokeYourBike\ResolveUri\ResolveUriTrait;
use BrokeYourBike\HttpEnums\HttpMethodEnum;
use BrokeYourBike\HttpClient\HttpClientTrait;
use BrokeYourBike\HttpClient\HttpClientInterface;
use BrokeYourBike\HasSourceModel\HasSourceModelTrait;

/**
 * @author Ivan Stasiuk <ivan@stasi.uk>
 */
class Client implements HttpClientInterface
{
    use HttpClientTrait;
    use ResolveUriTrait;
    use HasSourceModelTrait;

    private ConfigInterface $config;
    private CacheInterface $cache;

    public function __construct(ConfigInterface $config, ClientInterface $httpClient, CacheInterface $cache)
    {
        $this->config = $config;
        $this->httpClient = $httpClient;
        $this->cache = $cache;
    }

    public function getConfig(): ConfigInterface
    {
        return $this->config;
    }

    public function getCache(): CacheInterface
    {
        return $this->cache;
    }

    public function authTokenCacheKey(): string
    {
        return get_class($this) . ':authToken:';
    }

    public function getAuthToken(): string
    {
        if ($this->cache->has($this->authTokenCacheKey())) {
            $cachedToken = $this->cache->get($this->authTokenCacheKey());
            if (is_string($cachedToken)) {
                return $cachedToken;
            }
        }

        $response = $this->fetchAuthTokenRaw();
        $this->cache->set($this->authTokenCacheKey(), $response->token, 300);
        return (string) $response->token;
    }

    public function fetchAuthTokenRaw(): TokenResponse
    {
        $options = [
            \GuzzleHttp\RequestOptions::HEADERS => [
                'Accept' => 'application/json',
            ],
            \GuzzleHttp\RequestOptions::JSON => [
                'username' => $this->config->getUsername(),
                'password' => $this->config->getPassword(),
            ],
        ];

        $response = $this->httpClient->request(
            HttpMethodEnum::POST->value,
            (string) $this->resolveUriFor(rtrim($this->config->getUrl(), '/'), '/auth/login'),
            $options
        );

        return new TokenResponse($response);
    }

    public function estimate(string $from, string $to, float $amount): EstimateResponse
    {
        $options = [
            \GuzzleHttp\RequestOptions::HEADERS => [
                'Accept' => 'application/json',
                'token' => $this->getAuthToken(),
            ],
            \GuzzleHttp\RequestOptions::JSON => [
                'currency_pair' => "{$from}_{$to}",
                'amount' => $amount,
            ],
        ];

        $response = $this->httpClient->request(
            HttpMethodEnum::POST->value,
            (string) $this->resolveUriFor(rtrim($this->config->getUrl(), '/'), '/api/get-estimate'),
            $options
        );

        return new EstimateResponse($response);
    }

    public function payout(TransactionInterface $transaction): PayoutResponse
    {
        $network = match ($transaction->getChannel()) {
            ChannelEnum::MOBILE_MONEY => CollectionNetworkEnum::MPESA_DIRECT,
            ChannelEnum::BANK_TRANSFER => match ($transaction->getCurrency()) {
                'NGN' => CollectionNetworkEnum::TRANSFER_NG,
                default => CollectionNetworkEnum::BANK_TRANSFER,
            },
        };

        $options = [
            \GuzzleHttp\RequestOptions::HEADERS => [
                'Accept' => 'application/json',
                'token' => $this->getAuthToken(),
            ],
            \GuzzleHttp\RequestOptions::JSON => [
                'channel' => $transaction->getChannel()->value,
                'collection_network' => $network->value,
                'source_currency' => $transaction->getCurrency(),
                'source_amount' => $transaction->getAmount(),
                'country_code' => $transaction->getRecipientCountry(),
                'recipient_name' => $transaction->getRecipientName(),
                'bank_code' => $transaction->getRecipientBankCode(),
                'bank_account_number' => $transaction->getRecipientAccountNumber(),
                'msisdn' => $transaction->getRecipientPhone(),
                'recipient_email' => $transaction->getRecipientEmail(),
                'purpose_of_funds' => $transaction->getPurpose(),
                'payment_reference' => $transaction->getReference(),
            ],
        ];

        $response = $this->httpClient->request(
            HttpMethodEnum::POST->value,
            (string) $this->resolveUriFor(rtrim($this->config->getUrl(), '/'), '/auth/payout'),
            $options
        );

        return new PayoutResponse($response);
    }

    public function viewTransaction(string $transactionCode): TransactionResponse
    {
        $options = [
            \GuzzleHttp\RequestOptions::HEADERS => [
                'Accept' => 'application/json',
                'token' => $this->getAuthToken(),
            ],
            \GuzzleHttp\RequestOptions::JSON => [
                'transaction_code' => $transactionCode,
            ],
        ];

        $response = $this->httpClient->request(
            HttpMethodEnum::POST->value,
            (string) $this->resolveUriFor(rtrim($this->config->getUrl(), '/'), '/auth/view-transaction'),
            $options
        );

        return new TransactionResponse($response);
    }
}