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

PiteurStudio / CourierDZ / 13191187689

07 Feb 2025 01:18AM UTC coverage: 44.248% (+22.1%) from 22.124%
13191187689

push

github

web-flow
Merge pull request #12 from n4ss1m/improvements_0225

Refactor Types, Enhance Docs & Add 20 Ecotrack Providers

200 of 226 new or added lines in 21 files covered. (88.5%)

1 existing line in 1 file now uncovered.

300 of 678 relevant lines covered (44.25%)

5.48 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'])) {
×
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 = [
×
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
            };
×
114
        } catch (GuzzleException $guzzleException) {
×
115
            // Handle exceptions
116
            throw new HttpException($guzzleException->getMessage());
×
117
        }
118
    }
119

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

129
            // Define the headers
130
            $headers = [
×
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

NEW
146
            if (! is_array($result) || ! array_key_exists('livraison', $result)) {
×
NEW
147
                throw new HttpException('Ecotrack '.static::metadata()['name'].', Unexpected error occurred.');
×
148
            }
149

150
            // If the to_wilaya_id is specified, filter the result to only include the specified wilaya
151
            if ($to_wilaya_id !== null && $to_wilaya_id !== 0) {
×
152

NEW
153
                if (! is_array($result['livraison'])) {
×
NEW
154
                    throw new HttpException('Ecotrack '.static::metadata()['name'].', Unexpected error occurred.');
×
155
                }
156

157
                foreach ($result['livraison'] as $wilaya) {
×
158

NEW
159
                    if (! is_array($wilaya) || ! array_key_exists('wilaya_id', $wilaya)) {
×
NEW
160
                        throw new HttpException('Ecotrack '.static::metadata()['name'].', Unexpected error occurred.');
×
161
                    }
162

UNCOV
163
                    if ($wilaya['wilaya_id'] == $to_wilaya_id) {
×
164
                        // Return the first matching wilaya
165
                        return $wilaya;
×
166
                    }
167
                }
168

169
                // If no matching wilaya is found, return an empty array
170
                return [];
×
171
            }
172

173
            // Return the list of shipping rates
174
            return $result['livraison'];
×
175

176
        } catch (GuzzleException $guzzleException) {
×
177
            // Handle exceptions
178
            throw new HttpException($guzzleException->getMessage());
×
179
        }
180
    }
181

182
    public function getCreateOrderValidationRules(): array
183
    {
184
        return $this->getCreateOrderValidationRules;
×
185
    }
186

187
    /**
188
     * {@inheritdoc}
189
     */
190
    public function createOrder(array $orderData): array
191
    {
192
        // Validate the order data
193
        $this->validateCreate($orderData);
×
194

195
        // Prepare the request body
196
        $data = $orderData;
×
197

198
        $requestBody = json_encode($data, JSON_UNESCAPED_UNICODE);
×
199

200
        if ($requestBody === false) {
×
201
            throw new CreateOrderException('Failed to encode order data to JSON.');
×
202
        }
203

204
        try {
205
            // Initialize Guzzle client
206
            $client = new Client;
×
207

208
            // Define the headers
209
            $headers = [
×
210
                'Authorization' => 'Bearer '.$this->credentials['token'],
×
211
                'Content-Type' => 'application/json',
×
212
            ];
×
213

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

217
            $response = $client->send($request);
×
218

219
            // Get the response body
220
            $body = $response->getBody()->getContents();
×
221

222
            // Decode the response body
223
            $arrayResponse = json_decode($body, true);
×
224

225
            // Check if the order creation was successful
226
            if ($arrayResponse['success'] === false) {
×
227
                throw new CreateOrderException('Create Order failed: '.$arrayResponse['message']);
×
228
            }
229

230
            // Return the order response
231
            return $arrayResponse;
×
232

233
        } catch (GuzzleException $guzzleException) {
×
234
            // Handle exceptions
235
            throw new HttpException($guzzleException->getMessage());
×
236
        }
237
    }
238

239
    /**
240
     * {@inheritdoc}
241
     */
242
    public function orderLabel(string $orderId): array
243
    {
244
        try {
245
            // Initialize Guzzle client
246
            $client = new Client(['http_errors' => false]);
×
247

248
            // Define the headers
249
            $headers = [
×
250
                'Authorization' => 'Bearer '.$this->credentials['token'],
×
251
            ];
×
252

253
            // Make the GET request
254
            $response = $client->request('GET', static::apiDomain().'api/v1/get/order/label?tracking='.$orderId, [
×
255
                'headers' => $headers,
×
256
                'Content-Type' => 'application/json',
×
257
            ]);
×
258

259
            // Check if the request was successful
260
            if ($response->getStatusCode() !== 200) {
×
261
                // Check if the request failed because the tracking ID was not found
262
                if ($response->getStatusCode() === 422) {
×
263
                    throw new TrackingIdNotFoundException('Tracking ID not found in Ecotrack.');
×
264
                }
265

266
                // Handle any other error
267
                throw new HttpException('Failed to retrieve label for order with tracking ID '.$orderId);
×
268
            }
269

270
            // Get the response body
271
            $label = $response->getBody()->getContents();
×
272

273
            if ($label === '' || $label === '0') {
×
274
                throw new HttpException('Failed to retrieve label for order with tracking ID '.$orderId.' - Empty response from Ecotrack');
×
275
            }
276

277
            $base64data = base64_encode($label);
×
278

279
            if ($base64data === '') {
×
280
                throw new \RuntimeException('Unexpected empty base64 string');
×
281
            }
282

283
            // Return the label details
284
            return [
×
285
                'type' => 'pdf',
×
286
                'data' => $base64data,
×
287
            ];
×
288

289
        } catch (GuzzleException $guzzleException) {
×
290
            // Handle exceptions
291
            throw new HttpException($guzzleException->getMessage());
×
292
        }
293
    }
294

295
    /**
296
     * Get order details
297
     *
298
     * @throws NotImplementedException
299
     */
300
    public function getOrder(string $trackingId): array
301
    {
302
        throw new NotImplementedException('Not implemented');
×
303
    }
304
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc