crater-invoice/crater

Impl. adding a custom Currency Exchange Provider

duraki opened this issue · 3 comments

duraki commented

It seems kinda shitty practice to disallow admins to add new Currency Exchange providers (besides the one that are sponsored and listed in Settings by default).

Looking at the API -- nothing. Only API routes available is to edit/config a particular predefined Currency Exchange. Furthermore, looking at the API, it all seems hardcoded, notably:

The worst part is hiding the API route for creating an exchange rate provider! You think we aren't looking at the source-code?

    public function create(User $user)
    {
        ...
        if (BouncerFacade::can('create-exchange-rate-provider', ExchangeRateProvider::class)) {
            return true;
        }

Guess what, you will never find create-exchange-rate-provider in Currencies API. Besides;

  • [Exch. Rate Drivers] - example.com/api/v1/config?key=exchange_rate_drivers are pulled from config API route.
  • [w. Supported Currencies] - example.com/api/v1/supported-currencies?driver=open_exchange_rate&key=t&type=FREE, you see?

Anyway, please add this feature, or at least do some writeup on how to implement it, properly, that is.

Kindly.

I don’t like how you make it sound as if we are trying to scam you into buying exchange-rate services or something. We just collected some free and paid + easy to integrate APIs and patched them here to allow automatic conversion. We have no referral code or any affiliation with the given services.

You are free to modify this software according to your requirements.

duraki commented

I'm just being real, and I think many other issues on this repo will reference to similar situations. There are totally free alternatives, such is fawazahmed0/currency-api repository which updates currency daily and does not rate-limit. CDN is good and uptime is on point. Eh .. 😅

Anyway, Y'all welcome.

// app/Models/ExchangeRateProvider.php

  public static function checkExchangeRateProviderStatus($request)
  {
      switch ($request['driver']) {
      case 'cbbh':
        // $url = "https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/usd.json"    

                    /** or **/                   

        // $url = "https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/".$request->currencies[0]."/".$request->currencies[1].".json";

  $response = Http::get($url)->json();

  if (array_key_exists('usd', $response)) {
    if ($response["usd"] == false) { /* empty ary */
        return respondJson($response["error"]["message"], "Error getting exch_rate - via cbbh driver");
    }
  }

  return response()->json([
      'exchangeRate' => array_values($response['usd']),
  ], 200);

  break;

...

Additionally, add exchange rate driver in config:

// config/Crater.php

  /*
  * List of exchange rate drivers
  */
  'exchange_rate_drivers' => [
      ...
      ['key' => 'settings.exchange_rate.cbbh', 'value' => 'cbbh'],
  ],
// app/Traits/ExchangeRateProvidersTrait.php

  public function getExchangeRate($filter, $baseCurrencyCode, $currencyCode)
  {
    switch ($filter['driver']) {
      case 'cbbh':
        $url = "https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/"; //usd.json";
        $url = $url . $currencyCode . "/" . $baseCurrencyCode . ".json";
        $response = Http::get($url)->json();

        if (str_contains($response["body"], "Package size exceeded")) {
            return respondJson($response["error"]["message"], "error in cbbh driver");                    }

        return response()->json([
            'exchangeRate' => array_values([$response[$baseCurrencyCode]]),
        ], 200);

        break;
    // ...
  }

  public function getUrl($request)
  {
    switch ($request->driver) {
      case 'cbbh':
        $url = "https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/usd.json";
        return Http::get($url)->json();

        break;
    // ...
  }

  public function getSupportedCurrencies($request)
  {
    // ...
    switch ($request->driver) {
      case 'cbbh':
       $url = "https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies.json";
       $response = Http::get($url)->json();
       $checkKey = $this->getUrl($request);

       if ($response == null || $checkKey == null) {
            return respondJson($error_message, $server_message);
       }

       if ($checkKey['error']['status'] == 404) {
            return respondJson($error, $message);
       }

      return response()->json(['supportedCurrencies' => array_keys($response)]);
      break;
    // ...
  }
// resources/scripts/admin/components/modal-components/ExchangeRateProviderModal.vue

const driverSite = computed(() => {
  switch (exchangeRateStore.currentExchangeRate.driver) {
    case 'cbbh':
      return 'https://github.com/fawazahmed0/currency-api'
  // ...
}

Finally, add prefered Locale:

// resources/scripts/locales/en.json

"open_exchange_rate": "Open Exchange Rate",
"cbbh": "Open-source Exchange Rate", // << - driver

Go back to ExchangeRateProviderModal.vue and add:

// ...

const isCbbhOSSProvider = computer(() => {
  return exchangeRateStore.currentExchangeRate.driver == 'cbbh'
})

/**
const isCurrencyConverter = computer(() => { ...
  // ...
}
**/
duraki commented

Yeha, don't forget to:

$ docker exec -it crater_app_1 bash
crater-user@f2c5348052eb:/var/www$ composer install --no-interaction --prefer-dist --optimize-autoloader