Package system sms
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Contact;
|
||||
|
||||
use App\Enums\PersonPhoneType;
|
||||
use App\Models\Person\Person;
|
||||
use App\Models\Person\PersonPhone;
|
||||
|
||||
class PhoneSelector
|
||||
{
|
||||
/**
|
||||
* Select the best phone for a person following priority rules.
|
||||
* Priority:
|
||||
* 1) validated mobile
|
||||
* 2) validated (any type)
|
||||
* 3) mobile (any validation)
|
||||
* 4) first active phone
|
||||
*
|
||||
* Returns an array shape: ['phone' => ?PersonPhone, 'reason' => ?string]
|
||||
*/
|
||||
public function selectForPerson(Person $person): array
|
||||
{
|
||||
// Load active phones only (Person relation already filters active=1)
|
||||
$phones = $person->phones;
|
||||
|
||||
if ($phones->isEmpty()) {
|
||||
return ['phone' => null, 'reason' => 'no_active_phones'];
|
||||
}
|
||||
|
||||
// 1) validated mobile
|
||||
$phone = $phones->first(function (PersonPhone $p) {
|
||||
return ($p->validated === true) && ($p->phone_type === PersonPhoneType::Mobile);
|
||||
});
|
||||
if ($phone) {
|
||||
return ['phone' => $phone, 'reason' => null];
|
||||
}
|
||||
|
||||
// 2) validated (any type)
|
||||
$phone = $phones->first(fn (PersonPhone $p) => $p->validated === true);
|
||||
if ($phone) {
|
||||
return ['phone' => $phone, 'reason' => null];
|
||||
}
|
||||
|
||||
// 3) mobile (any validation)
|
||||
$phone = $phones->first(fn (PersonPhone $p) => $p->phone_type === PersonPhoneType::Mobile);
|
||||
if ($phone) {
|
||||
return ['phone' => $phone, 'reason' => null];
|
||||
}
|
||||
|
||||
// 4) first active
|
||||
return ['phone' => $phones->first(), 'reason' => null];
|
||||
}
|
||||
}
|
||||
@@ -79,16 +79,52 @@ public function sendFromTemplate(SmsTemplate $template, string $to, array $varia
|
||||
return $log;
|
||||
}
|
||||
|
||||
protected function renderContent(string $content, array $vars): string
|
||||
public function renderContent(string $content, array $vars): string
|
||||
{
|
||||
// Simple token replacement: {token}
|
||||
return preg_replace_callback('/\{([a-zA-Z0-9_\.]+)\}/', function ($m) use ($vars) {
|
||||
$key = $m[1];
|
||||
// Support {token} and {nested.keys} using dot-notation lookup
|
||||
$resolver = function (array $arr, string $path) {
|
||||
if (array_key_exists($path, $arr)) {
|
||||
return $arr[$path];
|
||||
}
|
||||
$segments = explode('.', $path);
|
||||
$cur = $arr;
|
||||
foreach ($segments as $seg) {
|
||||
if (is_array($cur) && array_key_exists($seg, $cur)) {
|
||||
$cur = $cur[$seg];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return array_key_exists($key, $vars) ? (string) $vars[$key] : $m[0];
|
||||
return $cur;
|
||||
};
|
||||
|
||||
return preg_replace_callback('/\{([a-zA-Z0-9_\.]+)\}/', function ($m) use ($vars, $resolver) {
|
||||
$key = $m[1];
|
||||
$val = $resolver($vars, $key);
|
||||
|
||||
return $val !== null ? (string) $val : $m[0];
|
||||
}, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a number to EU style: thousands separated by '.', decimals by ','.
|
||||
*/
|
||||
public function formatAmountEu(mixed $value, int $decimals = 2): string
|
||||
{
|
||||
if ($value === null || $value === '') {
|
||||
return number_format(0, $decimals, ',', '.');
|
||||
}
|
||||
$str = (string) $value;
|
||||
// Normalize possible EU-style input like "1.234,56" to standard for float casting
|
||||
if (str_contains($str, ',')) {
|
||||
$str = str_replace(['.', ','], ['', '.'], $str);
|
||||
}
|
||||
$num = (float) $str;
|
||||
|
||||
return number_format($num, $decimals, ',', '.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current credit balance from provider.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user