ifnex/04_Laravel/app/Services/KavenegarSmsService.php
Kazem Alghasi d6e04d53fa feat(core): integrate Kavenegar SMS notifications and audit logging
Implement a comprehensive notification system using Kavenegar SMS
gateway and enhance system traceability through audit logging and
detailed shipment status history.

- SMS Integration:
  - Add Kavenegar SMS service with configurable API keys and sender
    numbers via system settings.
  - Implement automated SMS notifications for shipment approval,
    rejection, successful payments, and tracking updates.
  - Add administrative UI in Filament to manage SMS gateway settings
    and toggle specific notification types.
- Audit & Tracking:
  - Apply `Auditable` trait to core models (User, Shipment, Wallet,
    etc.) to track changes.
  - Refactor `ShipmentStatusHistory` to include status transitions
    (`from_status` to `to_status`) and specific reasons for changes.
  - Implement `ShipmentObserver` to automate notification triggers
    on status changes.
- Database & Config:
  - Add migrations for enhanced shipment status history tracking.
  - Update `.env.example` and `config/ifnex.php` with Kavenegar
    configuration parameters.
2026-09-10 00:52:18 +03:30

167 lines
5.2 KiB
PHP

<?php
namespace App\Services;
use App\Models\SystemSetting;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
class KavenegarSmsService
{
private string $apiKey;
private string $sender;
public function __construct()
{
$this->apiKey = (string) SystemSetting::get('kavenegar_api_key', config('ifnex.kavenegar.api_key', ''));
$this->sender = (string) SystemSetting::get('kavenegar_sender', config('ifnex.kavenegar.sender', '10008566'));
}
public function isEnabled(): bool
{
return !empty($this->apiKey);
}
public function sendVerificationCode(string $phone): array
{
$code = Str::random(5, '0123456789');
$cacheKey = "sms_verify_{$phone}";
Cache::put($cacheKey, $code, now()->addMinutes(10));
$message = "کد تأیید IFNEX: {$code}";
return $this->send($phone, $message);
}
public function verifyCode(string $phone, string $code): bool
{
$cacheKey = "sms_verify_{$phone}";
$storedCode = Cache::get($cacheKey);
if ($storedCode && $storedCode === $code) {
Cache::forget($cacheKey);
return true;
}
return false;
}
public function send(string $receptor, string $message): array
{
if (!$this->isEnabled()) {
return [
'success' => false,
'message' => 'API Key Kavenegar تنظیم نشده است',
];
}
try {
$response = Http::timeout(10)
->post("https://api.kavenegar.com/v1/{$this->apiKey}/sms/send.json", [
'receptor' => $receptor,
'sender' => $this->sender,
'message' => $message,
]);
$data = $response->json();
if ($response->successful() && isset($data['return']['status']) && $data['return']['status'] == 200) {
return [
'success' => true,
'message' => 'پیامک با موفقیت ارسال شد',
'cost' => $data['entries'][0]['cost'] ?? 0,
];
}
return [
'success' => false,
'message' => $data['return']['message'] ?? 'خطا در ارسال پیامک',
];
} catch (\Exception $e) {
return [
'success' => false,
'message' => 'خطا در اتصال به سرور Kavenegar: ' . $e->getMessage(),
];
}
}
public function sendBulk(array $receptors, string $message): array
{
if (!$this->isEnabled()) {
return [
'success' => false,
'message' => 'API Key Kavenegar تنظیم نشده است',
];
}
try {
$response = Http::timeout(30)
->post("https://api.kavenegar.com/v1/{$this->apiKey}/sms/send.json", [
'receptor' => $receptors,
'sender' => $this->sender,
'message' => $message,
]);
$data = $response->json();
if ($response->successful() && isset($data['return']['status']) && $data['return']['status'] == 200) {
return [
'success' => true,
'message' => 'پیامک با موفقیت ارسال شد',
'cost' => collect($data['entries'])->sum('cost'),
];
}
return [
'success' => false,
'message' => $data['return']['message'] ?? 'خطا در ارسال پیامک',
];
} catch (\Exception $e) {
return [
'success' => false,
'message' => 'خطا در اتصال به سرور Kavenegar: ' . $e->getMessage(),
];
}
}
public function checkStatus(string $messageId): array
{
if (!$this->isEnabled()) {
return [
'success' => false,
'message' => 'API Key Kavenegar تنظیم نشده است',
];
}
try {
$response = Http::timeout(10)
->get("https://api.kavenegar.com/v1/{$this->apiKey}/select.json", [
'messageid' => $messageId,
]);
$data = $response->json();
if ($response->successful() && isset($data['return']['status']) && $data['return']['status'] == 200) {
$entry = $data['entries'][0] ?? null;
return [
'success' => true,
'status' => $entry['status'] ?? 'unknown',
'status_text' => $entry['statustext'] ?? 'نامشخص',
];
}
return [
'success' => false,
'message' => $data['return']['message'] ?? 'خطا در بررسی وضعیت',
];
} catch (\Exception $e) {
return [
'success' => false,
'message' => 'خطا در اتصال به سرور Kavenegar: ' . $e->getMessage(),
];
}
}
}