Skip to content
This repository was archived by the owner on Feb 2, 2018. It is now read-only.

Commit 966fa7c

Browse files
committed
Assert the customer has given all its information before placing an order
1 parent 75ceb2f commit 966fa7c

File tree

7 files changed

+107
-79
lines changed

7 files changed

+107
-79
lines changed

app/Customers/Entities/Customer.php

+23-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Groupeat\Orders\Entities\Order;
88
use Groupeat\Support\Entities\Abstracts\Entity;
99
use Groupeat\Support\Entities\Traits\HasPhoneNumber;
10+
use Groupeat\Support\Exceptions\Forbidden;
1011
use Groupeat\Support\Values\PhoneNumber;
1112
use Illuminate\Database\Eloquent\SoftDeletes;
1213

@@ -34,7 +35,7 @@ public function getRules()
3435
*
3536
* @return static
3637
*/
37-
public static function addExternalCustomer($firstName, $lastName, PhoneNumber $phoneNumber = null)
38+
public static function addExternalCustomer($firstName, $lastName, PhoneNumber $phoneNumber)
3839
{
3940
$customer = new static;
4041
$customer->isExternal = true;
@@ -55,4 +56,25 @@ public function isActivated()
5556
{
5657
return $this->isExternal ? true : $this->isActivatedThroughCredentials();
5758
}
59+
60+
public function getMissingAttributes()
61+
{
62+
return collect(['firstName', 'lastName', 'phoneNumber'])->filter(function ($attribute) {
63+
return empty($this->$attribute);
64+
})->all();
65+
}
66+
67+
public function assertNoMissingInformation()
68+
{
69+
$missingAttributes = $this->getMissingAttributes();
70+
71+
if (!empty($missingAttributes)) {
72+
$str = implode(', ', $missingAttributes);
73+
74+
throw new Forbidden(
75+
'missingCustomerInformation',
76+
"The attributes [$str] are missing for customer {$this->toShortString()}"
77+
);
78+
}
79+
}
5880
}

app/Orders/Entities/GroupOrder.php

