|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* |
|
4
|
|
|
* This file is part of the Sylius package. |
|
5
|
|
|
* |
|
6
|
|
|
* (c) Paweł Jędrzejewski |
|
7
|
|
|
* |
|
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
9
|
|
|
* file that was distributed with this source code. |
|
10
|
|
|
*/ |
|
11
|
|
|
|
|
12
|
|
|
namespace Sylius\Behat\Page\Shop\Checkout; |
|
13
|
|
|
|
|
14
|
|
|
use Behat\Mink\Session; |
|
15
|
|
|
use Behat\Mink\Element\NodeElement; |
|
16
|
|
|
use Sylius\Behat\Page\SymfonyPage; |
|
17
|
|
|
use Sylius\Behat\Service\Accessor\TableAccessorInterface; |
|
18
|
|
|
use Sylius\Component\Core\Model\AddressInterface; |
|
19
|
|
|
use Sylius\Component\Core\Model\ShippingMethodInterface; |
|
20
|
|
|
use Sylius\Component\Payment\Model\PaymentMethodInterface; |
|
21
|
|
|
use Sylius\Component\Core\Model\ProductInterface; |
|
22
|
|
|
use Symfony\Component\Intl\Intl; |
|
23
|
|
|
use Symfony\Component\Routing\RouterInterface; |
|
24
|
|
|
|
|
25
|
|
|
/** |
|
26
|
|
|
* @author Mateusz Zalewski <[email protected]> |
|
27
|
|
|
*/ |
|
28
|
|
|
class SummaryPage extends SymfonyPage implements SummaryPageInterface |
|
29
|
|
|
{ |
|
30
|
|
|
/** |
|
31
|
|
|
* @var TableAccessorInterface |
|
32
|
|
|
*/ |
|
33
|
|
|
private $tableAccessor; |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* @param Session $session |
|
37
|
|
|
* @param array $parameters |
|
38
|
|
|
* @param RouterInterface $router |
|
39
|
|
|
* @param TableAccessorInterface $tableAccessor |
|
40
|
|
|
*/ |
|
41
|
|
|
public function __construct( |
|
42
|
|
|
Session $session, |
|
43
|
|
|
array $parameters, |
|
44
|
|
|
RouterInterface $router, |
|
45
|
|
|
TableAccessorInterface $tableAccessor |
|
46
|
|
|
) { |
|
47
|
|
|
parent::__construct($session, $parameters, $router); |
|
48
|
|
|
|
|
49
|
|
|
$this->tableAccessor = $tableAccessor; |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* {@inheritdoc} |
|
55
|
|
|
*/ |
|
56
|
|
|
public function getRouteName() |
|
57
|
|
|
{ |
|
58
|
|
|
return 'sylius_shop_checkout_summary'; |
|
59
|
|
|
} |
|
60
|
|
|
|
|
61
|
|
|
/** |
|
62
|
|
|
* {@inheritdoc} |
|
63
|
|
|
*/ |
|
64
|
|
View Code Duplication |
public function hasItemWithProductAndQuantity($productName, $quantity) |
|
|
|
|
|
|
65
|
|
|
{ |
|
66
|
|
|
$table = $this->getElement('items_table'); |
|
67
|
|
|
|
|
68
|
|
|
try { |
|
69
|
|
|
$this->tableAccessor->getRowWithFields($table, ['item' => $productName, 'qty' => $quantity]); |
|
70
|
|
|
} catch (\InvalidArgumentException $exception) { |
|
71
|
|
|
return false; |
|
72
|
|
|
} |
|
73
|
|
|
|
|
74
|
|
|
return true; |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
/** |
|
78
|
|
|
* {@inheritdoc} |
|
79
|
|
|
*/ |
|
80
|
|
|
public function hasShippingAddress(AddressInterface $address) |
|
81
|
|
|
{ |
|
82
|
|
|
$shippingAddress = $this->getElement('shipping_address')->getText(); |
|
83
|
|
|
|
|
84
|
|
|
return $this->isAddressValid($shippingAddress, $address); |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* {@inheritdoc} |
|
89
|
|
|
*/ |
|
90
|
|
|
public function hasBillingAddress(AddressInterface $address) |
|
91
|
|
|
{ |
|
92
|
|
|
$billingAddress = $this->getElement('billing_address')->getText(); |
|
93
|
|
|
|
|
94
|
|
|
return $this->isAddressValid($billingAddress, $address); |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
/** |
|
98
|
|
|
* {@inheritdoc} |
|
99
|
|
|
*/ |
|
100
|
|
View Code Duplication |
public function hasShippingMethod(ShippingMethodInterface $shippingMethod) |
|
|
|
|
|
|
101
|
|
|
{ |
|
102
|
|
|
if (!$this->hasElement('shipping_method')) { |
|
103
|
|
|
return false; |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
return false !== strpos($this->getElement('shipping_method')->getText(), $shippingMethod->getName()); |
|
107
|
|
|
} |
|
108
|
|
|
|
|
109
|
|
|
/** |
|
110
|
|
|
* {@inheritdoc} |
|
111
|
|
|
*/ |
|
112
|
|
View Code Duplication |
public function hasPaymentMethod(PaymentMethodInterface $paymentMethod) |
|
|
|
|
|
|
113
|
|
|
{ |
|
114
|
|
|
if (!$this->hasElement('payment_method')) { |
|
115
|
|
|
return false; |
|
116
|
|
|
} |
|
117
|
|
|
|
|
118
|
|
|
return false !== strpos($this->getElement('payment_method')->getText(), $paymentMethod->getName()); |
|
119
|
|
|
} |
|
120
|
|
|
|
|
121
|
|
|
/** |
|
122
|
|
|
* {@inheritdoc} |
|
123
|
|
|
*/ |
|
124
|
|
|
public function hasProductDiscountedUnitPriceBy(ProductInterface $product, $amount) |
|
125
|
|
|
{ |
|
126
|
|
|
$productRowElement = $this->getProductRowElement($product); |
|
127
|
|
|
$discountedPriceElement = $productRowElement->find('css', 'td > s'); |
|
|
|
|
|
|
128
|
|
|
if (null === $discountedPriceElement) { |
|
129
|
|
|
return false; |
|
130
|
|
|
} |
|
131
|
|
|
$priceElement = $discountedPriceElement->getParent(); |
|
132
|
|
|
$prices = explode(' ', $priceElement->getText()); |
|
133
|
|
|
$priceWithoutDiscount = $this->getPriceFromString($prices[0]); |
|
134
|
|
|
$priceWithDiscount = $this->getPriceFromString($prices[1]); |
|
135
|
|
|
$discount = $priceWithoutDiscount - $priceWithDiscount; |
|
136
|
|
|
|
|
137
|
|
|
return $discount === $amount; |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
|
|
/** |
|
141
|
|
|
* {@inheritdoc} |
|
142
|
|
|
*/ |
|
143
|
|
|
public function hasOrderTotal($total) |
|
144
|
|
|
{ |
|
145
|
|
|
if (!$this->hasElement('order_total')) { |
|
146
|
|
|
return false; |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
return $this->getTotalFromString($this->getElement('order_total')->getText()) === $total; |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
/** |
|
153
|
|
|
* {@inheritdoc} |
|
154
|
|
|
*/ |
|
155
|
|
|
public function addNotes($notes) |
|
156
|
|
|
{ |
|
157
|
|
|
$this->getElement('extra_notes')->setValue($notes); |
|
158
|
|
|
} |
|
159
|
|
|
|
|
160
|
|
|
/** |
|
161
|
|
|
* {@inheritdoc} |
|
162
|
|
|
*/ |
|
163
|
|
|
public function hasPromotionTotal($promotionTotal) |
|
164
|
|
|
{ |
|
165
|
|
|
return false !== strpos($this->getElement('promotion_total')->getText(), $promotionTotal); |
|
166
|
|
|
} |
|
167
|
|
|
|
|
168
|
|
|
/** |
|
169
|
|
|
* {@inheritdoc} |
|
170
|
|
|
*/ |
|
171
|
|
|
public function hasPromotion($promotionName) |
|
172
|
|
|
{ |
|
173
|
|
|
return false !== stripos($this->getElement('promotion_discounts')->getText(), $promotionName); |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
/** |
|
177
|
|
|
* {@inheritdoc} |
|
178
|
|
|
*/ |
|
179
|
|
|
public function hasTaxTotal($taxTotal) |
|
180
|
|
|
{ |
|
181
|
|
|
return false !== strpos($this->getElement('tax_total')->getText(), $taxTotal); |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
/** |
|
185
|
|
|
* {@inheritdoc} |
|
186
|
|
|
*/ |
|
187
|
|
|
public function hasShippingTotal($price) |
|
188
|
|
|
{ |
|
189
|
|
|
return false !== strpos($this->getElement('shipping_total')->getText(), $price); |
|
190
|
|
|
} |
|
191
|
|
|
|
|
192
|
|
|
/** |
|
193
|
|
|
* {@inheritdoc} |
|
194
|
|
|
*/ |
|
195
|
|
|
protected function getDefinedElements() |
|
196
|
|
|
{ |
|
197
|
|
|
return array_merge(parent::getDefinedElements(), [ |
|
198
|
|
|
'billing_address' => '#addresses div:contains("Billing address") address', |
|
199
|
|
|
'extra_notes' =>'#sylius_checkout_summary_notes', |
|
200
|
|
|
'shipping_address' => '#addresses div:contains("Shipping address") address', |
|
201
|
|
|
'items_table' => '#items table', |
|
202
|
|
|
'shipping_method' => '#sylius-checkout-summary-shipping-method', |
|
203
|
|
|
'payment_method' => '#sylius-checkout-summary-payment-method', |
|
204
|
|
|
'product_row' => 'tbody tr:contains("%name%")', |
|
205
|
|
|
'order_total' => 'td:contains("Total")', |
|
206
|
|
|
'promotion_total' => '#promotion-total', |
|
207
|
|
|
'promotion_discounts' => '#promotion-discounts', |
|
208
|
|
|
'tax_total' => '#tax-total', |
|
209
|
|
|
'shipping_total' => '#shipping-total', |
|
210
|
|
|
]); |
|
211
|
|
|
} |
|
212
|
|
|
|
|
213
|
|
|
/** |
|
214
|
|
|
* @param ProductInterface $product |
|
215
|
|
|
* |
|
216
|
|
|
* @return NodeElement |
|
217
|
|
|
*/ |
|
218
|
|
|
private function getProductRowElement(ProductInterface $product) |
|
219
|
|
|
{ |
|
220
|
|
|
return $this->getElement('product_row', ['%name%' => $product->getName()]); |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
/** |
|
224
|
|
|
* @param string $displayedAddress |
|
225
|
|
|
* @param AddressInterface $address |
|
226
|
|
|
* |
|
227
|
|
|
* @return bool |
|
228
|
|
|
*/ |
|
229
|
|
|
private function isAddressValid($displayedAddress, AddressInterface $address) |
|
230
|
|
|
{ |
|
231
|
|
|
return |
|
232
|
|
|
$this->hasAddressPart($displayedAddress, $address->getCompany(), true) && |
|
233
|
|
|
$this->hasAddressPart($displayedAddress, $address->getFirstName()) && |
|
234
|
|
|
$this->hasAddressPart($displayedAddress, $address->getLastName()) && |
|
235
|
|
|
$this->hasAddressPart($displayedAddress, $address->getPhoneNumber(), true) && |
|
236
|
|
|
$this->hasAddressPart($displayedAddress, $address->getStreet()) && |
|
237
|
|
|
$this->hasAddressPart($displayedAddress, $address->getCity()) && |
|
238
|
|
|
$this->hasAddressPart($displayedAddress, $address->getProvinceCode(), true) && |
|
239
|
|
|
$this->hasAddressPart($displayedAddress, $this->getCountryName($address->getCountryCode())) && |
|
240
|
|
|
$this->hasAddressPart($displayedAddress, $address->getPostcode()) |
|
241
|
|
|
; |
|
242
|
|
|
} |
|
243
|
|
|
|
|
244
|
|
|
/** |
|
245
|
|
|
* @param string $address |
|
246
|
|
|
* @param string $addressPart |
|
247
|
|
|
* |
|
248
|
|
|
* @return bool |
|
249
|
|
|
*/ |
|
250
|
|
|
private function hasAddressPart($address, $addressPart, $optional = false) |
|
251
|
|
|
{ |
|
252
|
|
|
if ($optional && null === $addressPart) { |
|
253
|
|
|
return true; |
|
254
|
|
|
} |
|
255
|
|
|
|
|
256
|
|
|
return false !== strpos($address, $addressPart); |
|
257
|
|
|
} |
|
258
|
|
|
|
|
259
|
|
|
/** |
|
260
|
|
|
* @param string $countryCode |
|
261
|
|
|
* |
|
262
|
|
|
* @return string |
|
263
|
|
|
*/ |
|
264
|
|
|
private function getCountryName($countryCode) |
|
265
|
|
|
{ |
|
266
|
|
|
return strtoupper(Intl::getRegionBundle()->getCountryName($countryCode, 'en')); |
|
267
|
|
|
} |
|
268
|
|
|
|
|
269
|
|
|
/** |
|
270
|
|
|
* @param string $price |
|
271
|
|
|
* |
|
272
|
|
|
* @return int |
|
273
|
|
|
*/ |
|
274
|
|
|
private function getPriceFromString($price) |
|
275
|
|
|
{ |
|
276
|
|
|
return (int) round((str_replace(['€', '£', '$'], '', $price) * 100), 2); |
|
277
|
|
|
} |
|
278
|
|
|
|
|
279
|
|
|
/** |
|
280
|
|
|
* @param string $total |
|
281
|
|
|
* |
|
282
|
|
|
* @return int |
|
283
|
|
|
*/ |
|
284
|
|
|
private function getTotalFromString($total) |
|
285
|
|
|
{ |
|
286
|
|
|
$total = str_replace('Total:', '', $total); |
|
287
|
|
|
|
|
288
|
|
|
return $this->getPriceFromString($total); |
|
289
|
|
|
} |
|
290
|
|
|
} |
|
291
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.