'sms.browse', 'create' => 'sms.create', ]; protected $storeRequest = \Illuminate\Http\Request::class; protected $updateRequest = \Illuminate\Http\Request::class; /** * Send an SMS and save the record to sms_msg. * * Expects `phone_number` and `message` in the POST body. */ public function send(Request $request) { $this->checkCompanyContext(); if ($this->permissions['create'] != '' && !\Auth::user()->hasPermissionTo($this->permissions['create'])) { return $this->respond(false, [], ['error' => 'user_dont_no_access'], ['message' => trans('core::core.you_dont_have_access')]); } $provider = strtolower(config('sms.gateway_type', 'egyptian')); if ($provider === 'telnyx') { if (empty(config('sms.telnyx.api_key'))) { return $this->respond(false, [], ['error' => 'No SMS provider configured'], 'No SMS provider configured', 500); } } else { $smsUser = CompanySettings::get('S_COMPANY_SMSUSER'); $smsPass = CompanySettings::get('S_COMPANY_SMSPASS'); if (empty($smsUser) || empty($smsPass)) { return $this->respond(false, [], ['error' => 'No SMS provider configured'], 'No SMS provider configured', 500); } } try { $validator = Validator::make($request->all(), [ 'phone_number' => 'required|string|max:30', 'message' => 'required|string|max:1000', ]); if ($validator->fails()) { return $this->respond(false, [], $validator->errors()->all(), 'Validation Error', 422); } $record = (new SmsService())->sendAndSave( trim($request->get('message')), trim($request->get('phone_number')), ['company_id' => \Auth::user()->company_id ?? null] ); if ($record->status !== 'Failed') { return $this->respond(true, ['sms_id' => $record->id, 'status' => $record->status], [], 'SMS sent successfully'); } return $this->respond(false, ['sms_id' => $record->id, 'status' => $record->status], ['error' => 'Failed to send SMS'], 'Failed to send SMS', 500); } catch (\Throwable $th) { return $this->respond(false, [], ['error' => $th->getMessage()], 'Internal Server Error', 500); } } /** * Get the SMS account quota/balance from the configured provider. */ public function quota() { $this->checkCompanyContext(); if ($this->permissions['browse'] != '' && !\Auth::user()->hasPermissionTo($this->permissions['browse'])) { return $this->respond(false, [], ['error' => 'user_dont_no_access'], ['message' => trans('core::core.you_dont_have_access')]); } try { $provider = strtolower(config('sms.gateway_type', 'egyptian')); if ($provider === 'telnyx') { return $this->fetchTelnyxQuota(); } return $this->fetchEgyptianQuota(); } catch (\Throwable $th) { return $this->respond(false, [], ['error' => $th->getMessage()], 'Failed to fetch SMS quota', 500); } } private function fetchTelnyxQuota() { $apiKey = config('sms.telnyx.api_key', ''); if (empty($apiKey)) { return $this->respond(false, [], ['error' => 'No SMS provider configured'], 'No SMS provider configured', 500); } $response = Http::withOptions(['verify' => false]) ->withToken($apiKey) ->get('https://api.telnyx.com/v2/balance'); if (!$response->successful()) { return $this->respond(false, [], ['error' => 'Failed to fetch Telnyx balance'], 'Failed to fetch balance', 500); } $data = $response->json('data') ?? []; $balance = isset($data['balance']) ? (float) $data['balance'] : 0; $currency = $data['currency'] ?? 'USD'; return $this->respond(true, [ 'balance' => $balance, 'currency' => $currency, ], [], 'Quota fetched successfully'); } private function fetchEgyptianQuota() { $smsUser = CompanySettings::get('S_COMPANY_SMSUSER'); $smsPass = CompanySettings::get('S_COMPANY_SMSPASS'); if (empty($smsUser) || empty($smsPass)) { return $this->respond(false, [], ['error' => 'No SMS provider configured'], 'No SMS provider configured', 500); } $response = Http::withOptions(['verify' => false]) ->withBasicAuth($smsUser, $smsPass) ->get('https://api.socialbrand.agency/api/SMS/CheckCredit'); if (!$response->successful()) { return $this->respond(false, [], ['error' => 'Failed to fetch SMS credit'], 'Failed to fetch credit', 500); } $credits = (int) trim($response->body()); return $this->respond(true, [ 'credits' => $credits, ], [], 'Quota fetched successfully'); } }