+1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ public function addOrder(
130130
$comment = null
131131
) {
132132
$customer->assertActivated("The {$customer->toShortString()} should be activated to place an order.");
133+
$customer->assertNoMissingInformation();
133134
list($nbProductFormats, $totalRawPrice) = $this->getNbProductFormatsAndRawPriceWith($productFormats);
134135
$this->assertMaximumCapacityNotExceeded($nbProductFormats);
135136
$this->discountRate = $productFormats->getRestaurant()->getDiscountRateFor($totalRawPrice);

app/Orders/Http/V1/Traits/CanAddOrder.php

+17
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,31 @@
22
namespace Groupeat\Orders\Http\V1\Traits;
33

44
use Closure;
5+
use Groupeat\Support\Exceptions\BadRequest;
56
use Symfony\Component\HttpFoundation\Response;
67

78
trait CanAddOrder
89
{
910
protected function addOrder(Closure $getCommandCallback)
1011
{
1112
$productFormats = $this->json('productFormats');
13+
14+
if (empty($productFormats)) {
15+
throw new BadRequest(
16+
'missingProductFormats',
17+
"The product formats object is required to place an order"
18+
);
19+
}
20+
1221
$deliveryAddressData = $this->json('deliveryAddress');
22+
23+
if (empty($deliveryAddressData)) {
24+
throw new BadRequest(
25+
'missingDeliveryAddress',
26+
"The delivery address object is required to place an order"
27+
);
28+
}
29+
1330
$comment = $this->json('comment');
1431

1532
$command = $getCommandCallback($productFormats, $deliveryAddressData, $comment);

app/Orders/docs/main.md

+21
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,34 @@ The distance between the given address and the restaurant must be less than {{ r
9595
+ Response 201
9696

9797
[Order][]
98+
99+
+ Response 400
100+
101+
{
102+
"errorKey": "missingProductFormats",
103+
"message": "The product formats object is required to place an order"
104+
}
105+
106+
+ Response 400
107+
108+
{
109+
"errorKey": "missingDeliveryAddress",
110+
"message": "The delivery address object is required to place an order"
111+
}
98112

99113
+ Response 403
100114

101115
{
102116
"errorKey": "userShouldBeActivated",
103117
"message": "The customer #26 should be activated to place an order."
104118
}
119+
120+
+ Response 403
121+
122+
{
123+
"errorKey": "missingCustomerInformation",
124+
"message": "The attributes [firstName, lastName, phoneNumber] are missing for customer customer #35"
125+
}
105126

106127
+ Response 404
107128

tests/_support/ApiHelper.php

+13-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ public function amAnActivatedCustomer()
1515
return [$token, $id];
1616
}
1717

18+
public function amAnActivatedCustomerWithNoMissingInformation()
19+
{
20+
list($token, $id) = $this->amAnActivatedCustomer();
21+
$this->sendApiPutWithToken($token, "customers/$id", [
22+
'firstName' => 'Jean',
23+
'lastName' => 'Jacques',
24+
'phoneNumber' => '33605040302',
25+
]);
26+
27+
return [$token, $id];
28+
}
29+
1830
public function amAlloPizzaRestaurant()
1931
{
2032
$this->sendApiPut('auth/token', ['email' => '[email protected]', 'password' => 'AlloPizza']);
@@ -43,7 +55,7 @@ public function sendRegistrationRequest(
4355

4456
public function createGroupOrder()
4557
{
46-
list($token, $customerId) = $this->amAnActivatedCustomer();
58+
list($token, $customerId) = $this->amAnActivatedCustomerWithNoMissingInformation();
4759

4860
$this->sendApiGetWithToken(
4961
$token,

tests/api/GroupOrdersCest.php

-48
Original file line numberDiff line numberDiff line change
@@ -92,52 +92,4 @@ public function testThatARestaurantCanListItsGroupOrder(ApiTester $I)
9292
list($customerToken, $customerId) = $I->amAnActivatedCustomer();
9393
$I->sendApiGetWithToken($customerToken, 'restaurants?opened=1&around=1&latitude=48.855118&longitude=2.345730');
9494
}
95-
96-
public function createGroupOrder(ApiTester $I)
97-
{
98-
list($token, $customerId) = $I->amAnActivatedCustomer();
99-
100-
$I->sendApiGetWithToken(
101-
$token,
102-
'groupOrders?joinable=1&around=1&latitude=48.716941&longitude=2.239171&include=restaurant'
103-
);
104-
$groupOrders = $I->grabDataFromResponse('');
105-
106-
if (!empty($groupOrders)) {
107-
$groupOrderId = $groupOrders[0]['id'];
108-
$restaurantId = $groupOrders[0]['restaurant']['data']['id'];
109-
} else {
110-
$groupOrderId = null;
111-
$I->sendApiGetWithToken($token, 'restaurants?opened=1&around=1&latitude=48.716941&longitude=2.239171');
112-
$restaurants = $I->grabDataFromResponse();
113-
$restaurantId = $restaurants[0]['id'];
114-
}
115-
116-
$I->sendApiGetWithToken($token, "restaurants/$restaurantId");
117-
$restaurantCapacity = $I->grabDataFromResponse('deliveryCapacity');
118-
$I->assertGreaterThan(1, $restaurantCapacity);
119-
$I->sendApiGetWithToken($token, "restaurants/$restaurantId/products?include=formats");
120-
$productFormatId = last(last($I->grabDataFromResponse())['formats']['data'])['id'];
121-
$productFormats = [$productFormatId => 1];
122-
123-
$orderDetails = [
124-
'foodRushDurationInMinutes' => 30,
125-
'productFormats' => $productFormats,
126-
'deliveryAddress' => [
127-
'street' => "Allée des techniques avancées",
128-
'details' => "Bâtiment A, chambre 200",
129-
'latitude' => 48.716941,
130-
'longitude' => 2.239171,
131-
],
132-
];
133-
134-
if (!is_null($groupOrderId)) {
135-
$orderDetails['groupOrderId'] = $groupOrderId;
136-
}
137-
138-
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
139-
$orderId = $I->grabDataFromResponse('id');
140-
141-
return [$token, $orderId, $restaurantCapacity, $orderDetails, $customerId];
142-
}
14395
}

tests/api/OrdersCest.php

+32-29
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
class OrdersCest
44
{
5-
public function testThatACustomerShouldBeActivatedToPlaceAnOrder(ApiTester $I)
5+
public function testThatACustomerShouldBeActivatedAndHaveNoMissingInformationToPlaceAnOrder(ApiTester $I)
66
{
77
list($token) = $I->sendRegistrationRequest();
88
$orderDetails = $this->getOrderDetails($I, $token);
@@ -12,14 +12,21 @@ public function testThatACustomerShouldBeActivatedToPlaceAnOrder(ApiTester $I)
1212

1313
list($token) = $I->amAnActivatedCustomer();
1414
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
15+
$I->seeErrorResponse(403, 'missingCustomerInformation');
16+
17+
list($token, $customerId) = $I->amAnActivatedCustomerWithNoMissingInformation();
18+
$I->sendApiPutWithToken($token, "customers/$customerId", [
19+
'firstName' => 'Jean',
20+
'lastName' => 'Jacques',
21+
'phoneNumber' => '33605040302',
22+
]);
23+
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
1524
$I->seeResponseCodeIs(201);
1625
}
1726

1827
public function testThatTheRestaurantReceiveAnEmailAndASmsWhenAnOrderIsPlaced(ApiTester $I)
1928
{
20-
list($token) = $I->amAnActivatedCustomer();
21-
$orderDetails = $this->getOrderDetails($I, $token);
22-
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
29+
list($token, $orderId, $restaurantCapacity, $orderDetails, $customerId) = $I->createGroupOrder();
2330
$productFormatId = array_keys($orderDetails['productFormats'])[0];
2431
$restaurantEmail = $this->getRestaurantEmailFromProductFormat($productFormatId);
2532
$I->assertSame('restaurants.orderHasBeenPlaced', $I->grabFirstMailId());
@@ -29,7 +36,7 @@ public function testThatTheRestaurantReceiveAnEmailAndASmsWhenAnOrderIsPlaced(Ap
2936

3037
public function testThatTheFoodRushDurationMustBeValid(ApiTester $I)
3138
{
32-
list($token) = $I->amAnActivatedCustomer();
39+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
3340
$orderDetails = $this->getOrderDetails($I, $token, ['foodRushDurationInMinutes' => 70]);
3441

3542
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
@@ -42,24 +49,20 @@ public function testThatTheFoodRushDurationMustBeValid(ApiTester $I)
4249

4350
public function testThatTheOrderCannotBeEmpty(ApiTester $I)
4451
{
45-
list($token) = $I->amAnActivatedCustomer();
46-
47-
$variants = [
48-
['productFormats' => []],
49-
['productFormats' => [1 => 0]],
50-
];
52+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
5153

52-
foreach ($variants as $variant) {
53-
$orderDetails = $this->getOrderDetails($I, $token, $variant);
54+
$orderDetails = $this->getOrderDetails($I, $token, ['productFormats' => []]);
55+
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
56+
$I->seeErrorResponse(400, 'missingProductFormats');
5457

55-
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
56-
$I->seeErrorResponse(422, 'noProductFormats');
57-
}
58+
$orderDetails = $this->getOrderDetails($I, $token, ['productFormats' => [1 => 0]]);
59+
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
60+
$I->seeErrorResponse(422, 'noProductFormats');
5861
}
5962

6063
public function testThatTheProductFormatsMustExist(ApiTester $I)
6164
{
62-
list($token) = $I->amAnActivatedCustomer();
65+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
6366
$orderDetails = $this->getOrderDetails($I, $token, ['productFormats' => [66666 => 1]]);
6467

6568
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
@@ -68,7 +71,7 @@ public function testThatTheProductFormatsMustExist(ApiTester $I)
6871

6972
public function testThatTheAnOrderCannotBePlacedOnAClosedRestaurant(ApiTester $I)
7073
{
71-
list($token) = $I->amAnActivatedCustomer();
74+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
7275
$products = $this->getProducts($I, $token, ['around' => true, 'opened' => false], function ($restaurants) {
7376
foreach ($restaurants as $restaurant) {
7477
if ($restaurant['name'] == 'Toujours fermé') {
@@ -85,7 +88,7 @@ public function testThatTheAnOrderCannotBePlacedOnAClosedRestaurant(ApiTester $I
8588

8689
public function testThatTheRestaurantMustBeCloseEnough(ApiTester $I)
8790
{
88-
list($token) = $I->amAnActivatedCustomer();
91+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
8992

9093
$latitude = 0;
9194
$longitude = 0;
@@ -117,7 +120,7 @@ function ($restaurants) use ($latitude, $longitude) {
117120

118121
public function testThatTheProductFormatsMustBelongToTheSameRestaurant(ApiTester $I)
119122
{
120-
list($token) = $I->amAnActivatedCustomer();
123+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
121124
$I->sendApiGetWithToken($token, 'restaurants');
122125

123126
foreach ($I->grabDataFromResponse() as $restaurant) {
@@ -148,7 +151,7 @@ function () use ($wrongRestaurantId) {
148151

149152
public function testThatTheGroupOrderMustExceedTheMinimumPrice(ApiTester $I)
150153
{
151-
list($token) = $I->amAnActivatedCustomer();
154+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
152155
$options = ['around' => true, 'opened' => true];
153156
$minimumPrice = 0;
154157

@@ -177,7 +180,7 @@ public function testThatTheGroupOrderMustExceedTheMinimumPrice(ApiTester $I)
177180

178181
public function testThatTheOrderShouldNotExceedRestaurantDeliveryCapacity(ApiTester $I)
179182
{
180-
list($token) = $I->amAnActivatedCustomer();
183+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
181184
$options = ['around' => true, 'opened' => true];
182185
$deliveryCapacity = 0;
183186

@@ -206,7 +209,7 @@ public function testThatTheOrderShouldNotExceedRestaurantDeliveryCapacity(ApiTes
206209

207210
public function testThatARestaurantCanHaveOnlyOneGroupOrderAtTheSameTime(ApiTester $I)
208211
{
209-
list($token) = $I->amAnActivatedCustomer();
212+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
210213
$orderDetails = $this->getOrderDetails($I, $token);
211214

212215
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
@@ -218,29 +221,29 @@ public function testThatARestaurantCanHaveOnlyOneGroupOrderAtTheSameTime(ApiTest
218221

219222
public function testThatGroupOrdersCanBeListed(ApiTester $I)
220223
{
221-
list($token) = $I->amAnActivatedCustomer();
224+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
222225
$I->sendApiGetWithToken($token, 'groupOrders');
223226
$I->seeResponseCodeIs(200);
224227
}
225228

226229
public function testThatAnOrderCanBeShownByTheCustomerWhoPlacedItOnly(ApiTester $I)
227230
{
228-
list($token) = $I->amAnActivatedCustomer();
231+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
229232
$orderDetails = $this->getOrderDetails($I, $token);
230233
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
231234
$orderId = $I->grabDataFromResponse('id');
232235
$I->sendApiGetWithToken($token, "orders/$orderId");
233236
$I->seeResponseCodeIs(200);
234237
$I->assertSame($orderId, $I->grabDataFromResponse('id'));
235238

236-
list($token2) = $I->amAnActivatedCustomer();
239+
list($token2) = $I->amAnActivatedCustomerWithNoMissingInformation();
237240
$I->sendApiGetWithToken($token2, "orders/$orderId");
238241
$I->seeErrorResponse(403, 'wrongAuthenticatedUser');
239242
}
240243

241244
public function testThatTheDiscountRateIncreaseWhenAGroupOrderIsJoined(ApiTester $I)
242245
{
243-
list($token) = $I->amAnActivatedCustomer();
246+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
244247
$orderDetails = $this->getOrderDetails($I, $token);
245248
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
246249
$orderId = $I->grabDataFromResponse('id');
@@ -279,7 +282,7 @@ public function testThatTheDiscountRateIncreaseWhenAGroupOrderIsJoined(ApiTester
279282

280283
public function testThatTheDeliveryAddressMustBeCloseEnoughToJoinAGroupOrder(ApiTester $I)
281284
{
282-
list($token) = $I->amAnActivatedCustomer();
285+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
283286
$orderDetails = $this->getOrderDetails($I, $token);
284287
$I->sendApiPostWithToken($token, 'orders', $orderDetails);
285288
$orderId = $I->grabDataFromResponse('id');
@@ -296,7 +299,7 @@ public function testThatTheDeliveryAddressMustBeCloseEnoughToJoinAGroupOrder(Api
296299

297300
public function testThatTheRestaurantCanSeeIfTheCustomerAttachedACommentToItsOrder(ApiTester $I)
298301
{
299-
list($token) = $I->amAnActivatedCustomer();
302+
list($token) = $I->amAnActivatedCustomerWithNoMissingInformation();
300303
$orderDetails = $this->getOrderDetails($I, $token);
301304
$comment = "Please add some meat to my vegan pizza...";
302305
$orderDetails['comment'] = $comment;

0 commit comments

Comments
 (0)