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

PiteurStudio / CourierDZ / 13145102676

04 Feb 2025 09:23PM UTC coverage: 22.124% (-3.9%) from 26.042%
13145102676

push

github

web-flow
Merge pull request #11 from n4ss1m/feature_maystro_delivery

features: support more methods for Maystro Delivery

1 of 76 new or added lines in 1 file covered. (1.32%)

100 of 452 relevant lines covered (22.12%)

2.91 hits per line

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

9.71
/src/ShippingProviders/MaystroDeliveryProvider.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace CourierDZ\ShippingProviders;
6

7
use CourierDZ\Contracts\ShippingProviderContract;
8
use CourierDZ\Exceptions\CredentialsException;
9
use CourierDZ\Exceptions\HttpException;
10
use CourierDZ\Exceptions\NotImplementedException;
11
use CourierDZ\Support\ShippingProviderValidation;
12
use GuzzleHttp\Client;
13
use GuzzleHttp\Exception\GuzzleException;
14

15
class MaystroDeliveryProvider implements ShippingProviderContract
16
{
17
    use ShippingProviderValidation;
18

19
    /**
20
     * Provider credentials
21
     */
22
    protected array $credentials;
23

24
    /**
25
     * Validation rules for creating an order
26
     *
27
     * @var array<non-empty-string, non-empty-string>
28
     */
29
    public array $getCreateOrderValidationRules = [
30
        'wilaya' => 'required|integer|min:1|max:58',
31
        'commune' => 'required|integer|min:1',
32
        'destination_text' => 'nullable|string|max:255',
33
        'customer_phone' => 'required|numeric|digits_between:9,10',
34
        'customer_name' => 'required|string|max:255',
35
        'product_price' => 'required|integer',
36
        'delivery_type' => 'required|integer|in:0,1', // 0 = Livraison à domicile , 1 = Point de retrait
37
        'express' => 'boolean',
38
        'note_to_driver' => 'nullable|string|max:255',
39
        'products' => 'required|array',
40
        'source' => 'required|equals:4',
41
        'external_order_id' => 'nullable|string|max:255',
42
    ];
43

44
    /**
45
     * Constructor
46
     *
47
     * @throws CredentialsException
48
     */
49
    public function __construct(array $credentials)
50
    {
51
        // Get the provider name from the metadata
52
        $provider_name = static::metadata()['name'];
×
53

54
        // Check if the credentials are valid
55
        if (! isset($credentials['token'])) {
×
56
            throw new CredentialsException($provider_name.' credentials must "token".');
×
57
        }
58

59
        // Set the credentials
60
        $this->credentials = $credentials;
×
61
    }
62

63
    /**
64
     * The metadata for the provider.
65
     */
66
    public static function metadata(): array
67
    {
68
        return [
12✔
69
            'name' => 'MaystroDelivery',
12✔
70
            'title' => 'Maystro Delivery',
12✔
71
            'logo' => 'https://maystro-delivery.com/img/Maystro-blue-extonly.svg',
12✔
72
            'description' => 'Maystro Delivery société de livraison en Algérie offre un service de livraison rapide et sécurisé .',
12✔
73
            'website' => 'https://maystro-delivery.com/',
12✔
74
            'api_docs' => 'https://maystro.gitbook.io/maystro-delivery-documentation',
12✔
75
            'support' => 'https://maystro-delivery.com/ContactUS.html',
12✔
76
            'tracking_url' => 'https://maystro-delivery.com/trackingSD.html',
12✔
77
        ];
12✔
78
    }
79

80
    public static function apiDomain(): string
81
    {
NEW
82
        return 'https://backend.maystro-delivery.com/api/';
×
83
    }
84

85
    /**
86
     * Test the credentials
87
     *
88
     * This method tests the credentials by making a GET request
89
     * to the Maystro Delivery API to retrieve the list of wilayas.
90
     *
91
     * If the request is successful, the method returns true.
92
     * If the request returns a 401 or 403 status code, the method returns false.
93
     * If the request returns any other status code, the method throws an HttpException.
94
     *
95
     * @throws HttpException If the request fails
96
     */
97
    public function testCredentials(): bool
98
    {
99
        try {
100
            // Initialize Guzzle client
101
            $client = new Client(['http_errors' => false]);
×
102

103
            // Define the headers
104
            $headers = [
×
105
                'Authorization' => 'Token '.$this->credentials['token'],
×
106
            ];
×
107

108
            // Make the GET request
NEW
109
            $response = $client->request('GET', static::apiDomain().'base/wilayas/?country=1', [
×
110
                'headers' => $headers,
×
111
                'Content-Type' => 'application/json',
×
112
            ]);
×
113

114
            // Check the status code
115
            return match ($response->getStatusCode()) {
×
116
                // If the request is successful, return true
NEW
117
                200, 201 => true,
×
118
                // If the request returns a 401 status code, return false
NEW
119
                401 => false,
×
120
                // If the request returns any other status code, throw an HttpException
121
                default => throw new HttpException(static::metadata()['name'].', Unexpected error occurred.'),
×
122
            };
×
123
        } catch (GuzzleException $guzzleException) {
×
124
            // Handle exceptions
125
            throw new HttpException($guzzleException->getMessage());
×
126
        }
127
    }
128

129
    /**
130
     * {@inheritdoc}
131
     */
132
    public function getRates(?int $from_wilaya_id, ?int $to_wilaya_id): array
133
    {
134
        throw new NotImplementedException('Not implemented');
×
135
    }
136

137
    public function getCreateOrderValidationRules(): array
138
    {
139
        return $this->getCreateOrderValidationRules;
×
140
    }
141

142
    public function createProduct(string $store_id, string $logistical_description, ?string $product_id): array
143
    {
NEW
144
        $productData = [
×
NEW
145
            'store_id' => $store_id,
×
NEW
146
            'logistical_description' => $logistical_description,
×
NEW
147
        ];
×
148

NEW
149
        if ($product_id !== null && $product_id !== '' && $product_id !== '0') {
×
NEW
150
            $productData['product_id'] = $product_id;
×
151
        }
152

153
        try {
154
            // Initialize Guzzle client
NEW
155
            $client = new Client(['http_errors' => false]);
×
156

157
            // Define the headers
NEW
158
            $headers = [
×
NEW
159
                'Authorization' => 'Token '.$this->credentials['token'],
×
NEW
160
            ];
×
161

162
            // Make the GET request
NEW
163
            $response = $client->request('POST', static::apiDomain().'stores/product/', [
×
NEW
164
                'headers' => $headers,
×
NEW
165
                'body' => $productData,
×
NEW
166
            ]);
×
167

NEW
168
            if ($response->getStatusCode() == 200) {
×
NEW
169
                return json_decode($response->getBody()->getContents(), true);
×
170
            }
171

NEW
172
            throw new HttpException(static::metadata()['name'].', Unexpected error occurred.');
×
NEW
173
        } catch (GuzzleException $guzzleException) {
×
174
            // Handle exceptions
NEW
175
            throw new HttpException($guzzleException->getMessage());
×
176
        }
177
    }
178

179
    /**
180
     * {@inheritdoc}
181
     */
182
    public function createOrder(array $orderData): array
183
    {
184
        // Validate the order data
NEW
185
        $this->validateCreate($orderData);
×
186

187
        try {
188
            // Initialize Guzzle client
NEW
189
            $client = new Client(['http_errors' => false]);
×
190

191
            // Define the headers
NEW
192
            $headers = [
×
NEW
193
                'Authorization' => 'Token '.$this->credentials['token'],
×
NEW
194
            ];
×
195

196
            // Make the GET request
NEW
197
            $response = $client->request('POST', static::apiDomain().'stores/orders/', [
×
NEW
198
                'headers' => $headers,
×
NEW
199
                'body' => $orderData,
×
NEW
200
            ]);
×
201

NEW
202
            if (in_array($response->getStatusCode(), [200, 201])) {
×
NEW
203
                return json_decode($response->getBody()->getContents(), true);
×
204
            }
205

NEW
206
            throw new HttpException(static::metadata()['name'].', Unexpected error occurred.');
×
NEW
207
        } catch (GuzzleException $guzzleException) {
×
208
            // Handle exceptions
NEW
209
            throw new HttpException($guzzleException->getMessage());
×
210
        }
211
    }
212

213
    /**
214
     * {@inheritdoc}
215
     */
216
    public function getOrder(string $trackingId): array
217
    {
NEW
218
        $orderId = $trackingId;
×
219

220
        try {
221
            // Initialize Guzzle client
NEW
222
            $client = new Client(['http_errors' => false]);
×
223

224
            // Define the headers
NEW
225
            $headers = [
×
NEW
226
                'Authorization' => 'Token '.$this->credentials['token'],
×
NEW
227
            ];
×
228

229
            // Make the GET request
NEW
230
            $response = $client->request('GET', static::apiDomain().'stores/orders/'.$orderId.'/', [
×
NEW
231
                'headers' => $headers,
×
NEW
232
            ]);
×
233

NEW
234
            if (in_array($response->getStatusCode(), [200, 201])) {
×
NEW
235
                return json_decode($response->getBody()->getContents(), true);
×
236
            }
237

NEW
238
            throw new HttpException(static::metadata()['name'].', Unexpected error occurred.');
×
NEW
239
        } catch (GuzzleException $guzzleException) {
×
240
            // Handle exceptions
NEW
241
            throw new HttpException($guzzleException->getMessage());
×
242
        }
243
    }
244

245
    /**
246
     * {@inheritdoc}
247
     */
248
    public function orderLabel(string $orderId): array
249
    {
250
        try {
251
            // Initialize Guzzle client
NEW
252
            $client = new Client(['http_errors' => false]);
×
253

254
            // Define the headers
NEW
255
            $headers = [
×
NEW
256
                'Authorization' => 'Token '.$this->credentials['token'],
×
NEW
257
            ];
×
258

259
            // Make the GET request
NEW
260
            $response = $client->request('POST', static::apiDomain().'delivery/starter/starter_bordureau/', [
×
NEW
261
                'headers' => $headers,
×
NEW
262
                'body' => [
×
NEW
263
                    'all_created' => true,
×
NEW
264
                    'orders_ids' => [$orderId],
×
NEW
265
                ],
×
NEW
266
            ]);
×
267

NEW
268
            if (in_array($response->getStatusCode(), [200, 201])) {
×
269

NEW
270
                $label = $response->getBody()->getContents();
×
271

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

NEW
276
                $base64data = base64_encode($label);
×
277

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

NEW
282
                return [
×
NEW
283
                    'type' => 'pdf',
×
NEW
284
                    'data' => $base64data,
×
NEW
285
                ];
×
286
            }
287

NEW
288
            throw new HttpException(static::metadata()['name'].', Unexpected error occurred.');
×
NEW
289
        } catch (GuzzleException $guzzleException) {
×
290
            // Handle exceptions
NEW
291
            throw new HttpException($guzzleException->getMessage());
×
292
        }
293
    }
294
}
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