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.
167 lines
5.2 KiB
PHP
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(),
|
|
];
|
|
}
|
|
}
|
|
}
|