• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PiteurStudio / CourierDZ / 13103483584

02 Feb 2025 11:27PM UTC coverage: 26.042%. Remained the same
13103483584

push

github

web-flow
Merge pull request #10 from n4ss1m/refactor_rector

Refactor: Enable Rector Rules for Code Quality and Strictness

13 of 56 new or added lines in 7 files covered. (23.21%)

100 of 384 relevant lines covered (26.04%)

3.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/ProviderIntegrations/EcotrackProviderIntegration.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace CourierDZ\ProviderIntegrations;
6

7
use CourierDZ\Contracts\ShippingProviderContract;
8
use CourierDZ\Exceptions\CreateOrderException;
9
use CourierDZ\Exceptions\CredentialsException;
10
use CourierDZ\Exceptions\HttpException;
11
use CourierDZ\Exceptions\NotImplementedException;
12
use CourierDZ\Exceptions\TrackingIdNotFoundException;
13
use CourierDZ\Support\ShippingProviderValidation;
14
use GuzzleHttp\Client;
15
use GuzzleHttp\Exception\GuzzleException;
16
use GuzzleHttp\Psr7\Request;
17

18
abstract class EcotrackProviderIntegration implements ShippingProviderContract
19
{
20
    use ShippingProviderValidation;
21

22
    /**
23
     * Provider credentials
24
     *
25
     * @var array<non-empty-string, non-empty-string>
26
     */
27
    protected array $credentials;
28

29
    /**
30
     * Validation rules for creating an order
31
     *
32
     * @var array<non-empty-string, non-empty-string>
33
     */
34
    public array $getCreateOrderValidationRules = [
35
        'reference' => 'nullable|string|max:255',
36
        'nom_client' => 'required|string|max:255',
37
        'telephone' => 'required|numeric|digits_between:9,10',
38
        'telephone_2' => 'nullable|numeric|digits_between:9,10',
39
        'adresse' => 'required|string|max:255',
40
        'code_postal' => 'nullable|numeric',
41
        'commune' => 'required|string|max:255',
42
        'code_wilaya' => 'required|numeric|min:1|max:58',
43
        'montant' => 'required|numeric',
44
        'remarque' => 'nullable|string|max:255',
45
        'produit' => 'nullable|string|max:255',
46
        'stock' => 'integer|in:0,1',
47
        'quantite' => 'required_if:stock,1|integer|min:1',
48
        'produit_a_recupere' => 'nullable|string|max:255',
49
        'boutique' => 'nullable|string|max:255',
50
        'type' => 'required|integer|in:1,2,3,4', // Type de l'operation *[ 1 = Livraison , 2 = Echange , 3 = PICKUP , 4 = Recouvrement ]* | integer , entre 1 et 4 , **obligatoire**
51
        'stop_desk' => 'nullable|in:0,1',
52
    ];
53

54
    /**
55
     * EcotrackProviderIntegration constructor.
56
     *
57
     * @param  array<non-empty-string, non-empty-string>  $credentials  An array of credentials for the provider, containing the 'token' key
58
     *
59
     * @throws CredentialsException If the credentials do not contain the 'token' key
60
     */
61
    public function __construct(array $credentials)
62
    {
63
        $provider_name = (static::metadata())['name'];
×
64

65
        if (! isset($credentials['token'])) {
×
NEW
66
            throw new CredentialsException($provider_name." credentials must include 'token'.");
×
67
        }
68

69
        $this->credentials = $credentials;
×
70
    }
71

72
    abstract public static function metadata(): array;
73

74
    abstract public static function apiDomain(): string;
75

76
    /**
77
     * Test the credentials
78
     *
79
     * This method tests the credentials by making a GET request
80
     * to the Ecotrack API to retrieve the list of wilayas.
81
     *
82
     * If the request is successful, the method returns true.
83
     * If the request returns a 401 or 403 status code, the method returns false.
84
     * If the request returns any other status code, the method throws an HttpException.
85
     *
86
     * @throws HttpException If the request fails
87
     */
88
    public function testCredentials(): bool
89
    {
90
        try {
91
            // Initialize Guzzle client
92
            $client = new Client(['http_errors' => false]);
×
93

94
            // Define the headers
95
            $headers = [
×
NEW
96
                'Authorization' => 'Bearer '.$this->credentials['token'],
×
97
            ];
×
98

99
            // Make the GET request
100
            $response = $client->request('GET', static::apiDomain().'api/v1/get/wilayas', [
×
101
                'headers' => $headers,
×
102
                'Content-Type' => 'application/json',
×
103
            ]);
×
104

105
            // Check the status code
106
            return match ($response->getStatusCode()) {
×
107
                // If the request is successful, return true
108
                200 => true,
×
109
                // If the request returns a 401 or 403 status code, return false
110
                401, 403 => false,
×
111
                // If the request returns any other status code, throw an HttpException
112
                default => throw new HttpException('Ecotrack '.static::metadata()['name'].', Unexpected error occurred.'),
×
113
            };
×
NEW
114
        } catch (GuzzleException $guzzleException) {
×
115
            // Handle exceptions
NEW
116
            throw new HttpException($guzzleException->getMessage());
×
117
        }
118
    }
119

120
    /**
121
     * {@inheritdoc}
122
     */
123
    public function getRates(?int $from_wilaya_id, ?int $to_wilaya_id): array
124
    {
125
        try {
126
            // Initialize Guzzle client
127
            $client = new Client;
×
128

129
            // Define the headers
130
            $headers = [
×
NEW
131
                'Authorization' => 'Bearer '.$this->credentials['token'],
×
132
            ];
×
133

134
            // Make the GET request
135
            $response = $client->request('GET', static::apiDomain().'api/v1/get/fees', [
×
136
                'headers' => $headers,
×
137
                'Content-Type' => 'application/json',
×
138
            ]);
×
139

140
            // Get the response body
141
            $body = $response->getBody()->getContents();
×
142

143
            // Decode the response body
144
            $result = json_decode($body, true);
×
145

146
            // If the to_wilaya_id is specified, filter the result to only include the specified wilaya
NEW
147
            if ($to_wilaya_id !== null && $to_wilaya_id !== 0) {
×
148
                foreach ($result['livraison'] as $wilaya) {
×
149
                    if ($wilaya['wilaya_id'] == $to_wilaya_id) {
×
150
                        // Return the first matching wilaya
151
                        return $wilaya;
×
152
                    }
153
                }
154

155
                // If no matching wilaya is found, return an empty array
156
                return [];
×
157
            }
158

159
            // Return the list of shipping rates
160
            return $result['livraison'];
×
161

NEW
162
        } catch (GuzzleException $guzzleException) {
×
163
            // Handle exceptions
NEW
164
            throw new HttpException($guzzleException->getMessage());
×
165
        }
166
    }
167

168
    public function getCreateOrderValidationRules(): array
169
    {
170
        return $this->getCreateOrderValidationRules;
×
171
    }
172

173
    /**
174
     * {@inheritdoc}
175
     */
176
    public function createOrder(array $orderData): array
177
    {
178
        // Validate the order data
179
        $this->validateCreate($orderData);
×
180

181
        // Prepare the request body
182
        $data = $orderData;
×
183

184
        $requestBody = json_encode($data, JSON_UNESCAPED_UNICODE);
×
185

186
        if ($requestBody === false) {
×
187
            throw new CreateOrderException('Failed to encode order data to JSON.');
×
188
        }
189

190
        try {
191
            // Initialize Guzzle client
192
            $client = new Client;
×
193

194
            // Define the headers
195
            $headers = [
×
NEW
196
                'Authorization' => 'Bearer '.$this->credentials['token'],
×
197
                'Content-Type' => 'application/json',
×
198
            ];
×
199

200
            // Make the POST request
201
            $request = new Request('POST', static::apiDomain().'api/v1/create/order', $headers, $requestBody);
×
202

203
            $response = $client->send($request);
×
204

205
            // Get the response body
206
            $body = $response->getBody()->getContents();
×
207

208
            // Decode the response body
209
            $arrayResponse = json_decode($body, true);
×
210

211
            // Check if the order creation was successful
212
            if ($arrayResponse['success'] === false) {
×
213
                throw new CreateOrderException('Create Order failed: '.$arrayResponse['message']);
×
214
            }
215

216
            // Return the order response
217
            return $arrayResponse;
×
218

NEW
219
        } catch (GuzzleException $guzzleException) {
×
220
            // Handle exceptions
NEW
221
            throw new HttpException($guzzleException->getMessage());
×
222
        }
223
    }
224

225
    /**
226
     * {@inheritdoc}
227
     */
228
    public function orderLabel(string $orderId): array
229
    {
230
        try {
231
            // Initialize Guzzle client
232
            $client = new Client(['http_errors' => false]);
×
233

234
            // Define the headers
235
            $headers = [
×
NEW
236
                'Authorization' => 'Bearer '.$this->credentials['token'],
×
237
            ];
×
238

239
            // Make the GET request
240
            $response = $client->request('GET', static::apiDomain().'api/v1/get/order/label?tracking='.$orderId, [
×
241
                'headers' => $headers,
×
242
                'Content-Type' => 'application/json',
×
243
            ]);
×
244

245
            // Check if the request was successful
246
            if ($response->getStatusCode() !== 200) {
×
247
                // Check if the request failed because the tracking ID was not found
248
                if ($response->getStatusCode() === 422) {
×
249
                    throw new TrackingIdNotFoundException('Tracking ID not found in Ecotrack.');
×
250
                }
251

252
                // Handle any other error
253
                throw new HttpException('Failed to retrieve label for order with tracking ID '.$orderId);
×
254
            }
255

256
            // Get the response body
257
            $label = $response->getBody()->getContents();
×
258

NEW
259
            if ($label === '' || $label === '0') {
×
260
                throw new HttpException('Failed to retrieve label for order with tracking ID '.$orderId.' - Empty response from Ecotrack');
×
261
            }
262

263
            $base64data = base64_encode($label);
×
264

265
            if ($base64data === '') {
×
266
                throw new \RuntimeException('Unexpected empty base64 string');
×
267
            }
268

269
            // Return the label details
270
            return [
×
271
                'type' => 'pdf',
×
272
                'data' => $base64data,
×
273
            ];
×
274

NEW
275
        } catch (GuzzleException $guzzleException) {
×
276
            // Handle exceptions
NEW
277
            throw new HttpException($guzzleException->getMessage());
×
278
        }
279
    }
280

281
    /**
282
     * Get order details
283
     *
284
     * @throws NotImplementedException
285
     */
286
    public function getOrder(string $trackingId): array
287
    {
288
        throw new NotImplementedException('Not implemented');
×
289
    }
290
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc