Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
2.78% |
4 / 144 |
|
0.00% |
0 / 15 |
CRAP | |
0.00% |
0 / 1 |
| GestionaService | |
2.78% |
4 / 144 |
|
0.00% |
0 / 15 |
2634.36 | |
0.00% |
0 / 1 |
| __construct | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
2.03 | |||
| getCredentials | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
42 | |||
| encrypt | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| decrypt | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| auth | |
0.00% |
0 / 32 |
|
0.00% |
0 / 1 |
72 | |||
| request | |
0.00% |
0 / 43 |
|
0.00% |
0 / 1 |
210 | |||
| updateApiCredentials | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
42 | |||
| getApiDetails | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
| getLastUpdate | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
| getSyncStatus | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| setSyncStatus | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
| getG3wActive | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| updateG3wActive | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| getBudgetsByDay | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| checkDeleted | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace App\Services; |
| 4 | |
| 5 | use App\Models\TblCompanies; |
| 6 | use App\Models\TblG3WCredentials; |
| 7 | use App\Models\TblG3wLastUpdate; |
| 8 | use Illuminate\Http\JsonResponse; |
| 9 | use Illuminate\Support\Facades\Log; |
| 10 | |
| 11 | class GestionaService |
| 12 | { |
| 13 | protected $apiUrl; |
| 14 | |
| 15 | protected $user; |
| 16 | |
| 17 | protected $password; |
| 18 | |
| 19 | protected $accessToken; |
| 20 | |
| 21 | protected $region; |
| 22 | |
| 23 | protected $credentials; |
| 24 | |
| 25 | protected $appUser; |
| 26 | |
| 27 | protected $encryptKey; |
| 28 | protected string $cipher; |
| 29 | |
| 30 | public function __construct() |
| 31 | { |
| 32 | $this->encryptKey = config('app.encrypt_key'); |
| 33 | if (!$this->encryptKey) { |
| 34 | throw new \Exception('Encryption key not set in environment variables'); |
| 35 | } |
| 36 | |
| 37 | $this->cipher = 'AES-256-CBC'; |
| 38 | |
| 39 | $this->appUser = request()->header('Name') ?? 'System'; |
| 40 | } |
| 41 | |
| 42 | public function getCredentials($region): void{ |
| 43 | |
| 44 | if ($region === 'Catalunya') { |
| 45 | $region = 'Cataluña'; |
| 46 | } |
| 47 | |
| 48 | $this->credentials = TblG3WCredentials::where('region', $region)->first(); |
| 49 | |
| 50 | if (! $this->credentials) { |
| 51 | TblG3WCredentials::create([ |
| 52 | 'region' => $region, |
| 53 | ]); |
| 54 | $this->credentials = TblG3WCredentials::where('region', $region)->first(); |
| 55 | } |
| 56 | |
| 57 | $this->user = $this->credentials->user ? $this->decrypt($this->credentials->user) : null; |
| 58 | $this->password = $this->credentials->password ? $this->decrypt($this->credentials->password) : null; |
| 59 | $this->apiUrl = $this->credentials->url ? $this->decrypt($this->credentials->url) : null; |
| 60 | } |
| 61 | |
| 62 | /** |
| 63 | * @return false|string |
| 64 | */ |
| 65 | private function encrypt($data): string|false |
| 66 | { |
| 67 | $iv = substr(hash('sha256', (string) $this->encryptKey), 0, 16); |
| 68 | return openssl_encrypt($data, $this->cipher, $this->encryptKey, 0, $iv); |
| 69 | } |
| 70 | |
| 71 | /** |
| 72 | * @return false|string |
| 73 | */ |
| 74 | private function decrypt($encryptedData): string|false |
| 75 | { |
| 76 | $iv = substr(hash('sha256', (string) $this->encryptKey), 0, 16); |
| 77 | return openssl_decrypt($encryptedData, $this->cipher, $this->encryptKey, 0, $iv); |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * @return void |
| 82 | * |
| 83 | * @throws \Exception |
| 84 | */ |
| 85 | protected function auth($region) |
| 86 | { |
| 87 | try { |
| 88 | $this->getCredentials($region); |
| 89 | if (! $this->apiUrl || ! $this->user || ! $this->password) { |
| 90 | throw new \Exception('Incomplete credentials: URL, user, or password missing.'); |
| 91 | } |
| 92 | |
| 93 | $url = "{$this->apiUrl}login"; |
| 94 | |
| 95 | $curl = curl_init(); |
| 96 | curl_setopt_array($curl, [ |
| 97 | CURLOPT_URL => $url, |
| 98 | CURLOPT_RETURNTRANSFER => true, |
| 99 | CURLOPT_POST => true, |
| 100 | CURLOPT_POSTFIELDS => json_encode([ |
| 101 | 'email' => $this->user, |
| 102 | 'password' => $this->password, |
| 103 | ]), |
| 104 | CURLOPT_HTTPHEADER => [ |
| 105 | 'Accept: application/json', |
| 106 | 'Content-Type: application/json', |
| 107 | ], |
| 108 | ]); |
| 109 | |
| 110 | $response = curl_exec($curl); |
| 111 | |
| 112 | if (curl_errno($curl)) { |
| 113 | throw new \Exception('cURL error: '.curl_error($curl)); |
| 114 | } |
| 115 | |
| 116 | $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); |
| 117 | curl_close($curl); |
| 118 | |
| 119 | if ($httpCode !== 200) { |
| 120 | throw new \Exception('Authentication error: '.$response); |
| 121 | } |
| 122 | |
| 123 | $responseData = json_decode($response, true); |
| 124 | $this->accessToken = $responseData['accessToken'] ?? null; |
| 125 | |
| 126 | if (! $this->accessToken) { |
| 127 | throw new \Exception('No access token returned.'); |
| 128 | } |
| 129 | } catch (\Exception $e) { |
| 130 | Log::channel('g3w')->error('Error in auth: '.$e->getMessage()); |
| 131 | throw new \Exception('Authentication failed: '.$e->getMessage()); |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | /** |
| 136 | * @param $method |
| 137 | * @param $endpoint |
| 138 | * @return mixed |
| 139 | * |
| 140 | * @throws \Exception |
| 141 | */ |
| 142 | public function request($method, $endpoint, $region, array $data = []) |
| 143 | { |
| 144 | try { |
| 145 | $this->getCredentials($region); |
| 146 | |
| 147 | if (! $this->apiUrl) { |
| 148 | throw new \Exception('API URL is not defined.'); |
| 149 | } |
| 150 | |
| 151 | if (! $this->accessToken) { |
| 152 | $this->auth($region); |
| 153 | } |
| 154 | |
| 155 | $url = "{$this->apiUrl}{$endpoint}"; |
| 156 | $curl = curl_init(); |
| 157 | |
| 158 | curl_setopt_array($curl, [ |
| 159 | CURLOPT_URL => $url, |
| 160 | CURLOPT_RETURNTRANSFER => true, |
| 161 | CURLOPT_CUSTOMREQUEST => strtoupper((string) $method), |
| 162 | CURLOPT_HTTPHEADER => [ |
| 163 | 'Authorization: Bearer '.$this->accessToken, |
| 164 | 'Accept: application/json', |
| 165 | 'Content-Type: application/json', |
| 166 | ], |
| 167 | ]); |
| 168 | |
| 169 | if (in_array(strtoupper((string) $method), ['POST', 'PUT', 'PATCH']) && !empty($data)) { |
| 170 | if (!is_array($data)) { |
| 171 | throw new \Exception('The $data parameter must be an array.'); |
| 172 | } |
| 173 | curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); |
| 174 | } |
| 175 | |
| 176 | $response = curl_exec($curl); |
| 177 | |
| 178 | if (curl_errno($curl)) { |
| 179 | throw new \Exception('cURL error: '.curl_error($curl)); |
| 180 | } |
| 181 | |
| 182 | $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); |
| 183 | curl_close($curl); |
| 184 | |
| 185 | if ($httpCode === 401) { |
| 186 | $this->auth($region); |
| 187 | |
| 188 | return $this->request($method, $endpoint, $region, $data); |
| 189 | } |
| 190 | |
| 191 | if ($httpCode < 200 || $httpCode >= 300) { |
| 192 | Log::channel('g3w')->error('API Response Error: '.$response); |
| 193 | |
| 194 | $errorResponse = json_decode($response, true); |
| 195 | $errorMessage = is_array($errorResponse) && isset($errorResponse['message']) |
| 196 | ? $errorResponse['message'] |
| 197 | : 'Request error: '.$response; |
| 198 | |
| 199 | throw new \Exception($errorMessage); |
| 200 | } |
| 201 | |
| 202 | $responseData = json_decode($response, true); |
| 203 | |
| 204 | if (json_last_error() !== JSON_ERROR_NONE) { |
| 205 | throw new \Exception('Invalid JSON response: '.$response); |
| 206 | } |
| 207 | |
| 208 | return $responseData; |
| 209 | } catch (\Exception $e) { |
| 210 | Log::channel('g3w')->error('Error in request: '.$e->getMessage()); |
| 211 | throw $e; |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | /** |
| 216 | * @return true |
| 217 | * |
| 218 | * @throws \Exception |
| 219 | */ |
| 220 | public function updateApiCredentials(array $params, $region = null): bool |
| 221 | { |
| 222 | try { |
| 223 | $this->getCredentials($region); |
| 224 | |
| 225 | $updateData = []; |
| 226 | if (isset($params['url'])) { |
| 227 | if (!str_ends_with($params['url'], '/')) { |
| 228 | $params['url'] .= '/'; |
| 229 | } |
| 230 | $updateData['url'] = $this->encrypt($params['url']); |
| 231 | } |
| 232 | |
| 233 | if (isset($params['user'])) { |
| 234 | $updateData['user'] = $this->encrypt($params['user']); |
| 235 | } |
| 236 | |
| 237 | if (isset($params['password'])) { |
| 238 | $updateData['password'] = $this->encrypt($params['password']); |
| 239 | } |
| 240 | |
| 241 | $updateData['user_id'] = $params['user_id'] ?? null; |
| 242 | |
| 243 | TblG3WCredentials::where('region', $region)->update($updateData); |
| 244 | |
| 245 | return true; |
| 246 | } catch (\Exception $e) { |
| 247 | Log::channel('g3w')->error('Error updating credentials for region '.$this->region.': '.$e->getMessage()); |
| 248 | throw $e; |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | /** |
| 253 | * @return JsonResponse |
| 254 | */ |
| 255 | public function getApiDetails($region = null) |
| 256 | { |
| 257 | $this->getCredentials($region); |
| 258 | if (! $this->credentials) { |
| 259 | return response()->json(['message' => 'No credentials found'], 404); |
| 260 | } |
| 261 | |
| 262 | return response()->json([ |
| 263 | 'url' => $this->decrypt($this->credentials->url), |
| 264 | 'user' => $this->decrypt($this->credentials->user), |
| 265 | ]); |
| 266 | } |
| 267 | |
| 268 | /** |
| 269 | * @return JsonResponse |
| 270 | */ |
| 271 | public function getLastUpdate($region) |
| 272 | { |
| 273 | $lastUpdate = TblG3wLastUpdate::where('region', $region)->first(); |
| 274 | |
| 275 | if (! $lastUpdate) { |
| 276 | return response()->json(['message' => 'No last update found'], 404); |
| 277 | } |
| 278 | |
| 279 | return response()->json([ |
| 280 | 'lastUpdate' => $lastUpdate->updated_at->format('Y-m-d H:i:s'), |
| 281 | 'updatingNow' => $lastUpdate->updatingNow, |
| 282 | ]); |
| 283 | } |
| 284 | |
| 285 | public function getSyncStatus($region) |
| 286 | { |
| 287 | if ($region === "'Catalunya'") { |
| 288 | $region = 'Cataluña'; |
| 289 | } |
| 290 | |
| 291 | return TblG3wLastUpdate::where('region', $region)->first()->updatingNow ?? 0; |
| 292 | |
| 293 | } |
| 294 | |
| 295 | public function setSyncStatus($status, $region): void{ |
| 296 | if($region === "Catalunya" || $region === "'Catalunya'"){ |
| 297 | $region = "Cataluña"; |
| 298 | } |
| 299 | |
| 300 | $record = TblG3wLastUpdate::where('region', $region)->first(); |
| 301 | |
| 302 | $record->updatingNow = $status; |
| 303 | $record->save(); |
| 304 | } |
| 305 | |
| 306 | public function getG3wActive($region) |
| 307 | { |
| 308 | return TblCompanies::where('region', $region)->first()->g3W_active ?? 0; |
| 309 | } |
| 310 | |
| 311 | public function updateG3wActive($active, $region): void{ |
| 312 | $record = TblCompanies::where("region", $region)->first(); |
| 313 | |
| 314 | $record->g3W_active = $active; |
| 315 | $record->save(); |
| 316 | } |
| 317 | |
| 318 | public function getBudgetsByDay(string $date, $region){ |
| 319 | return $this->request('get', 'presupuesto?fecha=' . $date, $region, []); |
| 320 | } |
| 321 | |
| 322 | public function checkDeleted ($id, $region): bool{ |
| 323 | try{ |
| 324 | $this->request('get', "presupuesto/{$id}", $region, []); |
| 325 | |
| 326 | return false; |
| 327 | } catch (\Exception $e) { |
| 328 | if (str_contains($e->getMessage(), 'No se ha encontrado el presupuesto')) { |
| 329 | return true; |
| 330 | } |
| 331 | |
| 332 | return false; |
| 333 | } |
| 334 | |
| 335 | } |
| 336 | } |