Completed
Pull Request — master (#480)
by Sebastian
17:24
created

ProductFromShop::markStreamsAsSynced()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 32
Code Lines 15

Duplication

Lines 32
Ratio 100 %

Importance

Changes 0
Metric Value
dl 32
loc 32
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 15
nc 3
nop 0
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();
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
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
        //$billing = new CustomerModel\Billing();
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
381
        $customer->setDefaultBillingAddress($billingAddress);
382
383
        $this->manager->persist($customer);
384
385
        return $customer;
386
    }
387
388
    /**
389
     * Calculate the price (including VAT) that the from shop needs to pay.
390
     *
391
     * This is most likely NOT the price the customer itself has to pay.
392
     *
393
     * @return float
394
     */
395
    private function calculatePrice($product)
396
    {
397
        return $product->purchasePrice * ($product->vat + 1);
398
    }
399
400
    /**
401
     * @param ConnectAddress $address
402
     * @return array
403
     */
404
    private function getAddressData(ConnectAddress $address)
405
    {
406
        $repository = 'Shopware\Models\Country\Country';
407
        $repository = $this->manager->getRepository($repository);
408
        /** @var $country \Shopware\Models\Country\Country */
409
        $country = $repository->findOneBy([
410
            'iso3' => $address->country
411
        ]);
412
413
        return [
414
            'company' => $address->company ?: '',
415
            'department' => $address->department ?: '',
416
            'additionalAddressLine1' => $address->additionalAddressLine1 ?: '',
417
            'additionalAddressLine2' => $address->additionalAddressLine2 ?: '',
418
            'salutation' => 'mr',
419
            'lastName' => $address->surName,
420
            'firstName' => $address->firstName,
421
            'city' => $address->city,
422
            'zipCode' => $address->zip,
423
            'street' => $address->street,
424
            'streetNumber' => $address->streetNumber,
425
            'phone' => $address->phone,
426
            'country' => $country
427
        ];
428
    }
429
430
    public function updatePaymentStatus(PaymentStatus $status)
431
    {
432
        // $paymentStatus->localOrderId is actually ordernumber for this shop
433
        // e.g. BP-35-20002
434
        $repository = $this->manager->getRepository('Shopware\Models\Order\Order');
435
        $order = $repository->findOneBy(['number' => $status->localOrderId]);
436
437
        if ($order) {
438
            $paymentStatusRepository = $this->manager->getRepository('Shopware\Models\Order\Status');
439
            /** @var \Shopware\Models\Order\Status $orderPaymentStatus */
440
            $orderPaymentStatus = $paymentStatusRepository->findOneBy(
441
                ['name' => 'sc_' . $status->paymentStatus]
442
            );
443
444
            if ($orderPaymentStatus) {
445
                $order->setPaymentStatus($orderPaymentStatus);
446
447
                $this->eventManager->notify(
448
                    'Connect_Supplier_Update_PaymentStatus_Before',
449
                    [
450
                        'subject' => $this,
451
                        'paymentStatus' => $status,
452
                        'order' => $order
453
                    ]
454
                );
455
456
                $this->manager->persist($order);
457
                $this->manager->flush();
458
            } else {
459
                $this->logger->write(
460
                    true,
461
                    sprintf(
462
                        'Payment status "%s" not found',
463
                        $status->paymentStatus
464
                    ),
465
                    sprintf(
466
                        'Order with id "%s"',
467
                        $status->localOrderId
468
                    )
469
                );
470
            }
471
        } else {
472
            $this->logger->write(
473
                true,
474
                sprintf(
475
                    'Order with id "%s" not found',
476
                    $status->localOrderId
477
                ),
478
                serialize($status)
479
            );
480
        }
481
    }
482
483
    public function calculateShippingCosts(Order $order)
484
    {
485 View Code Duplication
        if (!$order->deliveryAddress) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
486
            return new Shipping([
487
                'isShippable' => false,
488
                'messages' => [
489
                    new Message([
490
                        'message' => 'delivery_address_empty'
491
                    ])
492
                ]
493
            ]);
494
        }
495
496
        $countryIso3 = $order->deliveryAddress->country;
497
        $country = $this->manager->getRepository('Shopware\Models\Country\Country')->findOneBy(['iso3' => $countryIso3]);
498
499 View Code Duplication
        if (!$country) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
500
            return new Shipping([
501
                'isShippable' => false,
502
                'messages' => [
503
                    new Message([
504
                        'message' => 'order_not_shippable_to_country',
505
                        'values' => [
506
                            'country' => $countryIso3,
507
                        ]
508
                    ])
509
                ]
510
            ]);
511
        }
512
513
        if (count($order->orderItems) == 0) {
514
            throw new \InvalidArgumentException(
515
                'ProductList is not allowed to be empty'
516
            );
517
        }
518
519
        /* @var \Shopware\Models\Shop\Shop $shop */
520
        $shop = $this->manager->getRepository('Shopware\Models\Shop\Shop')->getActiveDefault();
521 View Code Duplication
        if (!$shop) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
