add SuperAdmin SMS client routing

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-05 18:34:07 +03:30
co-authored by Cursor
parent f42ae09d14
commit c6b1478b21
3 changed files with 290 additions and 21 deletions
+69 -21
View File
@@ -4,7 +4,6 @@ namespace App\Services\SmsBilling;
use App\Exceptions\SmsBlockedException;
use App\Models\Setting;
use App\Models\User;
use App\Services\SmsBilling\Contracts\SmsProviderInterface;
use App\Services\SmsBilling\Providers\CentralSmsApiProvider;
use App\Services\SmsBilling\Providers\MeliPayamakProvider;
@@ -19,6 +18,7 @@ class SmsGatewayService
private SmsWalletService $walletService,
private SmsSegmentCalculator $segmentCalculator,
private SmsAlertService $alertService,
private SuperAdminSmsClient $superAdminSms,
MeliPayamakProvider $meliPayamakProvider,
CentralSmsApiProvider $centralSmsApiProvider,
) {
@@ -35,9 +35,17 @@ class SmsGatewayService
bool $isAlert = false
): SmsSendResult {
$config = $this->buildProviderConfig();
$billingOperational = SmsWalletService::isBillingOperational();
$useSuperAdmin = $this->superAdminSms->enabled();
$billingOperational = SmsWalletService::isBillingOperational() || $useSuperAdmin;
$text = trim($message);
if ($billingOperational && $this->walletService->isBlocked()) {
if ($text === '') {
return SmsSendResult::failed('متن پیامک خالی است.');
}
$partsEstimate = max(1, $this->segmentCalculator->countParts($text));
if ($billingOperational && ! $this->maySend($partsEstimate, $isAlert)) {
return SmsSendResult::blocked();
}
@@ -49,12 +57,6 @@ class SmsGatewayService
return SmsSendResult::failed('سرویس پیامک پیکربندی نشده است.');
}
$text = trim($message);
if ($text === '') {
return SmsSendResult::failed('متن پیامک خالی است.');
}
try {
$result = $provider->send($to, $text, $config);
@@ -77,18 +79,7 @@ class SmsGatewayService
$providerName = $this->providerLabel($provider);
if ($billingOperational) {
$debit = $this->walletService->debitSuccessfulSms(
$to,
$text,
$parts,
$providerName,
$source,
$isAlert
);
if (! $isAlert) {
$this->alertService->maybeSendLowBalanceAlerts($debit['wallet']);
}
$this->billAfterSuccess($to, $text, $parts, $providerName, $source, $isAlert);
}
return SmsSendResult::success($providerName);
@@ -117,6 +108,63 @@ class SmsGatewayService
return $result;
}
private function maySend(int $parts, bool $isAlert): bool
{
if ($this->superAdminSms->enabled()) {
$status = $this->superAdminSms->status($parts, $isAlert);
if ($status === null) {
return ! $this->walletService->isBlocked();
}
return (bool) $status['allowed'];
}
return ! $this->walletService->isBlocked();
}
private function billAfterSuccess(
string $to,
string $text,
int $parts,
string $providerName,
?string $source,
bool $isAlert
): void {
if ($this->superAdminSms->enabled()) {
$consumed = $this->superAdminSms->consume(
$to,
$text,
$parts,
$providerName,
$source,
$isAlert
);
if ($consumed === null) {
Log::error('SmsGateway: SuperAdmin consume failed after successful send', [
'to' => $to,
'parts' => $parts,
'source' => $source,
]);
}
return;
}
$debit = $this->walletService->debitSuccessfulSms(
$to,
$text,
$parts,
$providerName,
$source,
$isAlert
);
if (! $isAlert) {
$this->alertService->maybeSendLowBalanceAlerts($debit['wallet']);
}
}
private function buildProviderConfig(): array
{
return [