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

PiteurStudio / CourierDZ / 13101535973

02 Feb 2025 06:48PM UTC coverage: 26.042%. First build
13101535973

Pull #9

github

web-flow
Merge a8aadf6dd into 4fe37b9d1
Pull Request #9: improve composer test scripts

1 of 23 new or added lines in 5 files covered. (4.35%)

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
namespace CourierDZ\ProviderIntegrations;
4

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

16
abstract class EcotrackProviderIntegration implements ShippingProviderContract
17
{
18
    use ShippingProviderValidation;
19

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

27
    /**
28
     * Validation rules for creating an order
29
     *
30
     * @var array<non-empty-string, non-empty-string>
31
     */
32
    public array $getCreateOrderValidationRules = [
33
        'reference' => 'nullable|string|max:255',
34
        'nom_client' => 'required|string|max:255',
35
        'telephone' => 'required|numeric|digits_between:9,10',
36
        'telephone_2' => 'nullable|numeric|digits_between:9,10',
37
        'adresse' => 'required|string|max:255',
38
        'code_postal' => 'nullable|numeric',
39
        'commune' => 'required|string|max:255',
40
        'code_wilaya' => 'required|numeric|min:1|max:58',
41
        'montant' => 'required|numeric',
42
        'remarque' => 'nullable|string|max:255',
43
        'produit' => 'nullable|string|max:255',
44
        'stock' => 'integer|in:0,1',
45
        'quantite' => 'required_if:stock,1|integer|min:1',
46
        'produit_a_recupere' => 'nullable|string|max:255',
47
        'boutique' => 'nullable|string|max:255',
48
        '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**
49
        'stop_desk' => 'nullable|in:0,1',
50
    ];
51

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

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

67
        $this->credentials = $credentials;
×
68
    }
69

70
    abstract public static function metadata(): array;
71

72
    abstract public static function apiDomain(): string;
73

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

92
            // Define the headers
93
            $headers = [
×
94
                'Authorization' => "Bearer {$this->credentials['token']}",
×
95
            ];
×
96

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

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

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

127
            // Define the headers
128
            $headers = [
×
129
                'Authorization' => "Bearer {$this->credentials['token']}",
×
130
            ];
×
131

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

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

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

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

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

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

160
        } catch (GuzzleException $e) {
×
161
            // Handle exceptions
162
            throw new HttpException($e->getMessage());
×
163
        }
164
    }
165

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

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

179
        // Prepare the request body
180
        $data = $orderData;
×
181

182
        $requestBody = json_encode($data, JSON_UNESCAPED_UNICODE);
×
183

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

188
        try {
189
            // Initialize Guzzle client
190
            $client = new Client;
×
191

192
            // Define the headers
193
            $headers = [
×
194
                'Authorization' => "Bearer {$this->credentials['token']}",
×
195
                'Content-Type' => 'application/json',
×
196
            ];
×
197

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

201
            $response = $client->send($request);
×
202

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

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

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

214
            // Return the order response
215
            return $arrayResponse;
×
216

217
        } catch (GuzzleException $e) {
×
218
            // Handle exceptions
219
            throw new HttpException($e->getMessage());
×
220
        }
221
    }
222

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

232
            // Define the headers
233
            $headers = [
×
234
                'Authorization' => "Bearer {$this->credentials['token']}",
×
235
            ];
×
236

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

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

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

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

257
            if (empty($label)) {
×
258
                throw new HttpException('Failed to retrieve label for order with tracking ID '.$orderId.' - Empty response from Ecotrack');
×
259
            }
260

261
            $base64data = base64_encode($label);
×
262

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

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

273
        } catch (GuzzleException $e) {
×
274
            // Handle exceptions
275
            throw new HttpException($e->getMessage());
×
276
        }
277
    }
278

279
    /**
280
     * Get order details
281
     *
282
     * @throws NotImplementedException
283
     */
284
    public function getOrder(string $trackingId): array
285
    {
286
        throw new NotImplementedException('Not implemented');
×
287
    }
288
}
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