522
            return new Shipping([
523
                'isShippable' => false,
524
                'messages' => [
525
                    new Message([
526
                        'message' => 'default_shop_not_found'
527
                    ])
528
                ]
529
            ]);
530
        }
531
        $shop->registerResources(Shopware()->Container()->get('bootstrap'));
532
533
        /** @var /Enlight_Components_Session_Namespace $session */
0 ignored issues
show
Documentation introduced by
The doc-type /Enlight_Components_Session_Namespace could not be parsed: Unknown type name "/Enlight_Components_Session_Namespace" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
534
        $session = Shopware()->Session();
535
        $sessionId = uniqid('connect_remote');
536
        $session->offsetSet('sSESSION_ID', $sessionId);
537
538
        $repository = $this->manager->getRepository('Shopware\CustomModels\Connect\Attribute');
539
        $products = [];
540
        /** @var \Shopware\Connect\Struct\OrderItem $orderItem */
541
        foreach ($order->orderItems as $orderItem) {
542
            $attributes = $repository->findBy(['sourceId' => [$orderItem->product->sourceId], 'shopId' => null]);
543
            if (count($attributes) === 0) {
544
                continue;
545
            }
546
547
            $products[] = [
548
                'ordernumber' => $attributes[0]->getArticleDetail()->getNumber(),
549
                'quantity' => $orderItem->count,
550
            ];
551
        }
552
553
        /** @var \Shopware\CustomModels\Connect\Attribute $attribute */
554
        foreach ($products as $product) {
555
            Shopware()->Modules()->Basket()->sAddArticle($product['ordernumber'], $product['quantity']);
556
        }
557
558
        $shippingMethods = Shopware()->Modules()->Admin()->sGetPremiumDispatches($country->getId());
559 View Code Duplication
        if (empty($shippingMethods)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
560
            return new Shipping([
561
                'isShippable' => false,
562
                'messages' => [
563
                    new Message([
564
                        'message' => 'order_not_shippable_to_country',
565
                        'values' => [
566
                            'country' => $countryIso3,
567
                        ]
568
                    ])
569
                ]
570
            ]);
571
        }
572
573
        $shippingMethod = reset($shippingMethods);
574
575
        /** @var Dispatch $shipping */
576
        $shipping = $this->manager->getRepository(Dispatch::class)->find($shippingMethod['id']);
577
578 View Code Duplication
        if (!$shipping) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
579
            return new Shipping([
580
                'isShippable' => false,
581
                'messages' => [
582
                    new Message([
583
                        'message' => 'default_shipping_not_found'
584
                    ])
585
                ]
586
            ]);
587
        }
588
589
        $session->offsetSet('sDispatch', $shipping->getId());
590
591
        $result = Shopware()->Modules()->Admin()->sGetPremiumShippingcosts(['id' => $country->getId()]);
592 View Code Duplication
        if (!is_array($result)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
593
            return new Shipping([
594
                'isShippable' => false,
595
                'messages' => [
596
                    new Message([
597
                        'message' => 'checkout_not_possible'
598
                    ])
599
                ]
600
            ]);
601
        }
602
603
        $sql = 'DELETE FROM s_order_basket WHERE sessionID=?';
604
        Shopware()->Db()->executeQuery($sql, [
605
            $sessionId,
606
        ]);
607
608
        $shippingReturn = new Shipping([
609
            'shopId' => $this->gateway->getShopId(),
610
            'service' => $shipping->getName(),
611
            'shippingCosts' => floatval($result['netto']),
612
            'grossShippingCosts' => floatval($result['brutto']),
613
        ]);
614
615
        $this->eventManager->notify(
616
            'Connect_Supplier_Get_Shipping_After',
617
            [
618
                'subject' => $this,
619
                'shipping' => $shippingReturn,
620
                'order' => $order
621
            ]
622
        );
623
624
        return $shippingReturn;
625
    }
626
627
    /**
628
     * Perform sync changes to fromShop
629
     *
630
     * @param string $since
631
     * @param \Shopware\Connect\Struct\Change[] $changes
632
     * @return void
633
     */
634
    public function onPerformSync($since, array $changes)
