|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* (c) shopware AG <[email protected]> |
|
4
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
5
|
|
|
* file that was distributed with this source code. |
|
6
|
|
|
*/ |
|
7
|
|
|
|
|
8
|
|
|
namespace ShopwarePlugins\Connect\Components; |
|
9
|
|
|
|
|
10
|
|
|
use Enlight_Event_EventManager; |
|
11
|
|
|
|
|
12
|
|
|
use Shopware\Connect\Gateway; |
|
13
|
|
|
use Shopware\Connect\ProductFromShop as ProductFromShopBase; |
|
14
|
|
|
use Shopware\Connect\Struct\Order; |
|
15
|
|
|
use Shopware\Connect\Struct\Product; |
|
16
|
|
|
use Shopware\Connect\Struct\Address as ConnectAddress; |
|
17
|
|
|
use Shopware\Connect\Struct\Change\FromShop\Availability; |
|
18
|
|
|
use Shopware\Connect\Struct\Change\FromShop\Insert; |
|
19
|
|
|
use Shopware\Connect\Struct\Change\FromShop\Update; |
|
20
|
|
|
use Shopware\Connect\Struct\PaymentStatus; |
|
21
|
|
|
use Shopware\Connect\Struct\Shipping; |
|
22
|
|
|
|
|
23
|
|
|
use Shopware\Models\Shop\Shop; |
|
24
|
|
|
use Shopware\Models\Order\Order as ShopwareOrder; |
|
25
|
|
|
use Shopware\Models\Customer\Address as ShopwareAddress; |
|
26
|
|
|
use Shopware\Models\Dispatch\Dispatch; |
|
27
|
|
|
use Shopware\Models\Order as OrderModel; |
|
28
|
|
|
use Shopware\Models\Attribute\OrderDetail as OrderDetailAttributeModel; |
|
29
|
|
|
use Shopware\Models\Customer as CustomerModel; |
|
30
|
|
|
|
|
31
|
|
|
use Shopware\Components\Model\ModelManager; |
|
32
|
|
|
use Shopware\Components\Random; |
|
33
|
|
|
|
|
34
|
|
|
use ShopwarePlugins\Connect\Components\ProductStream\ProductStreamService; |
|
35
|
|
|
use Shopware\CustomModels\Connect\Attribute; |
|
36
|
|
|
use Shopware\Connect\Struct\Message; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* The interface for products exported *to* connect *from* the local shop |
|
40
|
|
|
* |
|
41
|
|
|
* @category Shopware |
|
42
|
|
|
* @package Shopware\Plugins\SwagConnect |
|
43
|
|
|
*/ |
|
44
|
|
|
class ProductFromShop implements ProductFromShopBase |
|
45
|
|
|
{ |
|
46
|
|
|
/** |
|
47
|
|
|
* @var Helper |
|
48
|
|
|
*/ |
|
49
|
|
|
private $helper; |
|
50
|
|
|
|
|
51
|
|
|
/** |
|
52
|
|
|
* @var ModelManager |
|
53
|
|
|
*/ |
|
54
|
|
|
private $manager; |
|
55
|
|
|
|
|
56
|
|
|
/** |
|
57
|
|
|
* @var \Shopware\Connect\Gateway |
|
58
|
|
|
*/ |
|
59
|
|
|
private $gateway; |
|
60
|
|
|
|
|
61
|
|
|
/** |
|
62
|
|
|
* @var Logger |
|
63
|
|
|
*/ |
|
64
|
|
|
private $logger; |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* @var Enlight_Event_EventManager |
|
68
|
|
|
*/ |
|
69
|
|
|
private $eventManager; |
|
70
|
|
|
|
|
71
|
|
|
/** |
|
72
|
|
|
* @param Helper $helper |
|
73
|
|
|
* @param ModelManager $manager |
|
74
|
|
|
* @param Gateway $gateway |
|
75
|
|
|
* @param Logger $logger |
|
76
|
|
|
* @param Enlight_Event_EventManager $eventManager |
|
77
|
|
|
*/ |
|
78
|
|
|
public function __construct( |
|
79
|
|
|
Helper $helper, |
|
80
|
|
|
ModelManager $manager, |
|
81
|
|
|
Gateway $gateway, |
|
82
|
|
|
Logger $logger, |
|
83
|
|
|
Enlight_Event_EventManager $eventManager |
|
84
|
|
|
) { |
|
85
|
|
|
$this->helper = $helper; |
|
86
|
|
|
$this->manager = $manager; |
|
87
|
|
|
$this->gateway = $gateway; |
|
88
|
|
|
$this->logger = $logger; |
|
89
|
|
|
$this->eventManager = $eventManager; |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
/** |
|
93
|
|
|
* Get product data |
|
94
|
|
|
* |
|
95
|
|
|
* Get product data for all the source IDs specified in the given string |
|
96
|
|
|
* array. |
|
97
|
|
|
* |
|
98
|
|
|
* @param string[] $sourceIds |
|
99
|
|
|
* @return Product[] |
|
100
|
|
|
*/ |
|
101
|
|
|
public function getProducts(array $sourceIds) |
|
102
|
|
|
{ |
|
103
|
|
|
return $this->helper->getLocalProduct($sourceIds); |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
/** |
|
107
|
|
|
* Get all IDs of all exported products |
|
108
|
|
|
* |
|
109
|
|
|
* @throws \BadMethodCallException |
|
110
|
|
|
* @return string[] |
|
111
|
|
|
*/ |
|
112
|
|
|
public function getExportedProductIDs() |
|
113
|
|
|
{ |
|
114
|
|
|
throw new \BadMethodCallException('Not implemented'); |
|
115
|
|
|
} |
|
116
|
|
|
|
|
117
|
|
|
/** |
|
118
|
|
|
* Reserve a product in shop for purchase |
|
119
|
|
|
* |
|
120
|
|
|
* @param Order $order |
|
121
|
|
|
* @throws \Exception Abort reservation by throwing an exception here. |
|
122
|
|
|
* @return void |
|
123
|
|
|
*/ |
|
124
|
|
|
public function reserve(Order $order) |
|
125
|
|
|
{ |
|
126
|
|
|
$this->eventManager->notify( |
|
127
|
|
|
'Connect_Supplier_Reservation_Before', |
|
128
|
|
|
[ |
|
129
|
|
|
'subject' => $this, |
|
130
|
|
|
'order' => $order |
|
131
|
|
|
] |
|
132
|
|
|
); |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
/** |
|
136
|
|
|
* Create order in shopware |
|
137
|
|
|
* Wraps the actual order process into a transaction |
|
138
|
|
|
* |
|
139
|
|
|
* |
|
140
|
|
|
* @param Order $order |
|
141
|
|
|
* @throws \Exception Abort buy by throwing an exception, |
|
142
|
|
|
* but only in very important cases. |
|
143
|
|
|
* Do validation in {@see reserve} instead. |
|
144
|
|
|
* @return string |
|
145
|
|
|
*/ |
|
146
|
|
|
public function buy(Order $order) |
|
147
|
|
|
{ |
|
148
|
|
|
$this->manager->beginTransaction(); |
|
149
|
|
|
try { |
|
150
|
|
|
$order = $this->eventManager->filter('Connect_Components_ProductFromShop_Buy_OrderFilter', $order); |
|
151
|
|
|
|
|
152
|
|
|
$this->validateBilling($order->billingAddress); |
|
153
|
|
|
$orderNumber = $this->doBuy($order); |
|
154
|
|
|
|
|
155
|
|
|
$this->manager->commit(); |
|
156
|
|
|
} catch (\Exception $e) { |
|
157
|
|
|
$this->manager->rollback(); |
|
158
|
|
|
throw $e; |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
return $orderNumber; |
|
162
|
|
|
} |
|
163
|
|
|
|
|
164
|
|
|
/** |
|
165
|
|
|
* returns PaymentInformation for invoice |
|
166
|
|
|
* @return null|object|\Shopware\Models\Payment\Payment |
|
167
|
|
|
*/ |
|
168
|
|
|
private function getInvoicePayment() |
|
169
|
|
|
{ |
|
170
|
|
|
$repository = $this->manager->getRepository('Shopware\Models\Payment\Payment'); |
|
171
|
|
|
return $repository->findOneBy([ |
|
172
|
|
|
'name' => 'invoice', |
|
173
|
|
|
]); |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
|
|
177
|
|
|
|
|
178
|
|
|
/** |
|
179
|
|
|
* Actually creates the remote order in shopware. |
|
180
|
|
|
* |
|
181
|
|
|
* @param Order $order |
|
182
|
|
|
* @return string |
|
183
|
|
|
*/ |
|
184
|
|
|
public function doBuy(Order $order) |
|
185
|
|
|
{ |
|
186
|
|
|
$this->manager->clear(); |
|
187
|
|
|
|
|
188
|
|
|
$shop = $this->manager->find('Shopware\Models\Shop\Shop', 1); |
|
189
|
|
|
$shopwareOrder = $this->createAndReturnMinimalOrderInShopware($order, $shop); |
|
190
|
|
|
|
|
191
|
|
|
$this->fillShopwareOrderWithItems($shopwareOrder, $order); |
|
192
|
|
|
|
|
193
|
|
|
$customer = $this->prepareCustomerFromConnectOrder($order, $shop); |
|
194
|
|
|
|
|
195
|
|
|
$shopwareOrder->setCustomer($customer); |
|
196
|
|
|
|
|
197
|
|
|
$billing = new OrderModel\Billing(); |
|
198
|
|
|
$billing->setCustomer($customer); |
|
199
|
|
|
$billing->fromArray($this->getAddressData( |
|
200
|
|
|
$order->billingAddress |
|
201
|
|
|
)); |
|
202
|
|
|
$shopwareOrder->setBilling($billing); |
|
203
|
|
|
|
|
204
|
|
|
$shipping = new OrderModel\Shipping(); |
|
205
|
|
|
$shipping->setCustomer($customer); |
|
206
|
|
|
$shipping->fromArray($this->getAddressData( |
|
207
|
|
|
$order->deliveryAddress |
|
208
|
|
|
)); |
|
209
|
|
|
$shopwareOrder->setShipping($shipping); |
|
210
|
|
|
|
|
211
|
|
|
$shopwareOrder->calculateInvoiceAmount(); |
|
212
|
|
|
|
|
213
|
|
|
$dispatchRepository = $this->manager->getRepository('Shopware\Models\Dispatch\Dispatch'); |
|
214
|
|
|
$dispatch = $dispatchRepository->findOneBy([ |
|
215
|
|
|
'name' => $order->shipping->service |
|
216
|
|
|
]); |
|
217
|
|
|
if ($dispatch) { |
|
218
|
|
|
$shopwareOrder->setDispatch($dispatch); |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
$this->eventManager->notify( |
|
222
|
|
|
'Connect_Supplier_Buy_Before', |
|
223
|
|
|
[ |
|
224
|
|
|
'subject' => $this, |
|
225
|
|
|
'order' => $order |
|
226
|
|
|
] |
|
227
|
|
|
); |
|
228
|
|
|
|
|
229
|
|
|
$this->manager->flush(); |
|
230
|
|
|
|
|
231
|
|
|
return $shopwareOrder->getNumber(); |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
/** |
|
235
|
|
|
* @param Order $connectOrder |
|
236
|
|
|
* @param Shop $shop |
|
237
|
|
|
* @return ShopwareOrder |
|
238
|
|
|
* @throws \Doctrine\ORM\ORMException |
|
239
|
|
|
* @throws \Doctrine\ORM\OptimisticLockException |
|
240
|
|
|
* @throws \Doctrine\ORM\TransactionRequiredException |
|
241
|
|
|
* @throws \Zend_Db_Adapter_Exception |
|
242
|
|
|
*/ |
|
243
|
|
|
private function createAndReturnMinimalOrderInShopware(Order $connectOrder, Shop $shop) |
|
244
|
|
|
{ |
|
245
|
|
|
$orderNumber = sprintf('SC-%s-%s', |
|
246
|
|
|
$connectOrder->orderShop, |
|
247
|
|
|
$connectOrder->localOrderId |
|
248
|
|
|
); |
|
249
|
|
|
$status = $this->manager->find('Shopware\Models\Order\Status', 0); |
|
250
|
|
|
|
|
251
|
|
|
// todo: Create the OrderModel without previous plain SQL |
|
252
|
|
|
//$model = new OrderModel\Order(); |
|
|
|
|
|
|
253
|
|
|
$sql = 'INSERT INTO `s_order` (`ordernumber`, `cleared`) VALUES (?, 17);'; |
|
254
|
|
|
Shopware()->Db()->query($sql, [$orderNumber]); |
|
255
|
|
|
$modelId = Shopware()->Db()->lastInsertId(); |
|
256
|
|
|
|
|
257
|
|
|
/** @var $shopwareOrder \Shopware\Models\Order\Order */ |
|
258
|
|
|
$shopwareOrder = $this->manager->find('Shopware\Models\Order\Order', $modelId); |
|
259
|
|
|
|
|
260
|
|
|
$attribute = new \Shopware\Models\Attribute\Order; |
|
261
|
|
|
$attribute->setConnectOrderId($connectOrder->localOrderId); |
|
262
|
|
|
$attribute->setConnectShopId($connectOrder->orderShop); |
|
263
|
|
|
$shopwareOrder->setAttribute($attribute); |
|
264
|
|
|
|
|
265
|
|
|
$shopwareOrder->fromArray([ |
|
266
|
|
|
'number' => $orderNumber, |
|
267
|
|
|
'invoiceShipping' => $connectOrder->shipping->grossShippingCosts, |
|
268
|
|
|
'invoiceShippingNet' => $connectOrder->shipping->shippingCosts, |
|
269
|
|
|
'currencyFactor' => 1, |
|
270
|
|
|
'orderStatus' => $status, |
|
271
|
|
|
'shop' => $shop, |
|
272
|
|
|
'languageSubShop' => $shop, |
|
273
|
|
|
'payment' => $this->getInvoicePayment(), |
|
274
|
|
|
'currency' => 'EUR', |
|
275
|
|
|
'orderTime' => 'now' |
|
276
|
|
|
]); |
|
277
|
|
|
|
|
278
|
|
|
return $shopwareOrder; |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
/** |
|
282
|
|
|
* iterates through order items and converts them to positions in shopware order |
|
283
|
|
|
* @param ShopwareOrder $shopwareOrder |
|
284
|
|
|
* @param Order $connectOrder |
|
285
|
|
|
* @throws \Doctrine\ORM\ORMException |
|
286
|
|
|
* @throws \Doctrine\ORM\OptimisticLockException |
|
287
|
|
|
* @throws \Doctrine\ORM\TransactionRequiredException |
|
288
|
|
|
*/ |
|
289
|
|
|
private function fillShopwareOrderWithItems(ShopwareOrder $shopwareOrder, Order $connectOrder) |
|
290
|
|
|
{ |
|
291
|
|
|
$openDetailStatus = $this->manager->find('Shopware\Models\Order\DetailStatus', 0); |
|
292
|
|
|
$connectAttributeRepository = $this->manager->getRepository('Shopware\CustomModels\Connect\Attribute'); |
|
293
|
|
|
|
|
294
|
|
|
$items = []; |
|
295
|
|
|
/** @var \Shopware\Connect\Struct\OrderItem $orderItem */ |
|
296
|
|
|
foreach ($connectOrder->orderItems as $orderItem) { |
|
297
|
|
|
$product = $orderItem->product; |
|
298
|
|
|
/** @var \Shopware\CustomModels\Connect\Attribute $connectAttribute */ |
|
299
|
|
|
//use null as shop id to fetch exported articles |
|
300
|
|
|
$connectAttribute = $connectAttributeRepository->findOneBy([ |
|
301
|
|
|
'sourceId' => $product->sourceId, |
|
302
|
|
|
'shopId' => null, |
|
303
|
|
|
]); |
|
304
|
|
|
if (!$connectAttribute) { |
|
305
|
|
|
$this->logger->write( |
|
306
|
|
|
true, |
|
307
|
|
|
sprintf('Detail with sourceId: %s does not exist', $product->sourceId), |
|
308
|
|
|
null, |
|
309
|
|
|
true |
|
310
|
|
|
); |
|
311
|
|
|
continue; |
|
312
|
|
|
} |
|
313
|
|
|
|
|
314
|
|
|
/** @var $detail \Shopware\Models\Article\Detail */ |
|
315
|
|
|
$detail = $connectAttribute->getArticleDetail(); |
|
316
|
|
|
/** @var $productModel \Shopware\Models\Article\Article */ |
|
317
|
|
|
$productModel = $detail->getArticle(); |
|
318
|
|
|
$item = new OrderModel\Detail(); |
|
319
|
|
|
$item->fromArray([ |
|
320
|
|
|
'articleId' => $productModel->getId(), |
|
321
|
|
|
'quantity' => $orderItem->count, |
|
322
|
|
|
'orderId' => $shopwareOrder->getId(), |
|
323
|
|
|
'number' => $shopwareOrder->getNumber(), |
|
324
|
|
|
'articleNumber' => $detail->getNumber(), |
|
325
|
|
|
'articleName' => $product->title, |
|
326
|
|
|
'price' => $this->calculatePrice($product), |
|
327
|
|
|
'taxRate' => $product->vat * 100, |
|
328
|
|
|
'status' => $openDetailStatus, |
|
329
|
|
|
'attribute' => new OrderDetailAttributeModel() |
|
330
|
|
|
]); |
|
331
|
|
|
$items[] = $item; |
|
332
|
|
|
} |
|
333
|
|
|
$shopwareOrder->setDetails($items); |
|
334
|
|
|
} |
|
335
|
|
|
|
|
336
|
|
|
/** |
|
337
|
|
|
* Reads customer information from connectOrder and creates a new customer if it does not exists |
|
338
|
|
|
* @param Order $connectOrder |
|
339
|
|
|
* @param Shop $shop |
|
340
|
|
|
* @return CustomerModel\Customer |
|
341
|
|
|
*/ |
|
342
|
|
|
private function prepareCustomerFromConnectOrder(Order $connectOrder, Shop $shop) |
|
343
|
|
|
{ |
|
344
|
|
|
$email = $connectOrder->billingAddress->email; |
|
345
|
|
|
|
|
346
|
|
|
$customerRepository = $this->manager->getRepository('Shopware\Models\Customer\Customer'); |
|
347
|
|
|
|
|
348
|
|
|
/** @var CustomerModel\Customer $customer */ |
|
349
|
|
|
$customer = $customerRepository->findOneBy([ |
|
350
|
|
|
'email' => $email |
|
351
|
|
|
]); |
|
352
|
|
|
|
|
353
|
|
|
if ($customer === null) { |
|
354
|
|
|
$password = Random::getAlphanumericString(30); |
|
355
|
|
|
$customer = new CustomerModel\Customer(); |
|
356
|
|
|
$customer->fromArray([ |
|
357
|
|
|
'active' => true, |
|
358
|
|
|
'email' => $email, |
|
359
|
|
|
'password' => $password, |
|
360
|
|
|
'accountMode' => 1, |
|
361
|
|
|
'shop' => $shop, |
|
362
|
|
|
'paymentId' => $this->getInvoicePayment()->getId(), |
|
363
|
|
|
]); |
|
364
|
|
|
//we need to save the customer right now to receive a id |
|
365
|
|
|
$this->manager->persist($customer); |
|
366
|
|
|
$this->manager->flush($customer); |
|
367
|
|
|
} |
|
368
|
|
|
|
|
369
|
|
|
$billingAddress = $customer->getDefaultBillingAddress(); |
|
370
|
|
|
if ($billingAddress === null) { |
|
371
|
|
|
$billingAddress = new ShopwareAddress(); |
|
372
|
|
|
} |
|
373
|
|
|
|
|
374
|
|
|
$billingAddress->fromArray($this->getAddressData( |
|
375
|
|
|
$connectOrder->billingAddress |
|
376
|
|
|
)); |
|
377
|
|
|
$billingAddress->setCustomer($customer); |
|
378
|
|
|
$this->manager->persist($billingAddress); |
|
379
|
|
|
|
|
380
|
|
|
$customer->setDefaultBillingAddress($billingAddress); |
|
381
|
|
|
|
|
382
|
|
|
$this->manager->persist($customer); |
|
383
|
|
|
|
|
384
|
|
|
return $customer; |
|
385
|
|
|
} |
|
386
|
|
|
|
|
387
|
|
|
/** |
|
388
|
|
|
* Calculate the price (including VAT) that the from shop needs to pay. |
|
389
|
|
|
* |
|
390
|
|
|
* This is most likely NOT the price the customer itself has to pay. |
|
391
|
|
|
* |
|
392
|
|
|
* @return float |
|
393
|
|
|
*/ |
|
394
|
|
|
private function calculatePrice($product) |
|
395
|
|
|
{ |
|
396
|
|
|
return $product->purchasePrice * ($product->vat + 1); |
|
397
|
|
|
} |
|
398
|
|
|
|
|
399
|
|
|
/** |
|
400
|
|
|
* @param ConnectAddress $address |
|
401
|
|
|
* @return array |
|
402
|
|
|
*/ |
|
403
|
|
|
private function getAddressData(ConnectAddress $address) |
|
404
|
|
|
{ |
|
405
|
|
|
$repository = 'Shopware\Models\Country\Country'; |
|
406
|
|
|
$repository = $this->manager->getRepository($repository); |
|
407
|
|
|
/** @var $country \Shopware\Models\Country\Country */ |
|
408
|
|
|
$country = $repository->findOneBy([ |
|
409
|
|
|
'iso3' => $address->country |
|
410
|
|
|
]); |
|
411
|
|
|
|
|
412
|
|
|
return [ |
|
413
|
|
|
'company' => $address->company ?: '', |
|
414
|
|
|
'department' => $address->department ?: '', |
|
415
|
|
|
'additionalAddressLine1' => $address->additionalAddressLine1 ?: '', |
|
416
|
|
|
'additionalAddressLine2' => $address->additionalAddressLine2 ?: '', |
|
417
|
|
|
'salutation' => 'mr', |
|
418
|
|
|
'lastName' => $address->surName, |
|
419
|
|
|
'firstName' => $address->firstName, |
|
420
|
|
|
'city' => $address->city, |
|
421
|
|
|
'zipCode' => $address->zip, |
|
422
|
|
|
'street' => $address->street, |
|
423
|
|
|
'streetNumber' => $address->streetNumber, |
|
424
|
|
|
'phone' => $address->phone, |
|
425
|
|
|
'country' => $country |
|
426
|
|
|
]; |
|
427
|
|
|
} |
|
428
|
|
|
|
|
429
|
|
|
public function updatePaymentStatus(PaymentStatus $status) |
|
430
|
|
|
{ |
|
431
|
|
|
// $paymentStatus->localOrderId is actually ordernumber for this shop |
|
432
|
|
|
// e.g. BP-35-20002 |
|
433
|
|
|
$repository = $this->manager->getRepository('Shopware\Models\Order\Order'); |
|
434
|
|
|
$order = $repository->findOneBy(['number' => $status->localOrderId]); |
|
435
|
|
|
|
|
436
|
|
|
if ($order) { |
|
437
|
|
|
$paymentStatusRepository = $this->manager->getRepository('Shopware\Models\Order\Status'); |
|
438
|
|
|
/** @var \Shopware\Models\Order\Status $orderPaymentStatus */ |
|
439
|
|
|
$orderPaymentStatus = $paymentStatusRepository->findOneBy( |
|
440
|
|
|
['name' => 'sc_' . $status->paymentStatus] |
|
441
|
|
|
); |
|
442
|
|
|
|
|
443
|
|
|
if ($orderPaymentStatus) { |
|
444
|
|
|
$order->setPaymentStatus($orderPaymentStatus); |
|
445
|
|
|
|
|
446
|
|
|
$this->eventManager->notify( |
|
447
|
|
|
'Connect_Supplier_Update_PaymentStatus_Before', |
|
448
|
|
|
[ |
|
449
|
|
|
'subject' => $this, |
|
450
|
|
|
'paymentStatus' => $status, |
|
451
|
|
|
'order' => $order |
|
452
|
|
|
] |
|
453
|
|
|
); |
|
454
|
|
|
|
|
455
|
|
|
$this->manager->persist($order); |
|
456
|
|
|
$this->manager->flush(); |
|
457
|
|
|
} else { |
|
458
|
|
|
$this->logger->write( |
|
459
|
|
|
true, |
|
460
|
|
|
sprintf( |
|
461
|
|
|
'Payment status "%s" not found', |
|
462
|
|
|
$status->paymentStatus |
|
463
|
|
|
), |
|
464
|
|
|
sprintf( |
|
465
|
|
|
'Order with id "%s"', |
|
466
|
|
|
$status->localOrderId |
|
467
|
|
|
) |
|
468
|
|
|
); |
|
469
|
|
|
} |
|
470
|
|
|
} else { |
|
471
|
|
|
$this->logger->write( |
|
472
|
|
|
true, |
|
473
|
|
|
sprintf( |
|
474
|
|
|
'Order with id "%s" not found', |
|
475
|
|
|
$status->localOrderId |
|
476
|
|
|
), |
|
477
|
|
|
serialize($status) |
|
478
|
|
|
); |
|
479
|
|
|
} |
|
480
|
|
|
} |
|
481
|
|
|
|
|
482
|
|
|
public function calculateShippingCosts(Order $order) |
|
483
|
|
|
{ |
|
484
|
|
View Code Duplication |
if (!$order->deliveryAddress) { |
|
|
|
|
|
|
485
|
|
|
return new Shipping([ |
|
486
|
|
|
'isShippable' => false, |
|
487
|
|
|
'messages' => [ |
|
488
|
|
|
new Message([ |
|
489
|
|
|
'message' => 'delivery_address_empty' |
|
490
|
|
|
]) |
|
491
|
|
|
] |
|
492
|
|
|
]); |
|
493
|
|
|
} |
|
494
|
|
|
|
|
495
|
|
|
$countryIso3 = $order->deliveryAddress->country; |
|
496
|
|
|
$country = $this->manager->getRepository('Shopware\Models\Country\Country')->findOneBy(['iso3' => $countryIso3]); |
|
497
|
|
|
|
|
498
|
|
View Code Duplication |
if (!$country) { |
|
|
|
|
|
|
499
|
|
|
return new Shipping([ |
|
500
|
|
|
'isShippable' => false, |
|
501
|
|
|
'messages' => [ |
|
502
|
|
|
new Message([ |
|
503
|
|
|
'message' => 'order_not_shippable_to_country', |
|
504
|
|
|
'values' => [ |
|
505
|
|
|
'country' => $countryIso3, |
|
506
|
|
|
] |
|
507
|
|
|
]) |
|
508
|
|
|
] |
|
509
|
|
|
]); |
|
510
|
|
|
} |
|
511
|
|
|
|
|
512
|
|
|
if (count($order->orderItems) == 0) { |
|
513
|
|
|
throw new \InvalidArgumentException( |
|
514
|
|
|
'ProductList is not allowed to be empty' |
|
515
|
|
|
); |
|
516
|
|
|
} |
|
517
|
|
|
|
|
518
|
|
|
/* @var \Shopware\Models\Shop\Shop $shop */ |
|
519
|
|
|
$shop = $this->manager->getRepository('Shopware\Models\Shop\Shop')->getActiveDefault(); |
|
520
|
|
View Code Duplication |
if (!$shop) { |
|
|
|
|
|
|
521
|
|
|
return new Shipping([ |
|
522
|
|
|
'isShippable' => false, |
|
523
|
|
|
'messages' => [ |
|
524
|
|
|
new Message([ |
|
525
|
|
|
'message' => 'default_shop_not_found' |
|
526
|
|
|
]) |
|
527
|
|
|
] |
|
528
|
|
|
]); |
|
529
|
|
|
} |
|
530
|
|
|
$shop->registerResources(Shopware()->Container()->get('bootstrap')); |
|
531
|
|
|
|
|
532
|
|
|
/** @var /Enlight_Components_Session_Namespace $session */ |
|
|
|
|
|
|
533
|
|
|
$session = Shopware()->Session(); |
|
534
|
|
|
$sessionId = uniqid('connect_remote'); |
|
535
|
|
|
$session->offsetSet('sSESSION_ID', $sessionId); |
|
536
|
|
|
|
|
537
|
|
|
$repository = $this->manager->getRepository('Shopware\CustomModels\Connect\Attribute'); |
|
538
|
|
|
$products = []; |
|
539
|
|
|
/** @var \Shopware\Connect\Struct\OrderItem $orderItem */ |
|
540
|
|
|
foreach ($order->orderItems as $orderItem) { |
|
541
|
|
|
$attributes = $repository->findBy(['sourceId' => [$orderItem->product->sourceId], 'shopId' => null]); |
|
542
|
|
|
if (count($attributes) === 0) { |
|
543
|
|
|
continue; |
|
544
|
|
|
} |
|
545
|
|
|
|
|
546
|
|
|
$products[] = [ |
|
547
|
|
|
'ordernumber' => $attributes[0]->getArticleDetail()->getNumber(), |
|
548
|
|
|
'quantity' => $orderItem->count, |
|
549
|
|
|
]; |
|
550
|
|
|
} |
|
551
|
|
|
|
|
552
|
|
|
/** @var \Shopware\CustomModels\Connect\Attribute $attribute */ |
|
553
|
|
|
foreach ($products as $product) { |
|
554
|
|
|
Shopware()->Modules()->Basket()->sAddArticle($product['ordernumber'], $product['quantity']); |
|
555
|
|
|
} |
|
556
|
|
|
|
|
557
|
|
|
$shippingMethods = Shopware()->Modules()->Admin()->sGetPremiumDispatches($country->getId()); |
|
558
|
|
View Code Duplication |
if (empty($shippingMethods)) { |
|
|
|
|
|
|
559
|
|
|
return new Shipping([ |
|
560
|
|
|
'isShippable' => false, |
|
561
|
|
|
'messages' => [ |
|
562
|
|
|
new Message([ |
|
563
|
|
|
'message' => 'order_not_shippable_to_country', |
|
564
|
|
|
'values' => [ |
|
565
|
|
|
'country' => $countryIso3, |
|
566
|
|
|
] |
|
567
|
|
|
]) |
|
568
|
|
|
] |
|
569
|
|
|
]); |
|
570
|
|
|
} |
|
571
|
|
|
|
|
572
|
|
|
$shippingMethod = reset($shippingMethods); |
|
573
|
|
|
|
|
574
|
|
|
/** @var Dispatch $shipping */ |
|
575
|
|
|
$shipping = $this->manager->getRepository(Dispatch::class)->find($shippingMethod['id']); |
|
576
|
|
|
|
|
577
|
|
View Code Duplication |
if (!$shipping) { |
|
|
|
|
|
|
578
|
|
|
return new Shipping([ |
|
579
|
|
|
'isShippable' => false, |
|
580
|
|
|
'messages' => [ |
|
581
|
|
|
new Message([ |
|
582
|
|
|
'message' => 'default_shipping_not_found' |
|
583
|
|
|
]) |
|
584
|
|
|
] |
|
585
|
|
|
]); |
|
586
|
|
|
} |
|
587
|
|
|
|
|
588
|
|
|
$session->offsetSet('sDispatch', $shipping->getId()); |
|
589
|
|
|
|
|
590
|
|
|
$result = Shopware()->Modules()->Admin()->sGetPremiumShippingcosts(['id' => $country->getId()]); |
|
591
|
|
View Code Duplication |
if (!is_array($result)) { |
|
|
|
|
|
|
592
|
|
|
return new Shipping([ |
|
593
|
|
|
'isShippable' => false, |
|
594
|
|
|
'messages' => [ |
|
595
|
|
|
new Message([ |
|
596
|
|
|
'message' => 'checkout_not_possible' |
|
597
|
|
|
]) |
|
598
|
|
|
] |
|
599
|
|
|
]); |
|
600
|
|
|
} |
|
601
|
|
|
|
|
602
|
|
|
$sql = 'DELETE FROM s_order_basket WHERE sessionID=?'; |
|
603
|
|
|
Shopware()->Db()->executeQuery($sql, [ |
|
604
|
|
|
$sessionId, |
|
605
|
|
|
]); |
|
606
|
|
|
|
|
607
|
|
|
$shippingReturn = new Shipping([ |
|
608
|
|
|
'shopId' => $this->gateway->getShopId(), |
|
609
|
|
|
'service' => $shipping->getName(), |
|
610
|
|
|
'shippingCosts' => floatval($result['netto']), |
|
611
|
|
|
'grossShippingCosts' => floatval($result['brutto']), |
|
612
|
|
|
]); |
|
613
|
|
|
|
|
614
|
|
|
$this->eventManager->notify( |
|
615
|
|
|
'Connect_Supplier_Get_Shipping_After', |
|
616
|
|
|
[ |
|
617
|
|
|
'subject' => $this, |
|
618
|
|
|
'shipping' => $shippingReturn, |
|
619
|
|
|
'order' => $order |
|
620
|
|
|
] |
|
621
|
|
|
); |
|
622
|
|
|
|
|
623
|
|
|
return $shippingReturn; |
|
624
|
|
|
} |
|
625
|
|
|
|
|
626
|
|
|
/** |
|
627
|
|
|
* Perform sync changes to fromShop |
|
628
|
|
|
* |
|
629
|
|
|
* @param string $since |
|
630
|
|
|
* @param \Shopware\Connect\Struct\Change[] $changes |
|
631
|
|
|
* @return void |
|
632
|
|
|
*/ |
|
633
|
|
|
public function onPerformSync($since, array $changes) |
|
634
|
|
|
{ |
|
635
|
|
|
$this->manager->getConnection()->beginTransaction(); |
|
636
|
|
|
|
|
637
|
|
|
$statusSynced = Attribute::STATUS_SYNCED; |
|
638
|
|
|
$statusInsert = Attribute::STATUS_INSERT; |
|
639
|
|
|
$statusUpdate = Attribute::STATUS_UPDATE; |
|
640
|
|
|
$statusDelete = Attribute::STATUS_DELETE; |
|
641
|
|
|
try { |
|
642
|
|
|
if ($since) { |
|
643
|
|
|
$this->manager->getConnection()->executeQuery( |
|
644
|
|
|
'UPDATE s_plugin_connect_items |
|
645
|
|
|
SET export_status = ? |
|
646
|
|
|
WHERE revision <= ? |
|
647
|
|
|
AND ( export_status = ? OR export_status = ? )', |
|
648
|
|
|
[$statusSynced, $since, $statusInsert, $statusUpdate] |
|
649
|
|
|
); |
|
650
|
|
|
|
|
651
|
|
|
$this->manager->getConnection()->executeQuery( |
|
652
|
|
|
'UPDATE s_plugin_connect_items |
|
653
|
|
|
SET export_status = ? |
|
654
|
|
|
WHERE revision <= ? |
|
655
|
|
|
AND export_status = ?', |
|
656
|
|
|
[null, $since, $statusDelete] |
|
657
|
|
|
); |
|
658
|
|
|
} else { |
|
659
|
|
|
$this->manager->getConnection()->executeQuery( |
|
660
|
|
|
'UPDATE s_plugin_connect_items |
|
661
|
|
|
SET export_status = ? |
|
662
|
|
|
WHERE revision IS NULL |
|
663
|
|
|
AND ( export_status = ? OR export_status = ? )', |
|
664
|
|
|
[$statusSynced, $statusInsert, $statusUpdate] |
|
665
|
|
|
); |
|
666
|
|
|
|
|
667
|
|
|
$this->manager->getConnection()->executeQuery( |
|
668
|
|
|
'UPDATE s_plugin_connect_items |
|
669
|
|
|
SET export_status = ? |
|
670
|
|
|
WHERE revision IS NULL |
|
671
|
|
|
AND export_status = ?', |
|
672
|
|
|
[null, $statusDelete] |
|
673
|
|
|
); |
|
674
|
|
|
} |
|
675
|
|
|
|
|
676
|
|
|
|
|
677
|
|
|
/** @var \Shopware\Connect\Struct\Change $change */ |
|
678
|
|
|
foreach ($changes as $change) { |
|
679
|
|
|
if (!$change instanceof Insert && !$change instanceof Update && !$change instanceof Availability) { |
|
680
|
|
|
continue; |
|
681
|
|
|
} |
|
682
|
|
|
|
|
683
|
|
|
$this->manager->getConnection()->executeQuery( |
|
684
|
|
|
'UPDATE s_plugin_connect_items |
|
685
|
|
|
SET revision = ? |
|
686
|
|
|
WHERE source_id = ? AND shop_id IS NULL', |
|
687
|
|
|
[$change->revision, $change->sourceId] |
|
688
|
|
|
); |
|
689
|
|
|
} |
|
690
|
|
|
|
|
691
|
|
|
$this->manager->getConnection()->commit(); |
|
692
|
|
|
} catch (\Exception $e) { |
|
693
|
|
|
$this->manager->getConnection()->rollBack(); |
|
694
|
|
|
} |
|
695
|
|
|
|
|
696
|
|
|
try { |
|
697
|
|
|
$this->markStreamsAsSynced(); |
|
698
|
|
|
$this->markStreamsAsNotExported(); |
|
699
|
|
|
} catch (\Exception $e) { |
|
700
|
|
|
$this->logger->write( |
|
701
|
|
|
true, |
|
702
|
|
|
sprintf('Failed to mark streams as synced! Message: "%s". Trace: "%s"', $e->getMessage(), $e->getTraceAsString()), |
|
703
|
|
|
null |
|
704
|
|
|
); |
|
705
|
|
|
} |
|
706
|
|
|
} |
|
707
|
|
|
|
|
708
|
|
View Code Duplication |
private function markStreamsAsNotExported() |
|
|
|
|
|
|
709
|
|
|
{ |
|
710
|
|
|
$streamIds = $this->manager->getConnection()->executeQuery( |
|
711
|
|
|
'SELECT pcs.stream_id as streamId |
|
712
|
|
|
FROM s_plugin_connect_streams as pcs |
|
713
|
|
|
WHERE export_status = ?', |
|
714
|
|
|
[ProductStreamService::STATUS_DELETE] |
|
715
|
|
|
)->fetchAll(); |
|
716
|
|
|
|
|
717
|
|
|
foreach ($streamIds as $stream) { |
|
718
|
|
|
$streamId = $stream['streamId']; |
|
719
|
|
|
|
|
720
|
|
|
$notDeleted = $this->manager->getConnection()->executeQuery( |
|
721
|
|
|
'SELECT pss.id |
|
722
|
|
|
FROM s_product_streams_selection as pss |
|
723
|
|
|
JOIN s_plugin_connect_items as pci |
|
724
|
|
|
ON pss.article_id = pci.article_id |
|
725
|
|
|
WHERE pss.stream_id = ? |
|
726
|
|
|
AND pci.export_status != ?', |
|
727
|
|
|
[$streamId, null] |
|
728
|
|
|
)->fetchAll(); |
|
729
|
|
|
|
|
730
|
|
|
if (count($notDeleted) === 0) { |
|
731
|
|
|
$this->manager->getConnection()->executeQuery( |
|
732
|
|
|
'UPDATE s_plugin_connect_streams |
|
733
|
|
|
SET export_status = ? |
|
734
|
|
|
WHERE stream_id = ?', |
|
735
|
|
|
[null, $streamId] |
|
736
|
|
|
); |
|
737
|
|
|
} |
|
738
|
|
|
} |
|
739
|
|
|
} |
|
740
|
|
|
|
|
741
|
|
View Code Duplication |
private function markStreamsAsSynced() |
|
|
|
|
|
|
742
|
|
|
{ |
|
743
|
|
|
$streamIds = $this->manager->getConnection()->executeQuery( |
|
744
|
|
|
'SELECT pcs.stream_id as streamId |
|
745
|
|
|
FROM s_plugin_connect_streams as pcs |
|
746
|
|
|
WHERE export_status = ?', |
|
747
|
|
|
[ProductStreamService::STATUS_EXPORT] |
|
748
|
|
|
)->fetchAll(); |
|
749
|
|
|
|
|
750
|
|
|
foreach ($streamIds as $stream) { |
|
751
|
|
|
$streamId = $stream['streamId']; |
|
752
|
|
|
|
|
753
|
|
|
$notExported = $this->manager->getConnection()->executeQuery( |
|
754
|
|
|
'SELECT pss.id |
|
755
|
|
|
FROM s_product_streams_selection as pss |
|
756
|
|
|
JOIN s_plugin_connect_items as pci |
|
757
|
|
|
ON pss.article_id = pci.article_id |
|
758
|
|
|
WHERE pss.stream_id = ? |
|
759
|
|
|
AND pci.export_status != ?', |
|
760
|
|
|
[$streamId, Attribute::STATUS_SYNCED] |
|
761
|
|
|
)->fetchAll(); |
|
762
|
|
|
|
|
763
|
|
|
if (count($notExported) === 0) { |
|
764
|
|
|
$this->manager->getConnection()->executeQuery( |
|
765
|
|
|
'UPDATE s_plugin_connect_streams |
|
766
|
|
|
SET export_status = ? |
|
767
|
|
|
WHERE stream_id = ?', |
|
768
|
|
|
[ProductStreamService::STATUS_SYNCED, $streamId] |
|
769
|
|
|
); |
|
770
|
|
|
} |
|
771
|
|
|
} |
|
772
|
|
|
} |
|
773
|
|
|
|
|
774
|
|
|
/** |
|
775
|
|
|
* @param ConnectAddress $address |
|
776
|
|
|
*/ |
|
777
|
|
|
private function validateBilling(ConnectAddress $address) |
|
778
|
|
|
{ |
|
779
|
|
|
if (!$address->email) { |
|
780
|
|
|
throw new \RuntimeException('Billing address should contain email'); |
|
781
|
|
|
} |
|
782
|
|
|
|
|
783
|
|
|
if (!$address->firstName) { |
|
784
|
|
|
throw new \RuntimeException('Billing address should contain first name'); |
|
785
|
|
|
} |
|
786
|
|
|
|
|
787
|
|
|
if (!$address->surName) { |
|
788
|
|
|
throw new \RuntimeException('Billing address should contain last name'); |
|
789
|
|
|
} |
|
790
|
|
|
|
|
791
|
|
|
if (!$address->zip) { |
|
792
|
|
|
throw new \RuntimeException('Billing address should contain zip'); |
|
793
|
|
|
} |
|
794
|
|
|
|
|
795
|
|
|
if (!$address->city) { |
|
796
|
|
|
throw new \RuntimeException('Billing address should contain city'); |
|
797
|
|
|
} |
|
798
|
|
|
|
|
799
|
|
|
if (!$address->phone) { |
|
800
|
|
|
throw new \RuntimeException('Billing address should contain phone'); |
|
801
|
|
|
} |
|
802
|
|
|
} |
|
803
|
|
|
} |
|
804
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.