feat: implement SMS notification service and integrate with existing services
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Services\Sms\IranPayamakService;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
|
||||
class SendPatternSms implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public int $tries = 3;
|
||||
|
||||
public array $backoff = [60, 300, 900];
|
||||
|
||||
public function __construct(
|
||||
protected string $phone,
|
||||
protected string $patternKey,
|
||||
protected array $attributes
|
||||
) {
|
||||
$this->afterCommit();
|
||||
}
|
||||
|
||||
public function handle(IranPayamakService $iranPayamakService): void
|
||||
{
|
||||
$iranPayamakService->sendPattern($this->phone, $this->patternKey, $this->attributes);
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,17 @@
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\OtpCode;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use App\Services\Sms\IranPayamakService;
|
||||
|
||||
class OtpService
|
||||
{
|
||||
protected IranPayamakService $iranPayamakService;
|
||||
|
||||
public function __construct(IranPayamakService $iranPayamakService)
|
||||
{
|
||||
$this->iranPayamakService = $iranPayamakService;
|
||||
}
|
||||
|
||||
public function generateCode(): string
|
||||
{
|
||||
return (string) random_int(1000, 9999);
|
||||
@@ -45,51 +52,14 @@ class OtpService
|
||||
->exists();
|
||||
}
|
||||
|
||||
private function sendSms(string $phone, string $code): array
|
||||
private function sendSms(string $phone, string $code): void
|
||||
{
|
||||
try {
|
||||
$formattedRecipient = $this->formatPhoneForSms($phone);
|
||||
|
||||
$response = Http::withHeaders([
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
'Api-Key' => config('services.iranpayamak.api_key'),
|
||||
])
|
||||
->post(config('services.iranpayamak.api_url'), [
|
||||
'code' => config('services.iranpayamak.patterns.verify_code'),
|
||||
'attributes' => [
|
||||
'otp' => $code,
|
||||
'status' => 'بازنشانی رمز عبور'
|
||||
],
|
||||
'recipient' => $formattedRecipient,
|
||||
'line_number' => config('services.iranpayamak.line_number'),
|
||||
'number_format' => 'english',
|
||||
$this->iranPayamakService->sendPattern($phone, 'verify_code', [
|
||||
'otp' => $code,
|
||||
'status' => 'بازنشانی رمز عبور',
|
||||
]);
|
||||
|
||||
if ($response->successful()) {
|
||||
return $response->json();
|
||||
} else {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'SMS sending failed: ' . $response->status(),
|
||||
'data' => $response->body()
|
||||
];
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'SMS sending exception: ' . $e->getMessage(),
|
||||
'data' => null
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function formatPhoneForSms(string $phone): string
|
||||
{
|
||||
if (str_starts_with($phone, '+98')) {
|
||||
return '0' . substr($phone, 3);
|
||||
}
|
||||
return $phone;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use App\Models\Report;
|
||||
use App\Models\User;
|
||||
use App\Services\FileStorageService;
|
||||
use App\Services\Shift\ShiftScheduleService;
|
||||
use App\Services\Sms\SmsNotificationService;
|
||||
use App\Services\Wallet\WalletService;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -27,11 +28,14 @@ class CaseService
|
||||
|
||||
protected ShiftScheduleService $shiftScheduleService;
|
||||
|
||||
public function __construct(FileStorageService $fileStorageService, WalletService $walletService, ShiftScheduleService $shiftScheduleService)
|
||||
protected SmsNotificationService $smsNotificationService;
|
||||
|
||||
public function __construct(FileStorageService $fileStorageService, WalletService $walletService, ShiftScheduleService $shiftScheduleService, SmsNotificationService $smsNotificationService)
|
||||
{
|
||||
$this->fileStorageService = $fileStorageService;
|
||||
$this->walletService = $walletService;
|
||||
$this->shiftScheduleService = $shiftScheduleService;
|
||||
$this->smsNotificationService = $smsNotificationService;
|
||||
}
|
||||
|
||||
public function pendingForUser(User $user): Builder
|
||||
@@ -95,6 +99,8 @@ class CaseService
|
||||
'finalized_by' => $doctor->id,
|
||||
]);
|
||||
|
||||
$this->smsNotificationService->reportReady($document);
|
||||
|
||||
return $report;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use App\Models\User;
|
||||
use App\Services\FileStorageService;
|
||||
use App\Services\Invoice\InvoiceService;
|
||||
use App\Services\Shift\ShiftScheduleService;
|
||||
use App\Services\Sms\SmsNotificationService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class FastRequestService
|
||||
@@ -22,11 +23,14 @@ class FastRequestService
|
||||
|
||||
protected InvoiceService $invoiceService;
|
||||
|
||||
public function __construct(FileStorageService $fileStorageService, ShiftScheduleService $shiftScheduleService, InvoiceService $invoiceService)
|
||||
protected SmsNotificationService $smsNotificationService;
|
||||
|
||||
public function __construct(FileStorageService $fileStorageService, ShiftScheduleService $shiftScheduleService, InvoiceService $invoiceService, SmsNotificationService $smsNotificationService)
|
||||
{
|
||||
$this->fileStorageService = $fileStorageService;
|
||||
$this->shiftScheduleService = $shiftScheduleService;
|
||||
$this->invoiceService = $invoiceService;
|
||||
$this->smsNotificationService = $smsNotificationService;
|
||||
}
|
||||
|
||||
public function create(User $requester, array $data, array $historyFiles = [], array $scanFiles = []): Document
|
||||
@@ -58,6 +62,8 @@ class FastRequestService
|
||||
]);
|
||||
}
|
||||
|
||||
$this->smsNotificationService->requestRegistered($document);
|
||||
|
||||
return $document;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,9 +8,17 @@ use App\Enums\InvoicePaymentMethodEnum;
|
||||
use App\Enums\InvoiceStatusEnum;
|
||||
use App\Models\Document;
|
||||
use App\Models\Invoice;
|
||||
use App\Services\Sms\SmsNotificationService;
|
||||
|
||||
class InvoiceService
|
||||
{
|
||||
protected SmsNotificationService $smsNotificationService;
|
||||
|
||||
public function __construct(SmsNotificationService $smsNotificationService)
|
||||
{
|
||||
$this->smsNotificationService = $smsNotificationService;
|
||||
}
|
||||
|
||||
public function createForDocument(Document $document): Invoice
|
||||
{
|
||||
$invoice = Invoice::create([
|
||||
@@ -43,6 +51,8 @@ class InvoiceService
|
||||
]);
|
||||
}
|
||||
|
||||
$this->smsNotificationService->paymentConfirmed($invoice);
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Sms;
|
||||
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use RuntimeException;
|
||||
|
||||
class IranPayamakService
|
||||
{
|
||||
public function sendPattern(string $phone, string $patternKey, array $attributes): array
|
||||
{
|
||||
$response = Http::withHeaders([
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
'Api-Key' => config('services.iranpayamak.api_key'),
|
||||
])->post(config('services.iranpayamak.api_url'), [
|
||||
'code' => config("services.iranpayamak.patterns.{$patternKey}"),
|
||||
'attributes' => $attributes,
|
||||
'recipient' => $this->formatRecipient($phone),
|
||||
'line_number' => config('services.iranpayamak.line_number'),
|
||||
'number_format' => 'english',
|
||||
]);
|
||||
|
||||
if (!$response->successful()) {
|
||||
throw new RuntimeException('SMS sending failed: ' . $response->status() . ' ' . $response->body());
|
||||
}
|
||||
|
||||
return $response->json() ?? [];
|
||||
}
|
||||
|
||||
protected function formatRecipient(string $phone): string
|
||||
{
|
||||
if (str_starts_with($phone, '+98')) {
|
||||
return '0' . substr($phone, 3);
|
||||
}
|
||||
|
||||
return $phone;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Sms;
|
||||
|
||||
use App\Jobs\SendPatternSms;
|
||||
use App\Models\Document;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\User;
|
||||
|
||||
class SmsNotificationService
|
||||
{
|
||||
public function requestRegistered(Document $document): void
|
||||
{
|
||||
$this->dispatch($document->requester, 'request_registered', [
|
||||
'code' => $document->code,
|
||||
]);
|
||||
}
|
||||
|
||||
public function paymentConfirmed(Invoice $invoice): void
|
||||
{
|
||||
$this->dispatch($invoice->user, 'payment_confirmed', [
|
||||
'invoice' => $invoice->number,
|
||||
'amount' => number_format($invoice->amount),
|
||||
]);
|
||||
}
|
||||
|
||||
public function reportReady(Document $document): void
|
||||
{
|
||||
$this->dispatch($document->requester, 'report_ready', [
|
||||
'code' => $document->code,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function dispatch(?User $user, string $patternKey, array $attributes): void
|
||||
{
|
||||
if (empty($user?->phone) || empty(config("services.iranpayamak.patterns.{$patternKey}"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendPatternSms::dispatch($user->phone, $patternKey, $attributes);
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -43,12 +43,14 @@ return [
|
||||
|
||||
'iranpayamak' => [
|
||||
'api_url' => env('IRANPAYAMAK_SMS_API_URL', 'https://api.iranpayamak.com/ws/v1/sms/pattern'),
|
||||
'line_number' => env('IRANPAYAMAK_SMS_API_URL', '50002178584000'),
|
||||
'api_key' => env('IRANPAYAMAK_SMS_API_URL', 'jnCyVq4ein7uGsgIGjHsVRrWz0112IA2v2qbZM5q0kHtEXubsh'),
|
||||
|
||||
'line_number' => env('IRANPAYAMAK_SMS_LINE_NUMBER', '50002178584000'),
|
||||
'api_key' => env('IRANPAYAMAK_SMS_API_KEY', 'jnCyVq4ein7uGsgIGjHsVRrWz0112IA2v2qbZM5q0kHtEXubsh'),
|
||||
|
||||
'patterns' => [
|
||||
'verify_code' => 'EvYDvfcUSk',
|
||||
'verify_code' => env('IRANPAYAMAK_SMS_PATTERN_VERIFY_CODE', 'EvYDvfcUSk'),
|
||||
'request_registered' => env('IRANPAYAMAK_SMS_PATTERN_REQUEST_REGISTERED' , 'GO2xzefAO8'),
|
||||
'payment_confirmed' => env('IRANPAYAMAK_SMS_PATTERN_PAYMENT_CONFIRMED' , 'bl3k2UZDPe'),
|
||||
'report_ready' => env('IRANPAYAMAK_SMS_PATTERN_REPORT_READY' , 'ImUrYHVWTx'),
|
||||
],
|
||||
],
|
||||
|
||||
|
||||
@@ -222,6 +222,7 @@ const submitReject = () => {
|
||||
@click="openRejectModal(data)"
|
||||
/>
|
||||
</div>
|
||||
<span v-else class="text-xs text-gray-400">-</span>
|
||||
</template>
|
||||
</TableGeneric>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user