635
    {
636
        $this->manager->getConnection()->beginTransaction();
637
638
        $statusSynced = Attribute::STATUS_SYNCED;
639
        $statusInsert = Attribute::STATUS_INSERT;
640
        $statusUpdate = Attribute::STATUS_UPDATE;
641
        $statusDelete = Attribute::STATUS_DELETE;
642
        try {
643
            if ($since) {
644
                $this->manager->getConnection()->executeQuery(
645
                    'UPDATE s_plugin_connect_items
646
                    SET export_status = ?
647
                    WHERE revision <= ?
648
                    AND ( export_status = ? OR export_status = ? )',
649
                    [$statusSynced, $since, $statusInsert, $statusUpdate]
650
                );
651
652
                $this->manager->getConnection()->executeQuery(
653
                    'UPDATE s_plugin_connect_items
654
                    SET export_status = ?
655
                    WHERE revision <= ?
656
                    AND export_status = ?',
657
                    [null, $since, $statusDelete]
658
                );
659
            } else {
660
                $this->manager->getConnection()->executeQuery(
661
                    'UPDATE s_plugin_connect_items
662
                    SET export_status = ?
663
                    WHERE revision IS NULL
664
                    AND ( export_status = ? OR export_status = ? )',
665
                    [$statusSynced, $statusInsert, $statusUpdate]
666
                );
667
668
                $this->manager->getConnection()->executeQuery(
669
                    'UPDATE s_plugin_connect_items
670
                    SET export_status = ?
671
                    WHERE revision IS NULL
672
                    AND export_status = ?',
673
                    [null, $statusDelete]
674
                );
675
            }
676
677
678
            /** @var \Shopware\Connect\Struct\Change $change */
679
            foreach ($changes as $change) {
680
                if (!$change instanceof Insert && !$change instanceof Update && !$change instanceof Availability) {
681
                    continue;
682
                }
683
684
                $this->manager->getConnection()->executeQuery(
685
                    'UPDATE s_plugin_connect_items
686
                    SET revision = ?
687
                    WHERE source_id = ? AND shop_id IS NULL',
688
                    [$change->revision, $change->sourceId]
689
                );
690
            }
691
692
            $this->manager->getConnection()->commit();
693
        } catch (\Exception $e) {
694
            $this->manager->getConnection()->rollBack();
695
        }
696
697
        try {
698
            $this->markStreamsAsSynced();
699
            $this->markStreamsAsNotExported();
700
        } catch (\Exception $e) {
701
            $this->logger->write(
702
                true,
703
                sprintf('Failed to mark streams as synced! Message: "%s". Trace: "%s"', $e->getMessage(), $e->getTraceAsString()),
704
                null
705
            );
706
        }
707
    }
708
709 View Code Duplication
    private function markStreamsAsNotExported()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
710
    {
711
        $streamIds = $this->manager->getConnection()->executeQuery(
712
            'SELECT pcs.stream_id as streamId
713
             FROM s_plugin_connect_streams as pcs
714
             WHERE export_status = ?',
715
            [ProductStreamService::STATUS_DELETE]
716
        )->fetchAll();
717
718
        foreach ($streamIds as $stream) {
719
            $streamId = $stream['streamId'];
720
721
            $notDeleted = $this->manager->getConnection()->executeQuery(
722
                'SELECT pss.id
723
                 FROM s_product_streams_selection as pss
724
                 JOIN s_plugin_connect_items as pci
725
                 ON pss.article_id = pci.article_id
726
                 WHERE pss.stream_id = ?
727
                 AND pci.export_status != ?',
728
                [$streamId, null]
729
            )->fetchAll();
730
731
            if (count($notDeleted) === 0) {
732
                $this->manager->getConnection()->executeQuery(
733
                    'UPDATE s_plugin_connect_streams
734
                     SET export_status = ?
735
                     WHERE stream_id = ?',
736
                    [null, $streamId]
737
                );
738
            }
739
        }
740
    }
741
742 View Code Duplication
    private function markStreamsAsSynced()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
743
    {
744
        $streamIds = $this->manager->getConnection()->executeQuery(
745
            'SELECT pcs.stream_id as streamId
746
             FROM s_plugin_connect_streams as pcs
747
             WHERE export_status = ?',
748
            [ProductStreamService::STATUS_EXPORT]
749
        )->fetchAll();
750
751
        foreach ($streamIds as $stream) {
752
            $streamId = $stream['streamId'];
753
754
            $notExported = $this->manager->getConnection()->executeQuery(
755
                'SELECT pss.id
756
                 FROM s_product_streams_selection as pss
757
                 JOIN s_plugin_connect_items as pci
758
                 ON pss.article_id = pci.article_id
759
                 WHERE pss.stream_id = ?
760
                 AND pci.export_status != ?',
761
                [$streamId, Attribute::STATUS_SYNCED]
762
            )->fetchAll();
763
764
            if (count($notExported) === 0) {
765
                $this->manager->getConnection()->executeQuery(
766
                    'UPDATE s_plugin_connect_streams
767
                     SET export_status = ?
768
                     WHERE stream_id = ?',
769
                    [ProductStreamService::STATUS_SYNCED, $streamId]
770
                );
771
            }
772
        }
773
    }
774
775
    /**
776
     * @param ConnectAddress $address
777
     */
778
    private function validateBilling(ConnectAddress $address)
779
    {
780
        if (!$address->email) {
781
            throw new \RuntimeException('Billing address should contain email');
782
        }
783
784
        if (!$address->firstName) {
785
            throw new \RuntimeException('Billing address should contain first name');
786
        }
787
788
        if (!$address->surName) {
789
            throw new \RuntimeException('Billing address should contain last name');
790
        }
791
792
        if (!$address->zip) {
793
            throw new \RuntimeException('Billing address should contain zip');
794
        }
795
796
        if (!$address->city) {
797
            throw new \RuntimeException('Billing address should contain city');
798
        }
799
800
        if (!$address->phone) {
801
            throw new \RuntimeException('Billing address should contain phone');
802
        }
803
    }
804
}
805