diff --git a/app/Http/Controllers/Admin/MassageController.php b/app/Http/Controllers/Admin/MassageController.php index 2899056..88e6b7e 100644 --- a/app/Http/Controllers/Admin/MassageController.php +++ b/app/Http/Controllers/Admin/MassageController.php @@ -3,12 +3,15 @@ namespace App\Http\Controllers\Admin; use App\DB\Te\TableEngine; +use App\Exceptions\SmsBlockedException; use App\Models\Customer; use App\Models\Message; use App\Models\Order; use Illuminate\Http\Request; use App\Http\Controllers\Controller; use App\Services\ConfigService; +use App\Services\SmsBilling\SmsGatewayService; +use App\Services\SmsBilling\SmsWalletService; use App\Services\SmsProfanityFilter; use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; @@ -53,12 +56,22 @@ class MassageController extends Controller $filter = app(SmsProfanityFilter::class); $filter->assertClean((string) ($request->message ?? '')); - foreach ($customers as $customer) { - // جایگزین کردن نام در پیام - $message = str_replace('%name%', $customer->name, $request->message); + $cfg = app(ConfigService::class); + $appName = trim((string) ($cfg->get('name_fa', '') ?: '')); + $rawMessage = $this->ensureAppNameFooter((string) ($request->message ?? ''), $appName); - // ارسال پیامک - $this->send($customer->mobile, $message); + // پیامک گروهی باید از گلوگاه billing رد شود و از اعتبار کم شود + $billingOk = SmsWalletService::isBillingOperational() + || app(\App\Services\SmsBilling\SuperAdminSmsClient::class)->enabled(); + if (! $billingOk) { + throw new UnprocessableEntityHttpException( + 'پنل پیامک (billing) فعال نیست؛ ارسال گروهی بدون کسر اعتبار مجاز نیست.' + ); + } + + foreach ($customers as $customer) { + $message = $this->applyCustomerNamePlaceholders($rawMessage, (string) $customer->name); + $this->sendBilledSms((string) $customer->mobile, $message, 'group_sms'); } return response()->json(true); @@ -98,10 +111,8 @@ class MassageController extends Controller $appUrl = $cfg->resolvePublicSiteUrl($request); $message = str_replace( - ['%name%', '%نام%', '%app_name%', '%نام_اپ%', '%app_url%', '%لینک_اپ%', '%لینک%'], + ['%app_name%', '%نام_اپ%', '%app_url%', '%لینک_اپ%', '%لینک%'], [ - (string) $customer->name, - (string) $customer->name, $appName, $appName, $appUrl, @@ -110,6 +121,8 @@ class MassageController extends Controller ], $rawMessage ); + $message = $this->applyCustomerNamePlaceholders($message, (string) $customer->name); + $message = $this->ensureAppNameFooter($message, $appName); $this->send($customer->mobile, $message); @@ -263,6 +276,39 @@ class MassageController extends Controller ->toArray(); } + /** + * ارسال از گلوگاه پنل پیامک با کسر اجباری اعتبار؛ در صورت مسدودی/شکست، خطا برمی‌گردد. + */ + private function sendBilledSms(string $mobile, string $message, string $source): void + { + $text = trim($message); + if ($text === '') { + throw new UnprocessableEntityHttpException('متن پیامک خالی است.'); + } + + $gateway = app(SmsGatewayService::class); + + try { + $result = $gateway->sendOrThrow($mobile, $text, $source); + } catch (SmsBlockedException $e) { + throw new UnprocessableEntityHttpException( + 'اعتبار پنل پیامک کافی نیست یا ارسال مسدود است.' + ); + } + + if (! $result->sent) { + throw new UnprocessableEntityHttpException( + $result->errorMessage ?: 'ارسال پیامک ناموفق بود؛ اعتبار کسر نشد.' + ); + } + + Message::create([ + 'sms' => $text, + 'receiver' => $mobile, + 'platforms' => ($result->provider ?: 'sms') . ':' . $mobile, + ]); + } + private function removeDuplicateNumbers(array $customers) { $uniqueCustomers = []; @@ -278,6 +324,46 @@ class MassageController extends Controller return $uniqueCustomers; } + /** + * جایگزینی توکن نام مشتری با واریانت‌های فارسی/انگلیسی و فاصله اختیاری. + * مثال: %name ، %name% ، ٪نام ، % نام ، ٪ نام + */ + private function applyCustomerNamePlaceholders(string $message, string $customerName): string + { + $patterns = [ + '/[%٪]\s*name\s*[%٪]?/iu', + '/[%٪]\s*نام\s*[%٪]?/u', + ]; + + foreach ($patterns as $pattern) { + $replaced = preg_replace($pattern, $customerName, $message); + if (is_string($replaced)) { + $message = $replaced; + } + } + + return $message; + } + + /** خط آخر پیام باید نام اپ باشد؛ اگر نبود اضافه می‌شود. */ + private function ensureAppNameFooter(string $message, string $appName): string + { + $appName = trim($appName); + $trimmed = rtrim($message); + + if ($appName === '') { + return $trimmed; + } + + $lines = preg_split('/\R/u', $trimmed) ?: []; + $last = trim((string) end($lines)); + if ($last === $appName) { + return $trimmed; + } + + return $trimmed === '' ? $appName : ($trimmed . "\n" . $appName); + } + public function messagesTable(Request $request) { $records = Message::with(['person']);