Skip to content

Commit

Permalink
Merge pull request #126 from fleetbase/dev-v1.5.21
Browse files Browse the repository at this point in the history
v1.5.21 - improvements to resolver and money cast utility
  • Loading branch information
roncodes authored Dec 24, 2024
2 parents 8a99eda + d4dafc0 commit da6418d
Show file tree
Hide file tree
Showing 10 changed files with 477 additions and 15 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fleetbase/core-api",
"version": "1.5.20",
"version": "1.5.21",
"description": "Core Framework and Resources for Fleetbase API",
"keywords": [
"fleetbase",
Expand Down
25 changes: 21 additions & 4 deletions src/Casts/Money.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,25 @@ public function set($model, $key, $value, $attributes)
if ($value === null) {
return 0;
}
$value = $this->removeCurrencySymbols($value);
$value = $this->removeSpecialCharactersExceptDotAndComma($value);
$value = static::removeCurrencySymbols($value);
$value = static::removeSpecialCharactersExceptDotAndComma($value);
if (is_float($value) || Str::contains($value, '.')) {
$value = number_format((float) $value, 2, '.', '');
}

return Utils::numbersOnly($value);
}

/**
* Apply the case.
*/
public static function apply($value): int
{
if ($value === null) {
return 0;
}
$value = static::removeCurrencySymbols($value);
$value = static::removeSpecialCharactersExceptDotAndComma($value);
if (is_float($value) || Str::contains($value, '.')) {
$value = number_format((float) $value, 2, '.', '');
}
Expand All @@ -58,7 +75,7 @@ public function set($model, $key, $value, $attributes)
* $cleanPrice = removeCurrencySymbols($price);
* // $cleanPrice will be "123.45"
*/
private function removeCurrencySymbols($string)
public static function removeCurrencySymbols($string)
{
$currencySymbols = '/[\$€£¥₹¢฿₽₪₩₮]/';
$cleanString = preg_replace($currencySymbols, '', $string);
Expand Down Expand Up @@ -87,7 +104,7 @@ private function removeCurrencySymbols($string)
* $cleanPrice = removeSpecialCharactersExceptDotAndComma($price);
* // $cleanPrice will be "1,234.56"
*/
public function removeSpecialCharactersExceptDotAndComma($string)
public static function removeSpecialCharactersExceptDotAndComma($string)
{
$cleanString = preg_replace('/[^\d.,]/', '', $string);

Expand Down
41 changes: 40 additions & 1 deletion src/Events/ResourceLifecycleEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class ResourceLifecycleEvent implements ShouldBroadcastNow
Expand Down Expand Up @@ -93,6 +94,33 @@ public function __construct(Model $model, $eventName = null, $version = 1)
$this->data = $this->getEventData();
}

private function getInternalEventData(): array
{
return [
'modelUuid' => $this->modelUuid,
'modelClassNamespace' => $this->modelClassNamespace,
'modelClassName' => $this->modelClassName,
'modelHumanName' => $this->modelHumanName,
'modelRecordName' => $this->modelRecordName,
'modelName' => $this->modelName,
'namespace' => $this->namespace,
'userSession' => $this->userSession,
'companySession' => $this->companySession,
'eventName' => $this->eventName,
'sentAt' => $this->sentAt,
'version' => $this->version,
'requestMethod' => $this->requestMethod,
'eventId' => $this->eventId,
'apiVersion' => $this->apiVersion,
'apiCredential' => $this->apiCredential,
'apiSecret' => $this->apiSecret,
'apiKey' => $this->apiKey,
'apiEnvironment' => $this->apiEnvironment,
'isSandbox' => $this->isSandbox,
'data' => $this->data,
];
}

/**
* The event's broadcast name.
*
Expand Down Expand Up @@ -121,6 +149,11 @@ public function broadcastWith()
public function broadcastOn()
{
$model = $this->getModelRecord();
if (!$model) {
Log::error('Unable to resolve a model to broadcast for', $this->getInternalEventData());

return [];
}
$channels = $this->initializeChannels($model);
$this->addModelSpecificChannels($model, $channels);
$this->addCompanySpecificChannels($model, $channels);
Expand Down Expand Up @@ -307,6 +340,12 @@ public function getNamespaceFromModel(Model $model): string
public function getEventData()
{
$model = $this->getModelRecord();
if (!$model) {
Log::error('Unable to resolve a model to get event data for', $this->getInternalEventData());

return [];
}

$resource = $this->getModelResource($model, $this->namespace, $this->version);
$resourceData = [];
$keepRelations = ['chat_message'];
Expand Down Expand Up @@ -343,7 +382,7 @@ public function getEventData()
*
* @throws \Exception if the model class specified by $namespace does not exist or cannot be instantiated
*/
public function getModelRecord(): EloquentModel
public function getModelRecord(): ?EloquentModel
{
$namespace = $this->modelClassNamespace;

Expand Down
2 changes: 1 addition & 1 deletion src/Http/Controllers/Internal/v1/LookupController.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ function ($country) {
public function country($code, Request $request)
{
$simple = $request->boolean('simple', true);
$country = Country::search($code)->first();
$country = Country::getByIso2($code);

if ($simple && $country) {
$country = $country->simple();
Expand Down
2 changes: 2 additions & 0 deletions src/Http/Resources/Organization.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public function toArray($request)
'type' => $this->when(Http::isInternalRequest(), $this->type),
'users_count' => $this->when(Http::isInternalRequest(), $this->companyUsers()->count()),
'timezone' => $this->timezone,
'country' => $this->country,
'currency' => $this->currency,
'logo_url' => $this->logo_url,
'backdrop_url' => $this->backdrop_url,
'branding' => Setting::getBranding(),
Expand Down
20 changes: 18 additions & 2 deletions src/Support/Find.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ class Find
public static function httpResourceForModel(Model $model, ?string $namespace = null, ?int $version = 1): ?string
{
$resourceNamespace = null;
$defaultResourceNS = '\\Fleetbase\\Http\\Resources\\';
$defaultResourceNS = $coreResourceNS = '\\Fleetbase\\Http\\Resources\\';
$packageName = static::getModelPackage($model);
if ($packageName) {
$defaultResourceNS = '\\Fleetbase\\' . $packageName . '\\Http\\Resources\\';
}

$baseNamespace = $namespace ? $namespace . '\\Http\\Resources\\' : $defaultResourceNS;
$modelName = Utils::classBasename($model);

Expand Down Expand Up @@ -55,7 +60,7 @@ public static function httpResourceForModel(Model $model, ?string $namespace = n
throw new \Exception('Missing resource');
}
} catch (\Error|\Exception $e) {
$resourceNamespace = $defaultResourceNS . 'FleetbaseResource';
$resourceNamespace = $coreResourceNS . 'FleetbaseResource';
}

return $resourceNamespace;
Expand Down Expand Up @@ -177,4 +182,15 @@ public static function httpFilterForModel(Model $model, ?string $namespace = nul

return null;
}

public static function getModelPackage(Model $model): ?string
{
$fullClassName = get_class($model);
$fullClassNameSegments = explode('\\', $fullClassName);
if ($fullClassNameSegments[1] !== 'Models') {
return $fullClassNameSegments[1];
}

return null;
}
}
82 changes: 77 additions & 5 deletions src/Support/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Fleetbase\Models\Company;
use Fleetbase\Models\File;
use Fleetbase\Models\Model;
use Fleetbase\Types\Currency;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
Expand Down Expand Up @@ -636,16 +637,22 @@ public static function smartHumanize(?string $string): string
/**
* Returns the uuid for a table with where hook.
*
* @param string|array $table
* @param array|callable $where
*/
public static function getUuid($table, $where = []): ?string
public static function getUuid(string|array $table, array $where = [], array $options = []): string|array|null
{
if (is_array($table)) {
foreach ($table as $t) {
$uuid = static::getUuid($t, $where);

if ($uuid) {
if (isset($options['full']) && $options['full'] === true) {
return [
'uuid' => $uuid,
'table' => $t,
];
}

return $uuid;
}
}
Expand Down Expand Up @@ -1037,10 +1044,10 @@ public static function isNotScalar($target)
*
* @param string countryName
*/
public static function getCountryCodeByName(?string $countryName): ?string
public static function getCountryCodeByName(?string $countryName, ?string $defaultValue = null): ?string
{
if (static::isEmpty($countryName) || !is_string($countryName)) {
return null;
return $defaultValue;
}

$countries = new \PragmaRX\Countries\Package\Countries();
Expand Down Expand Up @@ -1069,7 +1076,34 @@ public static function getCountryCodeByName(?string $countryName): ?string
}
}

return static::get($data, 'iso2') ?? null;
return static::get($data, 'iso2', $defaultValue);
}

public static function getCountryCodeByCurrency(?string $currencyCode, ?string $defaultValue = null): ?string
{
if (static::isEmpty($currencyCode) || !is_string($currencyCode)) {
return $defaultValue;
}

$countries = new \PragmaRX\Countries\Package\Countries();
$countries = $countries
->all()
->map(function ($country) {
return [
'name' => static::get($country, 'name.common'),
'iso2' => static::get($country, 'cca2'),
'currency' => static::get($country, 'currencies.0'),
];
})
->values()
->toArray();
$countries = collect($countries);

$data = $countries->first(function ($country) use ($currencyCode) {
return strtolower($country['currency']) === strtolower($currencyCode);
});

return static::get($data, 'iso2', $defaultValue);
}

/**
Expand Down Expand Up @@ -2562,4 +2596,42 @@ public static function arrayFrom(array|string|object $target): array
// If $target is none of the above types, return it as a single-element array.
return [$target];
}

/**
* Formats the given amount for Stripe by adjusting it based on the currency's requirements.
*
* This function accounts for Stripe's list of zero-decimal currencies, as well as currencies
* not explicitly handled by Stripe, using the precision defined in the Currency class.
* For zero-decimal currencies, the amount is returned as-is. For other currencies, the amount
* is scaled based on their precision (e.g., multiplied by 100 for two-decimal currencies).
*
* @param int $amount The amount to be formatted, already in the smallest currency unit (e.g., cents for USD).
* @param string $currency The currency code (ISO 4217 format, e.g., 'USD', 'MNT', 'JPY').
*
* @return int the formatted amount in the smallest currency unit, scaled as needed
*
* @throws \InvalidArgumentException if the currency code is invalid or not supported by the Currency class
*/
public static function formatAmountForStripe($amount, $currency): int
{
// List of zero-decimal currencies, including MNT as a workaround
$zeroDecimalCurrencies = [
'BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG',
'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF',
];

// If the currency is zero-decimal, return the amount as is
if (in_array(strtoupper($currency), $zeroDecimalCurrencies)) {
return (int) $amount;
}

// Otherwise, scale the amount based on the currency precision
$currency = new Currency($currency);
$precision = $currency->getPrecision() ?? 2;
if ($precision === 0) {
$amount = (int) $amount * 100;
}

return (int) $amount;
}
}
2 changes: 1 addition & 1 deletion src/Traits/HasOptionsAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function hasOption($key)
public function updateOption($key, $value)
{
$options = $this->getAllOptions();
$options[$key] = $value;
data_set($options, $key, $value);

$this->setAttribute('options', $options);

Expand Down
10 changes: 10 additions & 0 deletions src/Types/Country.php
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,16 @@ function ($country) use ($query) {
);
}

/**
* Get a country instance by ISO2 code.
*
* @return Country
*/
public static function getByIso2(string $code)
{
return static::all()->where('cca2', strtoupper($code))->first();
}

/**
* Find a country by it's currency code.
*
Expand Down
Loading

0 comments on commit da6418d

Please sign in to comment.