Completed
Push — master ( ca1e08...8a96f4 )
by Mario
03:09
created

Bootstrap::isShopwareVersionNew()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 34 and the first side effect is on line 29.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Shopware
4
 * Copyright © 2015 shopware AG
5
 *
6
 * According to our dual licensing model, this program can be used either
7
 * under the terms of the GNU Affero General Public License, version 3,
8
 * or under a proprietary license.
9
 *
10
 * The texts of the GNU Affero General Public License with an additional
11
 * permission and of our proprietary license can be found at and
12
 * in the LICENSE file you have received along with this program.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * "Shopware" is a registered trademark of shopware AG.
20
 * The licensing of the program under the AGPLv3 does not imply a
21
 * trademark license. Therefore any rights, title and interest in
22
 * our trademarks remain entirely with us.
23
 */
24
25
use Doctrine\DBAL\Connection;
26
use Shopware\Components\StreetSplitService;
27
28
# Load dummy interface CSRFWhitelistAware for SW < 5.2
29
require_once __DIR__ . '/Components/CSRFWhitelistAware.php';
30
31
/**
32
 * Shopware Klarna Plugin
33
 */
34
class Shopware_Plugins_Frontend_SwagPaymentKlarna_Bootstrap extends Shopware_Components_Plugin_Bootstrap
35
{
36
    /**
37
     * The klarna payment object.
38
     * @var \Shopware\Models\Payment\Payment
39
     */
40
    private $klarnaPayment = null;
41
    
42
    /**
43
     * Instance of API-Object
44
     * @var object
45
     */
46
    private $klarnaService = null;
47
48
    /**
49
     * Instance of klarna address object
50
     * @var object
51
     */
52
    private $klarnaAddr = null;
53
54
    /**
55
     * @return array
56
     */
57
    public function install($isUpdate = false)
58
    {
59
        $this->createMyEvents();
60
        if (!$isUpdate) {
61
            $this->createMyPayment();
62
        }
63
        $this->createMyForm();
64
        $this->createMyTranslations();
65
        $this->createMyAttributes();
66
67
        $aReturn = [
68
            'success' => true,
69
            'invalidateCache' => ['backend']
70
        ];
71
        
72
        return $aReturn;
73
    }
74
75
    /**
76
     * @param string $version
77
     * @return array|bool
78
     */
79
    public function update($version)
80
    {
81
        if ($version == '0.0.1') {
82
            return false;
83
        }
84
85
        if (version_compare($version, '2.0.0', '<')) {
86
            $em = $this->get('models');
87
            $form = $this->Form();
88
            if ($form->getElement('hideCheckoutSteps')) {
89
                $em->remove($form->getElement('hideCheckoutSteps'));
90
            }
91
            if ($form->getElement('expressButton')) {
92
                $em->remove($form->getElement('expressButton'));
93
            }
94
            if ($form->getElement('expressButtonLayer')) {
95
                $em->remove($form->getElement('expressButtonLayer'));
96
            }
97
            if ($form->getElement('noAccountCheckout')) {
98
                $em->remove($form->getElement('noAccountCheckout'));
99
            }
100
            $em->flush();
101
102
            $this->updatePayment();
103
        }
104
105
        return $this->install(true);
106
    }
107
108
    /**
109
     * @return bool
110
     */
111
    public function uninstall()
112
    {
113
        try {
114
            $this->get('models')->removeAttribute(
115
                's_order_attributes',
116
                'swag_klarna',
117
                'status'
118
            );
119
            $this->get('models')->removeAttribute(
120
                's_order_attributes',
121
                'swag_klarna',
122
                'invoice_number'
123
            );
124
            $this->get('models')->removeAttribute(
125
                's_order_details_attributes',
126
                'swag_klarna',
127
                'invoice_number'
128
            );
129
            $this->get('models')->generateAttributeModels(
130
                [
131
                    's_order_attributes',
132
                    's_order_details_attributes'
133
                ]
134
            );
135
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
136
        }
137
138
        return true;
139
    }
140
141
    /**
142
     * @return bool
143
     */
144
    public function isShopwareVersionNew()
145
    {
146
        return (Shopware::VERSION === '___VERSION___' || version_compare(Shopware::VERSION, '5.2.0', '>='));
147
    }
148
149
    /**
150
     * @param string $name
151
     * @return mixed
152
     */
153
    public function get($name)
154
    {
155
        if (version_compare(Shopware::VERSION, '4.2.0', '<') && Shopware::VERSION != '___VERSION___') {
156
            $name = ucfirst($name);
157
            return $this->Application()->Bootstrap()->getResource($name);
158
        }
159
160
        return parent::get($name);
161
    }
162
163
    /**
164
     * Fetches and returns klarna payment row instance.
165
     *
166
     * @return \Shopware\Models\Payment\Payment
167
     */
168
    public function getPayment()
169
    {
170
        if ($this->klarnaPayment === null) {
171
            $this->klarnaPayment = $this->Payments()->findOneBy(
172
                ['name' => 'klarna_checkout']
173
            );
174
        }
175
176
        return $this->klarnaPayment;
177
    }
178
179
    /**
180
     * @return \Klarna_Checkout_Connector
181
     */
182
    public function getConnector()
183
    {
184
        return $this->Application()->KlarnaCheckoutConnector();
185
    }
186
187
    /**
188
     * @return \Klarna
189
     */
190
    public function getService()
191
    {
192
        /** @var Klarna $service */
193
        $service = $this->Application()->KlarnaService();
194
        $service->setActivateInfo('flags', KlarnaFlags::RSRV_SEND_BY_EMAIL);
195
        $service->setVersion($this->buildKlarnaVersion($service));
196
        $service->config(
197
            $this->Config()->get('merchantId'),
198
            $this->Config()->get('sharedSecret'),
199
            KlarnaCountry::DE,
200
            KlarnaLanguage::DE,
201
            KlarnaCurrency::EUR,
202
            $this->Config()->get('testDrive') ? Klarna::BETA : Klarna::LIVE,
203
            'pdo',
204
            [
0 ignored issues
show
Documentation introduced by
array('table' => 's_klar...>Db()->getConnection()) is of type array<string,?,{"table":"string","pdo":"?"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
205
                'table' => 's_klarna_pclasses',
206
                'pdo' => $this->Application()->Db()->getConnection()
207
            ]
208
        );
209
210
        return $service;
211
    }
212
213
    /**
214
     * Activate the plugin klarna plugin.
215
     * Sets the active flag in the payment row.
216
     *
217
     * @return array
218
     */
219
    public function enable()
220
    {
221
        $payment = $this->getPayment();
222
        if ($payment !== null) {
223
            $payment->setActive(true);
224
            $this->get('models')->flush($payment);
225
        }
226
227
        return [
228
            'success' => true,
229
            'invalidateCache' => ['backend', 'frontend']
230
        ];
231
    }
232
233
    /**
234
     * Disable plugin method and sets the active flag in the payment row
235
     *
236
     * @return bool
237
     */
238
    public function disable()
239
    {
240
        $payment = $this->getPayment();
241
        if ($payment !== null) {
242
            $payment->setActive(false);
243
            $this->get('models')->flush($payment);
244
        }
245
246
        return true;
247
    }
248
    
249
    /**
250
     * Returns an instance of klarna object
251
     *
252
     * @param void
253
     * @return \Klarna
254
     */
255
    public function getKLarnaService()
256
    {
257
        if ($this->klarnaService === null) {
258
            require_once __DIR__ . '/Components/Klarna/Klarna.php';
259
            require_once __DIR__ . '/Components/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
260
            $this->klarnaService = new Klarna();
261
        }
262
263
        return $this->klarnaService;
264
    }
265
    
266
    /**
267
     * Returns an instance of klarna address object
268
     *
269
     * @param void
270
     * @return object
271
     */
272
    public function getKlarnaAddr()
273
    {
274
        if ($this->klarnaAddr === null) {
275
            $this->klarnaAddr = new KlarnaAddr();
276
        }
277
        
278
        return $this->klarnaAddr;
279
    }
280
281
    /**
282
     * Creates and subscribe the events and hooks.
283
     */
284
    protected function createMyEvents()
285
    {
286
        // BACKEND
287
        $this->subscribeEvent(
288
            'Enlight_Controller_Action_PostDispatch_Backend_Order',
289
            'onLoadOrderBackendModule'
290
        );
291
        $this->subscribeEvent(
292
            'Enlight_Controller_Action_PostDispatch_Backend_Payment',
293
            'onLoadPaymentBackendModule'
294
        );
295
296
        $this->subscribeEvent(
297
            'Enlight_Controller_Dispatcher_ControllerPath_Backend_PaymentKlarna',
298
            'onGetControllerPathBackend'
299
        );
300
301
        // FRONTEND
302
        $this->subscribeEvent(
303
            'Enlight_Controller_Dispatcher_ControllerPath_Frontend_PaymentKlarna',
304
            'onGetControllerPathFrontend'
305
        );
306
        $this->subscribeEvent(
307
            'Enlight_Controller_Action_Frontend_Checkout_Express',
308
            'onCheckoutExpress'
309
        );
310
311
        $this->subscribeEvent(
312
            'Enlight_Controller_Action_PostDispatch',
313
            'onPostDispatch',
314
            110
315
        );
316
317
        // CONNECTOR
318
        $this->subscribeEvent(
319
            'Enlight_Bootstrap_InitResource_KlarnaCheckoutConnector',
320
            'onInitResourceKlarnaCheckoutConnector'
321
        );
322
323
        // SERVICES
324
        $this->subscribeEvent(
325
            'Enlight_Bootstrap_InitResource_KlarnaService',
326
            'onInitResourceKlarnaService'
327
        );
328
329
        $this->subscribeEvent(
330
            'Enlight_Bootstrap_InitResource_StreetSplitService',
331
            'onGetStreetSplitService'
332
        );
333
334
        $this->subscribeEvent(
335
            'Enlight_Controller_Action_PostDispatch_Frontend_Register',
336
            'onPostDispatchFrontendRegister'
337
        );
338
339
        $this->subscribeEvent(
340
            'Shopware\Models\Customer\Repository::getListQueryBuilder::after',
341
            'onAfterGetCustomerListQueryBuilder'
342
        );
343
344
        $this->subscribeEvent(
345
            'Theme_Compiler_Collect_Plugin_Javascript',
346
            'addJsFiles'
347
        );
348
349
        // Subscribe the needed event for less merge and compression
350
        $this->subscribeEvent(
351
            'Theme_Compiler_Collect_Plugin_Less',
352
            'addLessFiles'
353
        );
354
355
        // Hook event subscriptions below this line
356
357
        $this->subscribeEvent(
358
            'Shopware_Controllers_Backend_Payment::updatePaymentsAction::before',
359
            'onBeforeUpdatePayment'
360
        );
361
        
362
        $this->subscribeEvent(
363
            'Shopware_Controllers_Backend_Order::saveAction::after',
364
            'onBackendOrderSaveAfter'
365
        );
366
        $this->subscribeEvent(
367
            'Shopware_Controllers_Backend_Order::deleteAction::after',
368
            'onBackendOrderDeleteAfter'
369
        );
370
    }
371
372
    /**
373
     * Method will be triggered on clicking save on order details
374
     *
375
     * @param Enlight_Hook_HookArgs $args
376
     * @return void
377
     * @throws Exception
378
     */
379
    public function onBackendOrderSaveAfter(Enlight_Hook_HookArgs $args)
380
    {
381
        $orderDataRaw = $args->getSubject()->Request()->getPost();
382
        $orderId = $orderDataRaw['id'];
383
        $paymentName = $orderDataRaw['payment'][0]['name'];
384
385
        $orderStatus = $this->getOrderStatusById($orderId);
386
387
        $validUpdateDataToKlarna = (
388
            $orderStatus != 'activate' &&
389
            (
390
                $paymentName == 'klarna_checkout' ||
391
                $paymentName == 'klarna_account' ||
392
                $paymentName == 'klarna_invoice'
393
            )
394
        );
395
396
        if ($validUpdateDataToKlarna) {
397
            $klarnaService = $this->getService();
398
399
            $klarnaAddrBilling = $this->getKlarnaAddrByRawOrderData($orderDataRaw, 'billing');
400
            $klarnaAddrShipping = $this->getKlarnaAddrByRawOrderData($orderDataRaw, 'shipping');
401
402
            $transactionId = $orderDataRaw['transactionId'];
403
            
404
            $klarnaService->setAddress(KlarnaFlags::IS_BILLING, $klarnaAddrBilling);
0 ignored issues
show
Security Bug introduced by
It seems like $klarnaAddrBilling defined by $this->getKlarnaAddrByRa...rderDataRaw, 'billing') on line 399 can also be of type false; however, Klarna::setAddress() does only seem to accept object<KlarnaAddr>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
405
            $klarnaService->setAddress(KlarnaFlags::IS_SHIPPING, $klarnaAddrShipping);
0 ignored issues
show
Security Bug introduced by
It seems like $klarnaAddrShipping defined by $this->getKlarnaAddrByRa...derDataRaw, 'shipping') on line 400 can also be of type false; however, Klarna::setAddress() does only seem to accept object<KlarnaAddr>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
406
            try {
407
                $klarnaService->update($transactionId);
408
            } catch (Exception $e) {
409
                throw new Exception($e->getMessage());
410
            }
411
        }
412
    }
413
414
    /**
415
     * @param $orderId
416
     * @return string
417
     */
418
    protected function getOrderStatusById($orderId)
419
    {
420
        $klarnaOrderStatus = Shopware()->Db()->fetchOne('SELECT swag_klarna_status FROM s_order_attributes WHERE orderID = ?', [$orderId]);
421
422
        return $klarnaOrderStatus;
423
    }
424
425
    
426
    /**
427
     * Method will be triggered on clicking delete on order overview
428
     *
429
     * @param Enlight_Hook_HookArgs $args
430
     * @return void
431
     */
432
    public function onBackendOrderDeleteAfter(Enlight_Hook_HookArgs $args)
433
    {
434
        $orderDataRaw = $args->getSubject()->Request()->getPost();
435
        $paymentName = $orderDataRaw['payment'][0]['name'];
436
        
437
        if ($paymentName == 'klarna_checkout') {
438
            $klarnaService = $this->getService();
439
            $transactionId = $orderDataRaw['transactionId'];
440
            try {
441
                $klarnaService->cancelReservation($transactionId);
442
            } catch (Exception $e) {
443
                throw new Exception($e->getMessage());
444
            }
445
        }
446
    }
447
    
448
    
449
    /**
450
     * Hook to change the absolute media-path to a normalized virtual path.
451
     * @param Enlight_Hook_HookArgs $args
452
     */
453
    public function onBeforeUpdatePayment(Enlight_Hook_HookArgs $args)
454
    {
455
        if (!$this->assertMinimumVersion('5.1')) {
456
            return;
457
        }
458
459
        /** @var Zend_Controller_Request_Http $request */
460
        $request = $args->getSubject()->Request();
461
        $attributes = $request->getParam('attribute');
462
        $attribute = reset($attributes);
463
464
        if (empty($attribute['swagKlarnaKlarnaMedia'])) {
465
            return;
466
        }
467
468
        $mediaService = $this->get('shopware_media.media_service');
469
        $attribute['swagKlarnaKlarnaMedia'] = $mediaService->normalize($attribute['swagKlarnaKlarnaMedia']);
470
        $attributes[0] = $attribute;
471
        $request->setParam('attribute', $attributes);
472
    }
473
474
    /**
475
     * Needed to implement an additional "where"-condition to filter temporary klarna-customers, so they won't be shown
476
     * in the backend anymore.
477
     *
478
     * @param Enlight_Hook_HookArgs $args
479
     */
480
    public function onAfterGetCustomerListQueryBuilder(Enlight_Hook_HookArgs $args)
481
    {
482
        /** @var \Doctrine\DBAL\Query\QueryBuilder $builder */
483
        $builder = $args->getReturn();
484
485
        $builder->andWhere('billing.lastName != :lastName')->setParameter('lastName', 'Klarna Checkout');
486
487
        $args->setReturn($builder);
488
    }
489
490
    /**
491
     * @return StreetSplitService
492
     */
493
    public function onGetStreetSplitService()
494
    {
495
        $this->Application()->Loader()->registerNamespace(
496
            'Shopware\Components',
497
            __DIR__ . '/Components/'
498
        );
499
500
        return new StreetSplitService();
501
    }
502
    
503
    /**
504
     * Logs a message
505
     *
506
     * @param string $message
507
     * @param int $logLevelMessage
508
     * @param mixed $mPrintableElement
509
     * @return void
510
     */
511 View Code Duplication
    public function klarnaLog($message, $logLevelMessage = 1, $mPrintableElement = null)
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...
512
    {
513
        $configname = 'klarnaLogLevel';
514
        $elementId = Shopware()->Db()->fetchOne('SELECT id FROM s_core_config_elements WHERE name = ?', [$configname]);
515
        $logLevelConfigSetting = Shopware()->Db()->fetchOne('SELECT value FROM s_core_config_values WHERE element_id = ?', [$elementId]);
516
        $logLevelConfigSetting = unserialize($logLevelConfigSetting);
517
        $logLevelSetting = (is_numeric($logLevelConfigSetting) && $logLevelConfigSetting >=0 && $logLevelConfigSetting <=4) ? (int)$logLevelConfigSetting : 1;
518
        
519
        if ($logLevelMessage <= $logLevelSetting) {
520
            $prefix = "[".date('Y-m-d H:i:s')."] ";
521
            $debugBacktrace = '';
522
            if ($logLevelSetting >= 4) {
523
                $debugBacktrace = print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), true);
524
            }
525
            $sPrintableElementMessage = '';
526
            if ($mPrintableElement !== null) {
527
                $sPrintableElementMessage = print_r($mPrintableElement, true);
528
            }
529
            $fullMessage = $prefix.$message."\n".$sPrintableElementMessage.$debugBacktrace;
530
            $shopPath = Shopware()->DocPath();
531
            $logfilePath = $shopPath.'/var/log/klarnaTrace.log';
532
            $fileHandler = fopen($logfilePath, 'a');
533
            fwrite($fileHandler, $fullMessage);
534
            fclose($fileHandler);
535
        }
536
    }
537
538
    /**
539
     * Method returns matching address parts by address type
540
     *
541
     * @param array $orderDataRaw
542
     * @param string $type
543
     * @return bool|KlarnaAddr
544
     */
545
    protected function getKlarnaAddrByRawOrderData($orderDataRaw, $type)
546
    {
547
        $klarnaAddr = false;
548
        $baseData = (isset($orderDataRaw[$type][0])) ? $orderDataRaw[$type][0] : false;
549
        $baseData = $this->convertEncoding($baseData);
550
        
551
        if ($baseData) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $baseData of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
552
            $addressParts = $this->fetchStreetAndHouseNumber($baseData);
553
554
            $manager = $this->get('models');
555
            $repository = 'Shopware\Models\Country\Country';
556
            $repository = $manager->getRepository($repository);
557
            $country = $repository->findOneBy(['id' => $baseData['countryId']]);
558
            $countryiso = $country->getIso();
559
560
            $klarnaAddr =  new KlarnaAddr();
561
            $klarnaAddr->setEmail($orderDataRaw['customerEmail']);
562
            $klarnaAddr->setFirstName($baseData['firstName']);
563
            $klarnaAddr->setLastName($baseData['lastName']);
564
            $klarnaAddr->setTelno($baseData['phone']);
565
            $klarnaAddr->setStreet($addressParts['street']);
566
            $klarnaAddr->setHouseNumber($addressParts['streetnr']);
567
            $klarnaAddr->setHouseExt($addressParts['streetnr_extension']);
568
            $klarnaAddr->setCompanyName($baseData['company']);
569
            $klarnaAddr->setCareof($baseData['department']);
570
            $klarnaAddr->setZipCode($baseData['zipCode']);
571
            $klarnaAddr->setCity($baseData['city']);
572
            $klarnaAddr->setCountry($countryiso);
573
        }
574
575
        $this->klarnaLog('Update order address from backend with following address data:', 3, $klarnaAddr);
576
        return $klarnaAddr;
577
    }
578
579
580
    /**
581
     * Method splits street, streetnr and streetnr extension from basestring
582
     *
583
     * @param array $baseData
584
     * @return array
585
     */
586
    protected function fetchStreetAndHouseNumber($baseData)
587
    {
588
589
        $addressParts = explode(' ', $baseData['street']);
590
        $index = 0;
591
        $street = $streetnr = '';
592
        $houseNumberFound = false;
593
594
        foreach ($addressParts as $addressPart) {
595
            if (!$houseNumberFound) {
596
                // check if current addresspart is numeric
597
                $houseNumberFound = is_numeric($addressPart);
598
            }
599
600
            $index++;
601
            if ($index == count($addressParts) || $houseNumberFound) {
602
                // at least last element should be streetnr
603
                if (!empty($streetnr)) {
604
                    $streetnr .= ' ';
605
                }
606
                $streetnr .= (string) $addressPart;
607
            } else {
608
                $street .= (string)' '.$addressPart;
609
            }
610
        }
611
612
        $streetnr_extension = '';
613
        if (!empty($baseData['additionalAddressLine1'])) {
614
            $streetnr_extension .= $baseData['additionalAddressLine1'];
615
        }
616
        if (!empty($baseData['additionalAddressLine2'])) {
617
            $streetnr_extension .= "\n".$baseData['additionalAddressLine2'];
618
        }
619
620
        $return = [
621
            'street' => $street,
622
            'streetnr' => $streetnr,
623
            'streetnr_extension' => $streetnr_extension,
624
        ];
625
626
        return $return;
627
    }
628
    
629
630
    /**
631
     * Converts encoding in all string fields of an array
632
     *
633
     * @param array $data
634
     * @return array
635
     */
636
    protected function convertEncoding($data)
637
    {
638
        $out = [];
639
        foreach ($data as $key => $value) {
640
            if (is_string($value)) {
641
                $value = mb_convert_encoding($value, 'ISO-8859-1', 'UTF-8');
642
            }
643
            
644
            $out[$key] = $value;
645
        }
646
        
647
        return $out;
648
    }
649
650
    /**
651
     * Creates and save the payment row.
652
     */
653
    protected function createMyPayment()
654
    {
655
        /** @var \Shopware\Components\Model\ModelManager $manager */
656
        $manager = $this->get('models');
657
        $repository = 'Shopware\Models\Country\Country';
658
        $repository = $manager->getRepository($repository);
659
        $countries = [
660
            $repository->findOneBy(['iso' => 'SE']),
661
            $repository->findOneBy(['iso' => 'DE']),
662
            $repository->findOneBy(['iso' => 'NO']),
663
            $repository->findOneBy(['iso' => 'FI']),
664
            $repository->findOneBy(['iso' => 'AT'])
665
        ];
666
        $this->createPayment(
667
            [
668
                'name' => 'klarna_checkout',
669
                'description' => $this->getLabel(),
670
                'action' => 'payment_klarna',
671
                'additionalDescription' => '',
672
                'countries' => $countries
673
            ]
674
        );
675
    }
676
677
    /**
678
     * Creates and stores the payment config form.
679
     */
680
    protected function createMyForm()
681
    {
682
        $form = $this->Form();
683
684
        // API settings
685
        $form->setElement(
686
            'boolean',
687
            'testDrive',
688
            [
689
                'label' => 'Testmodus aktvieren',
690
                'value' => false,
691
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
692
                'position' => 0
693
            ]
694
        );
695
696
        $form->setElement(
697
            'text',
698
            'merchantId',
699
            [
700
                'label' => 'API-HändlerID (EID)',
701
                'required' => true,
702
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
703
                'position' => 1
704
            ]
705
        );
706
707
        $form->setElement(
708
            'text',
709
            'sharedSecret',
710
            [
711
                'label' => 'API-Secret (sharedsecret)',
712
                'required' => true,
713
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
714
                'position' => 2
715
            ]
716
        );
717
718
        $form->setElement(
719
            'number',
720
            'termSiteId',
721
            [
722
                'label' => 'Shopseite mit den Geschäftsbedingungen',
723
                'value' => 4,
724
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
725
                'position' => 3
726
            ]
727
        );
728
729
        $form->setElement(
730
            'boolean',
731
            'allowSeparateShippingAddress',
732
            [
733
                'label' => 'Abweichende Lieferadresse erlauben',
734
                'value' => true,
735
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
736
                'position' => 4
737
            ]
738
        );
739
740
        $form->setElement(
741
            'boolean',
742
            'supportPackstation',
743
            [
744
                'label' => 'DHL Packstation unterstützen',
745
                'value' => false,
746
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
747
                'position' => 5,
748
                'helpText' => 'Die abweichende Lieferadresse muss erlaubt sein'
749
            ]
750
        );
751
752
        $form->setElement(
753
            'text',
754
            'postnumberField',
755
            [
756
                'label' => 'Alternatives Feld für die DHL-Postnummer',
757
                'value' => 'attribute1',
758
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
759
                'position' => 6
760
            ]
761
        );
762
763
        $form->setElement(
764
            'boolean',
765
            'mandatoryPhone',
766
            [
767
                'label' => 'Telefonummer als Pflichtfeld',
768
                'value' => false,
769
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
770
                'position' => 7
771
            ]
772
        );
773
774
        $form->setElement(
775
            'boolean',
776
            'mandatoryBirthday',
777
            [
778
                'label' => 'Geburtsdatum als Pflichtfeld',
779
                'value' => false,
780
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
781
                'position' => 8
782
            ]
783
        );
784
785
        $form->setElement(
786
            'boolean',
787
            'disableAutofocus',
788
            [
789
                'label' => 'Autofokus deaktivieren',
790
                'value' => false,
791
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
792
                'position' => 9
793
            ]
794
        );
795
796
        $form->setElement(
797
            'boolean',
798
            'showKlarnaButton',
799
            [
800
                'label' => 'Klarna Checkout-Button anzeigen',
801
                'value' => true,
802
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
803
                'position' => 10
804
            ]
805
        );
806
807
        $form->setElement(
808
            'boolean',
809
            'preFillCheckout',
810
            [
811
                'label' => 'Klarna Checkout für registrierte Kunden vorausfüllen',
812
                'value' => true,
813
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
814
                'position' => 11
815
            ]
816
        );
817
818
        $form->setElement(
819
            'color',
820
            'checkoutButtonColor',
821
            [
822
                'label' => 'Checkout Button Farbe',
823
                'value' => null,
824
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
825
                'position' => 12
826
            ]
827
        );
828
829
        $form->setElement(
830
            'color',
831
            'checkoutButtonTextColor',
832
            [
833
                'label' => 'Checkout Buttontext Farbe',
834
                'value' => null,
835
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
836
                'position' => 13
837
            ]
838
        );
839
840
        $form->setElement(
841
            'color',
842
            'checkoutCheckboxColor',
843
            [
844
                'label' => 'Checkout Checkbox Farbe',
845
                'value' => null,
846
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
847
                'position' => 14
848
            ]
849
        );
850
851
        $form->setElement(
852
            'color',
853
            'checkoutCheckboxCheckmarkColor',
854
            [
855
                'label' => 'Checkout Checkbox Häckchen Farbe',
856
                'value' => null,
857
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
858
                'position' => 15
859
            ]
860
        );
861
862
        $form->setElement(
863
            'color',
864
            'checkoutHeaderColor',
865
            [
866
                'label' => 'Checkout Header Farbe',
867
                'value' => null,
868
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
869
                'position' => 16
870
            ]
871
        );
872
873
        $form->setElement(
874
            'color',
875
            'checkoutLinkColor',
876
            [
877
                'label' => 'Checkout Link Farbe',
878
                'value' => null,
879
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
880
                'position' => 17
881
            ]
882
        );
883
884
        $form->setElement(
885
            'boolean',
886
            'KlarnaExternalPayments',
887
            [
888
                'label' => 'Externe Zahlungsarten im Klarna Checkout darstellen',
889
                'value' => null,
890
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
891
                'helpText' => 'Ihr Klarna-Konto muss für diese Funktion freigeschaltet werden',
892
                'position' => 18
893
            ]
894
        );
895
896
        $form->setElement(
897
            'select',
898
            'displayType',
899
            [
900
                'label' => 'Klarna Checkout Darstellungs-Art',
901
                'value' => 1,
902
                'store' => [
903
                    [1, 'Tab-Darstellung'],
904
                    [2, 'Nur Klarna Checkout-Darstellung'],
905
                    [3, 'Einseiten-Darstellung']
906
                ],
907
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
908
                'position' => 19
909
            ]
910
        );
911
912
        $form->setElement(
913
            'boolean',
914
            'showB2bSelect',
915
            [
916
                'label' => 'B2B-Auswahl anzeigen',
917
                'value' => true,
918
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
919
                'helpText' => 'In dem Klarna Checkout wird eine Auswahl "Privatkunde / Firma" angezeigt',
920
                'position' => 20
921
            ]
922
        );
923
924
        $form->setElement(
925
            'boolean',
926
            'showLoginPanel',
927
            [
928
                'label' => 'Login-Formular anzeigen',
929
                'value' => true,
930
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
931
                'helpText' => 'In dem Klarna Checkout wird ein Login-Formular angezeigt',
932
                'position' => 21
933
            ]
934
        );
935
936
        $form->setElement(
937
            'boolean',
938
            'showMiniBasket',
939
            [
940
                'label' => 'Warenkorb anzeigen',
941
                'value' => true,
942
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
943
                'helpText' => 'In dem Klarna Checkout wird eine kleine Übersicht des Warenkorbs angezeigt',
944
                'position' => 22
945
            ]
946
        );
947
948
        $form->setElement(
949
            'boolean',
950
            'showDispatch',
951
            [
952
                'label' => 'Lieferland & Versandarten anzeigen',
953
                'value' => true,
954
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
955
                'helpText' => 'In dem Klarna Checkout wird eine Lieferland- sowie Versandarten-Auswahl angezeigt',
956
                'position' => 23
957
            ]
958
        );
959
960
        $form->setElement(
961
            'select',
962
            'positionOrder',
963
            [
964
                'label' => 'Reihenfolge der Elemente',
965
                'value' => 1,
966
                'store' => [
967
                    [1, 'Login-Formular, Mini-Warenkorb, Versandauswahl, Zahlungsauswahl'],
968
                    [2, 'Login-Formular, Mini-Warenkorb, Zahlungsauswahl, Versandauswahl'],
969
                    [3, 'Versandauswahl, Zahlungsauswahl, Login-Formular, Mini-Warenkorb'],
970
                    [4, 'Zahlungsauswahl, Versandauswahl, Login-Formular, Mini-Warenkorb']
971
                ],
972
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
973
                'helpText' => 'Die \'Zahlungsauswahl\' wird nur in der \'Einseitig\'-Darstellung angezeigt.',
974
                'position' => 24
975
            ]
976
        );
977
978
        $form->setElement(
979
            'boolean',
980
            'partPaymentWidget',
981
            [
982
                'label' => 'Teilzahlungs-Widget auf der Detailseite anzeigen',
983
                'value' => true,
984
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
985
                'position' => 25
986
            ]
987
        );
988
989
        $form->setElement(
990
            'boolean',
991
            'convertShippingFee',
992
            [
993
                'label' => 'Versandkosten in eine Bestellposition umwandeln',
994
                'value' => true,
995
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
996
                'position' => 26
997
            ]
998
        );
999
1000
        $form->setElement(
1001
            'select',
1002
            'statusId',
1003
            [
1004
                'label' => 'Zahlstatus nach der Bestellung',
1005
                'value' => 18,
1006
                'store' => 'base.PaymentStatus',
1007
                'displayField' => 'description',
1008
                'valueField' => 'id',
1009
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1010
                'position' => 27
1011
            ]
1012
        );
1013
1014
        $form->setElement(
1015
            'select',
1016
            'activateStatusId',
1017
            [
1018
                'label' => 'Zahlungsstatus nach der Aktivierung',
1019
                'value' => 12,
1020
                'store' => 'base.PaymentStatus',
1021
                'displayField' => 'description',
1022
                'valueField' => 'id',
1023
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1024
                'position' => 28
1025
            ]
1026
        );
1027
1028
        $form->setElement(
1029
            'select',
1030
            'cancelStatusId',
1031
            [
1032
                'label' => 'Zahlungsstatus nach der Stornierung',
1033
                'value' => 17,
1034
                'store' => 'base.PaymentStatus',
1035
                'displayField' => 'description',
1036
                'valueField' => 'id',
1037
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1038
                'position' => 29
1039
            ]
1040
        );
1041
        
1042
        $form->setElement(
1043
            'select',
1044
            'klarnaLogLevel',
1045
            [
1046
                'label' => 'Detaillevel der Logeinträge zur Fehlerverfolgung',
1047
                'value' => 0,
1048
                'store' => [
1049
                    [0, 'Nichts protokollieren'],
1050
                    [1, 'Nur Fehler protokollieren'],
1051
                    [2, 'Fehler und Warnungen protokollieren'],
1052
                    [3, 'Alle Meldungen protokollieren'],
1053
                    [4, 'Alle Meldungen und zusätzlich Entwicklerinformationen protokollieren (Große Logdateien!)'],
1054
                ],
1055
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1056
                'helpText' => 'Diese Einstellmöglichkeit dient vor allem der Nachverfolgung von Fehlern im Ablauf. Die Logdatei finden Sie unter var/log/klarnaTrace.log ihrer Shopware-Installation.',
1057
                'position' => 30
1058
            ]
1059
        );
1060
    }
1061
1062
    /**
1063
     *
1064
     */
1065
    public function createMyTranslations()
1066
    {
1067
        $form = $this->Form();
1068
        $translations = $this->getTranslationArray();
1069
1070
        // In 4.2.2 we introduced a helper function for this, so we can skip the custom logic
1071
        if ($this->assertMinimumVersion('4.2.2')) {
1072
            $this->addFormTranslations($translations);
1073
            return true;
1074
        }
1075
1076
        $shopRepository = Shopware()->Models()->getRepository('\Shopware\Models\Shop\Locale');
1077
        foreach ($translations as $locale => $snippets) {
1078
            /** @var \Shopware\Models\Shop\Locale|null $localeModel */
1079
            $localeModel = $shopRepository->findOneBy(['locale' => $locale]);
1080
            if ($localeModel === null) {
1081
                continue;
1082
            }
1083
            foreach ($snippets as $element => $snippet) {
1084
                $translationModel = null;
1085
                //get the form element by name
1086
                $elementModel = $form->getElement($element);
1087
1088
                //not found? continue with next snippet
1089
                if ($elementModel === null) {
1090
                    continue;
1091
                }
1092
1093
                // Try to load existing translation
1094
                foreach ($elementModel->getTranslations() as $translation) {
1095
                    if ($translation->getLocale()->getLocale() == $locale) {
1096
                        $translationModel = $translation;
1097
                        break;
1098
                    }
1099
                }
1100
1101
                // If none found create a new one
1102
                if (!$translationModel) {
1103
                    $translationModel = new \Shopware\Models\Config\ElementTranslation();
1104
                    $translationModel->setLocale($localeModel);
1105
                    //add the translation to the form element
1106
                    $elementModel->addTranslation($translationModel);
1107
                }
1108
1109
                if ($snippet['label']) {
1110
                    $translationModel->setLabel($snippet['label']);
1111
                }
1112
1113
                if ($snippet['description']) {
1114
                    $translationModel->setDescription($snippet['description']);
1115
                }
1116
            }
1117
        }
1118
    }
1119
1120
    /**
1121
     *
1122
     */
1123
    public function createMyAttributes()
1124
    {
1125
        try {
1126
            $this->get('models')->addAttribute(
1127
                's_order_details_attributes',
1128
                'swag_klarna',
1129
                'invoice_number',
1130
                'VARCHAR(255)'
1131
            );
1132
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1133
        }
1134
1135
        $this->get('models')->generateAttributeModels(
1136
            [
1137
                's_order_details_attributes'
1138
            ]
1139
        );
1140
1141
        try {
1142
            $this->get('models')->addAttribute(
1143
                's_order_attributes',
1144
                'swag_klarna',
1145
                'status',
1146
                'VARCHAR(255)'
1147
            );
1148
            $this->get('models')->addAttribute(
1149
                's_order_attributes',
1150
                'swag_klarna',
1151
                'invoice_number',
1152
                'VARCHAR(255)'
1153
            );
1154
1155
            $this->get('models')->addAttribute(
1156
                's_core_paymentmeans_attributes',
1157
                'swag_klarna',
1158
                'show_in_klarna_iframe',
1159
                'int(11)'
1160
            );
1161
            $this->get('models')->addAttribute(
1162
                's_core_paymentmeans_attributes',
1163
                'swag_klarna',
1164
                'allow_in_payment_container',
1165
                'int(11)'
1166
            );
1167
            $this->get('models')->addAttribute(
1168
                's_core_paymentmeans_attributes',
1169
                'swag_klarna',
1170
                'klarna_media',
1171
                'VARCHAR(255)'
1172
            );
1173
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1174
        }
1175
1176
        $this->get('models')->generateAttributeModels(
1177
            [
1178
                's_order_attributes',
1179
                's_core_paymentmeans_attributes'
1180
            ]
1181
        );
1182
        
1183
        if ($this->assertMinimumVersion('5.2')) {
1184
            $this->get('shopware_attribute.crud_service')->update(
1185
                's_core_paymentmeans_attributes',
1186
                'swag_klarna_show_in_klarna_iframe',
1187
                'boolean',
1188
                [
1189
                    'label' => 'In Klarna Checkout einbinden',
1190
                    'helpText' => 'Bindet die Zahlungsart direkt in das Klarna iFrame ein',
1191
                    'displayInBackend' => true,
1192
                    'pluginId' => $this->getId()
1193
                ]
1194
            );
1195
            $this->get('shopware_attribute.crud_service')->update(
1196
                's_core_paymentmeans_attributes',
1197
                'swag_klarna_allow_in_payment_container',
1198
                'boolean',
1199
                [
1200
                    'label' => 'Nicht neben dem Klarna Checkout anzeigen',
1201
                    'helpText' => 'Versteckt die Zahlungsart in dem "Andere Zahlungsarten-Container" im Klarna Checkout',
1202
                    'displayInBackend' => true,
1203
                    'pluginId' => $this->getId()
1204
                ]
1205
            );
1206
            $this->get('shopware_attribute.crud_service')->update(
1207
                's_core_paymentmeans_attributes',
1208
                'swag_klarna_klarna_media',
1209
                'string',
1210
                [
1211
                    'label' => 'Bild Name für Klarna Checkout',
1212
                    'helpText' => 'Zeigt die Zahlungsart zusätzlich mit einem Bild im iFrame an. Funktioniert nur, wenn SSL konfiguriert ist. Optimale Größe: 276x48px.'
1213
                    . 'Das Bild muss im Order /media/image gespeichert werden',
1214
                    'displayInBackend' => true,
1215
                    'pluginId' => $this->getId()
1216
                ]
1217
            );
1218
        }
1219
    }
1220
1221
    public function registerMyTemplateDir($isBackend = false)
1222
    {
1223
        if ($isBackend) {
1224
            $this->get('template')->addTemplateDir(__DIR__ . '/Views/', 'klarna');
1225
        } elseif ($this->isTemplateResponsive()) {
1226
            $this->get('template')->addTemplateDir(__DIR__ . '/Views/responsive', 'klarna');
1227
        } else {
1228
            $this->get('template')->addTemplateDir(__DIR__ . '/Views/_emotion', 'klarna');
1229
        }
1230
    }
1231
1232
    /**
1233
     * Checks if the the current Template is responsive
1234
     *
1235
     * @return bool
1236
     */
1237
    public function isTemplateResponsive()
1238
    {
1239
        $template = $this->Application()->Shop()->getTemplate()->getVersion();
1240
        if ($template < 3) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !($template < 3);.
Loading history...
1241
            return false;
1242
        }
1243
1244
        return true;
1245
    }
1246
1247
    /**
1248
     * Returns the path to a frontend controller for an event.
1249
     *
1250
     * @return string
1251
     */
1252
    public function onGetControllerPathFrontend()
1253
    {
1254
        $this->registerMyTemplateDir();
1255
1256
        return __DIR__ . '/Controllers/Frontend/PaymentKlarna.php';
1257
    }
1258
1259
    /**
1260
     * Returns the path to a backend controller for an event.
1261
     *
1262
     * @return string
1263
     */
1264
    public function onGetControllerPathBackend()
1265
    {
1266
        $this->registerMyTemplateDir(true);
1267
        $this->Application()->Snippets()->addConfigDir(
1268
            __DIR__ . '/Snippets/'
1269
        );
1270
1271
        return __DIR__ . '/Controllers/Backend/PaymentKlarna.php';
1272
    }
1273
1274
    /**
1275
     * @param Enlight_Event_EventArgs $args
1276
     */
1277
    public function onPostDispatch(Enlight_Event_EventArgs $args)
1278
    {
1279
        /** @var $action Enlight_Controller_Action */
1280
        $action = $args->getSubject();
1281
        $request = $action->Request();
1282
        $response = $action->Response();
1283
        $view = $action->View();
1284
1285
        if (!$request->isDispatched()
1286
            || $response->isException()
1287
            || $request->getModuleName() != 'frontend'
1288
            || !$view->hasTemplate()
1289
        ) {
1290
            return;
1291
        }
1292
1293
        // just return in case kco payment is deactivated in backend
1294
1295
        if (!$this->isKcoPaymentActive()){
1296
            return;
1297
        }
1298
        $user = $view->getAssign('sUserData');
1299
        $config = $this->Config();
1300
1301
        // this is used for showing klarna buttons in basket
1302
        if ($request->getControllerName() == 'checkout'
1303
            && ($request->getActionName() == 'cart' || $request->getActionName() == 'ajaxCart')
1304
        ) {
1305
            $this->registerMyTemplateDir();
1306
            $view->assign('KlarnaEnableButton', (bool)$config->get('showKlarnaButton'));
1307
            $view->assign('KlarnaShowCheckoutButton', $this->getShowCheckoutButton($user));
1308
            $view->assign('klarnaKcoPaymentActive', $this->isKlarnaKcoPaymentActive($user));
1309
            $view->assign('KlarnaPaymentDescription', $this->getPayment()->getDescription());
1310
            if (!$this->isTemplateResponsive()) {
1311
                $view->extendsTemplate('frontend/payment_klarna_checkout/cart.tpl');
1312
            }
1313
        }
1314
1315
        // show klarna invoice information on article detail pages
1316
        if (!empty($config->partPaymentWidget)
1317
            && $request->getControllerName() == 'detail' && $request->getActionName() == 'index'
1318
        ) {
1319
            $this->registerMyTemplateDir();
1320
            //Do not shot the logo on the detail page if the kpm-plugin is active
1321
            $view->KlarnaShowLogo = !$this->isKpmActive();
1322
            $view->KlarnaLocale = $this->getLocale();
1323
            $view->KlarnaMerchantId = $config->get('merchantId');
1324
            if (!$this->isTemplateResponsive()) {
1325
                $view->extendsTemplate('frontend/payment_klarna_part/detail.tpl');
1326
            }
1327
        }
1328
1329
        if ($request->getControllerName() == 'register' && $request->getActionName() == 'index') {
1330
            $this->registerMyTemplateDir();
1331
            $view->assign('KlarnaLocale', $this->getLocale());
1332
            $view->assign('KlarnaMerchantId', $config->get('merchantId'));
1333
            $view->assign('KlarnaHideCheckoutSteps', true);
1334
            
1335
            if (version_compare(Shopware::VERSION, '5.2.0', '<')){
1336
                $view->assign('KlarnaSkipLoginFix', true);
1337
            }
1338
            if (!$this->isTemplateResponsive()) {
1339
                $view->extendsTemplate('frontend/payment_klarna_checkout/register.tpl');
1340
            }
1341
            
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
1342
        }
1343
1344
        if ($request->getControllerName() == 'account' && $request->getActionName() == 'ajax_login') {
1345
            $this->registerMyTemplateDir();
1346
            $view->assign('KlarnaLocale', $this->getLocale());
1347
            $view->assign('KlarnaMerchantId', $config->get('merchantId'));
1348
            
1349
            if (!$this->isTemplateResponsive()) {
1350
                $view->extendsTemplate('frontend/payment_klarna_checkout/ajax_login.tpl');
1351
            }
1352
        }
1353
1354
    }
1355
1356
    /**
1357
     * Populate register form with saved data on changing klarna and register tabs
1358
     *
1359
     * @param Enlight_Event_EventArgs $args
1360
     */
1361
    public function onPostDispatchFrontendRegister($args)
1362
    {
1363
        /** @var $action Enlight_Controller_Action */
1364
        $action = $args->getSubject();
1365
        $view = $action->View();
1366
        $request = $action->Request();
1367
        /** @var Enlight_Components_Session_Namespace $session */
1368
        $session = $this->Application()->Session();
1369
1370
         // Switch User to external PaymentId after registration
1371
         if (isset($session['KlarnaExternalPaymentId'])) {
1372
                $this->savePayment($session['KlarnaExternalPaymentId']);
1373
        }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 9 spaces, found 8
Loading history...
1374
1375
       $view->assign('klarnaRedirect', $request->has('klarnaRedirect') && $request->getParam('klarnaRedirect') == 1);
1376
    }
1377
    
1378
1379
    /**
1380
     * Helper method to set the selected payment-method into the session to change it in the customer-account after logging in
1381
     *
1382
     * @param $paymentId
1383
     * @throws Enlight_Exception
1384
     */
1385
    public function savePayment($paymentId)
1386
    {
1387
        $admin = Shopware()->Modules()->Admin();
1388
        $admin->sSYSTEM->_POST['sPayment'] = $paymentId;
1389
        $admin->sUpdatePayment($paymentId);
1390
1391
    }
1392
1393
    public function addJsFiles()
1394
    {
1395
        $jsPath = [
1396
            __DIR__ . '/Views/responsive/frontend/_public/src/js/jquery.klarna_checkout.js'
1397
        ];
1398
1399
        return new Doctrine\Common\Collections\ArrayCollection($jsPath);
1400
    }
1401
1402
    /**
1403
     * @param Enlight_Event_EventArgs $args
1404
     */
1405 View Code Duplication
    public function onLoadOrderBackendModule(Enlight_Event_EventArgs $args)
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...
1406
    {
1407
        /** @var $subject Enlight_Controller_Action */
1408
        $subject = $args->getSubject();
1409
        $request = $subject->Request();
1410
        $view = $subject->View();
1411
1412
        switch ($request->getActionName()) {
1413
            case 'load':
1414
                $this->registerMyTemplateDir(true);
1415
                $view->extendsTemplate('backend/order/payment_klarna.js');
1416
                break;
1417
            default:
1418
                break;
1419
        }
1420
    }
1421
1422
    /**
1423
     * @param Enlight_Event_EventArgs $args
1424
     */
1425 View Code Duplication
    public function onLoadPaymentBackendModule(Enlight_Event_EventArgs $args)
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...
1426
    {
1427
        /** @var $subject Enlight_Controller_Action */
1428
        $subject = $args->getSubject();
1429
        $request = $subject->Request();
1430
        $view = $subject->View();
1431
1432
        switch ($request->getActionName()) {
1433
            case 'load':
1434
                $this->registerMyTemplateDir(true);
1435
                $view->extendsTemplate('backend/payment/payment_klarna.js');
1436
                break;
1437
            default:
1438
                break;
1439
        }
1440
    }
1441
1442
    public function updateOrderVariables()
1443
    {
1444
        $session = Shopware()->Session();
1445
        $admin = Shopware()->Modules()->Admin();
1446
        /** @var ArrayObject $orderVariables */
1447
        $orderVariables = $session['sOrderVariables'];
1448
        $userData = $admin->sGetUserData();
1449
        $userData['payment'] = $orderVariables['sUserData']['payment'];
1450
        $userData['additional'] = array_merge(
1451
            $orderVariables['sUserData']['additional'],
1452
            $userData['additional']
1453
        );
1454
        
1455
        if (isset($session['sChangedCountry'])){
1456
            
1457
            /** @var \Shopware\Components\Model\ModelManager $em */
1458
            $em = $this->get('models');
1459
1460
            /** @var \Shopware\Models\Customer\Customer $customer */
1461
            $country = $em->getRepository('Shopware\Models\Country\Country')->findOneBy(['id' => $session['sChangedCountry']]);
1462
            $userData['shippingaddress']['country'] =$country;     
1463
            $userData['billingaddress']['country'] =$country;   
1464
            $userData['shippingaddress']['countryID'] = $session['sChangedCountry'];
1465
            $userData['billingaddress']['countryID'] = $session['sChangedCountry'];
1466
         }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 8 spaces, found 9
Loading history...
1467
        
1468
        $orderVariables['sUserData'] = $userData;
1469
        $testbreakpoint = 0;
0 ignored issues
show
Unused Code introduced by
$testbreakpoint is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1470
1471
    }
1472
1473
    /**
1474
     * @param $shop Shopware\Models\Shop\Shop
1475
     * @return int|null
1476
     */
1477
    public function getCountryByShop($shop)
1478
    {
1479
        $locale = $shop->getLocale()->getLocale();
1480
        $this->klarnaLog("Entering Bootstrap::getCountryByShop", 3);
1481
        $locale = explode('_', $locale);
1482
        $locale = isset($locale[1]) ? $locale[1] : $locale[0];
1483
        $this->klarnaLog("Bootstrap::getCountryByShop locale to request for:".$locale,3);
1484
        $sql = 'SELECT id FROM s_core_countries WHERE countryiso=?';
1485
        $countryId = Shopware()->Db()->fetchOne($sql, [$locale]);
1486
        $countryId = ($countryId) ? (int)$countryId : null;
1487
                
1488
        return $countryId;
1489
    }
1490
1491
    /**
1492
     * Get user country by country id
1493
     *
1494
     * @param $id
1495
     * @return string
1496
     */
1497
    public function getCountryIsoById($id)
1498
    {
1499
        $sql = 'SELECT countryiso FROM s_core_countries WHERE id = ?';
1500
        $countryIso = Shopware()->Db()->fetchOne($sql, [$id]);
1501
1502
        return $countryIso;
1503
    }
1504
1505
    public function getLocale($underscore = false, $countryIso = null)
1506
    {
1507
        /** @var \Shopware\Models\Shop\Shop $shop */
1508
        $shop = $this->Application()->Shop();
1509
        $locale = $shop->getLocale()->getLocale();
1510
        $locale = strtolower($locale);
1511
        if (!$underscore) {
1512
            $locale = str_replace('_', '-', $locale);
1513
        }
1514
        $locale = $locale == 'nn-no' ? 'nb-no' : $locale;
1515
1516
        if ($locale == 'de-de') {
1517
            if($countryIso == 'CH') {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
1518
                $locale = 'de-ch';
1519
            } elseif ($countryIso == 'AT') {
1520
                $locale = 'de-at';
1521
            }
1522
        }
1523
1524
        return $locale;
1525
    }
1526
1527
    public function getCheckoutOptions($allowPackstation = true, $dispatch = [])
1528
    {
1529
        $config = $this->Config();
1530
        $options = $this->getColorConfigOptions($config);
1531
1532
        $options['allow_separate_shipping_address'] = (bool)$config->get('allowSeparateShippingAddress');
1533
        $options['packstation_enabled'] = (bool)$config->get('supportPackstation') && $allowPackstation;
1534
        $options['phone_mandatory'] = (bool)$config->get('mandatoryPhone');
1535
        $options['date_of_birth_mandatory'] = (bool)$config->get('mandatoryBirthday');
1536
1537
        if (!empty($dispatch)) {
1538
            $options['shipping_details'] = $dispatch['description'];
1539
        }
1540
1541
        return $options;
1542
    }
1543
1544
    public function getCheckoutCart($basket)
1545
    {
1546
        $cart = [];
1547
        foreach ($basket['content'] as $index=>$basketItem) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "=>"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after "=>"; 0 found
Loading history...
1548
            // compatibility to shopware plugin custom products
1549
            if (isset($basketItem['custom_product_prices'])) {
1550
                $basketItemPrice = (double)$basketItem['custom_product_prices']['total'];
1551
            }
1552
            else {
1553
                $basketItemPrice = (double)str_replace(',', '.', $basketItem['price']);
1554
            }
1555
            $unitPrice = round($basketItemPrice * 100);
1556
            $cart[] = [
1557
                'type' => $unitPrice >= 0 ? 'physical' : 'discount',
1558
                'reference' => $basketItem['ordernumber'],
1559
                'name' => $basketItem['articlename'],
1560
                'quantity' => (int)$basketItem['quantity'],
1561
                'unit_price' => (int)$unitPrice,
1562
                'tax_rate' => (int)round($basketItem['tax_rate'] * 100)
1563
            ];
1564
        }
1565
        if (!empty($basket['sShippingcosts'])) {
1566
            $shippingCostsWithTax = $basket['sShippingcostsWithTax'];
1567
            $shippingAmount = !empty($shippingCostsWithTax) ? $shippingCostsWithTax : $basket['sShippingcosts'];
1568
            $cart[] = [
1569
                'type' => 'shipping_fee',
1570
                'reference' => 'SHIPPING',
1571
                'name' => 'Shipping Fee',
1572
                'quantity' => 1,
1573
                'unit_price' => (int)round($shippingAmount * 100),
1574
                'tax_rate' => (int)round($basket['sShippingcostsTax'] * 100),
1575
            ];
1576
        }
1577
1578
        return $cart;
1579
    }
1580
1581
    public function getCheckoutMerchant()
1582
    {
1583
        /** @var \Shopware\Components\Routing\RouterInterface $router */
1584
        $router = $this->Application()->Front()->Router();
1585
        $merchant = [];
1586
        $merchant['id'] = $this->Config()->get('merchantId');
1587
        $merchant['terms_uri'] = $router->assemble(
1588
            [
1589
                'controller' => 'custom',
1590
                'sCustom' => $this->Config()->get('termSiteId', 4),
1591
                'forceSecure' => true
1592
            ]
1593
        );
1594
        $merchant['checkout_uri'] = $router->assemble(
1595
            [
1596
                'action' => 'confirm'
1597
            ]
1598
        );
1599
        $merchant['confirmation_uri'] = $router->assemble(
1600
            [
1601
                'controller' => 'payment_klarna',
1602
                'action' => 'return',
1603
                'forceSecure' => true
1604
            ]
1605
        ) . "?transactionId={checkout.order.uri}";
1606
        $merchant['push_uri'] = $router->assemble(
1607
            [
1608
                'controller' => 'payment_klarna',
1609
                'action' => 'push',
1610
                'forceSecure' => true,
1611
                'appendSession' => true
1612
            ]
1613
        ) . "&transactionId={checkout.order.uri}";
1614
        $merchant['back_to_store_uri'] = $router->assemble(
1615
            [
1616
                'controller' => 'index',
1617
                'action' => 'index'
1618
            ]
1619
        );
1620
1621
        return $merchant;
1622
    }
1623
1624
    public function getCheckoutAddress($user, $type = 'billing')
1625
    {
1626
        if (empty($user[$type . 'address']['zipcode']) || $user[$type . 'address']['zipcode'] == '00000') {
1627
            return [];
1628
        }
1629
1630
        $address = [
1631
            'given_name' => $user[$type . 'address']['firstname'],
1632
            'family_name' => $user[$type . 'address']['lastname'],
1633
            'postal_code' => $user[$type . 'address']['zipcode'],
1634
            'city' => $user[$type . 'address']['city'],
1635
            'country' => $user['additional'][$type == 'billing' ? 'country' : 'countryShipping']['countryiso'],
1636
            'email' => $user['additional']['user']['email'],
1637
            'phone' => $user['billingaddress']['phone'],
1638
        ];
1639
        $address['country'] = strtolower($address['country']);
1640
        if ($address['country'] == 'de' || $address['country'] == 'nl') {
1641
            $address['title'] = $user[$type . 'address']['salutation'] == 'ms' ? 'Frau' : 'Herr';
1642
            if ($this->assertMinimumVersion('5.0.0')) {
1643
                /** @var StreetSplitService $streetSplitService */
1644
                $streetSplitService = Shopware()->StreetSplitService();
1645
                $streetAndNumber = $streetSplitService->split($user[$type . 'address']['street']);
1646
1647
                $address['street_name'] = $streetAndNumber['streetName'];
1648
                $address['street_number'] = $streetAndNumber['streetNumber'];
1649 View Code Duplication
            } else {
1650
                $address['street_name'] = $user[$type . 'address']['street'];
1651
                $address['street_number'] = $user[$type . 'address']['streetnumber'];
1652
            }
1653 View Code Duplication
        } else {
1654
            $address['street_address'] = trim(
1655
                $user[$type . 'address']['street'] . ' ' . $user[$type . 'address']['streetnumber']
1656
            );
1657
        }
1658
1659
        // Make sure phone number is unset if empty
1660
        if ($address['phone'] === null){
1661
            unset($address['phone']);
1662
        }
1663
        return $address;
1664
    }
1665
1666
    public function getCheckoutCustomer($user)
1667
    {
1668
        $customer = [
1669
            'type' => 'person'
1670
        ];
1671
        if (!empty($user['billingaddress']['birthday']) && $user['billingaddress']['birthday'] != '0000-00-00') {
1672
            $customer['date_of_birth'] = $user['billingaddress']['birthday'];
1673
        }
1674
        // SW 5.2 and newer
1675
        if (!empty($user['additional']['user']['birthday']) && $user['additional']['user'] != '0000-00-00') {
1676
            $customer['date_of_birth'] = $user['additional']['user']['birthday'];
1677
        }
1678
1679
        return $customer;
1680
    }
1681
1682
    /**
1683
     *
1684
     * @return string
1685
     */
1686
    public function getLabel()
1687
    {
1688
        return 'Klarna Checkout';
1689
    }
1690
1691
    /**
1692
     * @return string
1693
     * @throws Exception
1694
     */
1695
    public function getVersion()
1696
    {
1697
        $info = json_decode(file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'plugin.json'), true);
1698
1699
        if ($info) {
1700
            return $info['currentVersion'];
1701
        } else {
1702
            throw new Exception('The plugin has an invalid version file.');
1703
        }
1704
    }
1705
1706
    /**
1707
     * @return array
1708
     */
1709
    public function getInfo()
1710
    {
1711
        return [
1712
            'version' => $this->getVersion(),
1713
            'label' => $this->getLabel(),
1714
            'description' => file_get_contents(__DIR__ . '/info.txt')
1715
        ];
1716
    }
1717
1718
    /**
1719
     * Creates and returns the klarna client for an event.
1720
     *
1721
     * @return \Klarna_Checkout_Connector
0 ignored issues
show
Documentation introduced by
Should the return type not be Klarna_Checkout_ConnectorInterface?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1722
     */
1723
    public function onInitResourceKlarnaCheckoutConnector()
1724
    {
1725
        require_once __DIR__ . '/Components/KlarnaCheckout/Checkout.php';
1726
        if ($this->Config()->get('testDrive')) {
1727
            Klarna_Checkout_Order::$baseUri = 'https://checkout.testdrive.klarna.com/checkout/orders';
1728
        } else {
1729
            Klarna_Checkout_Order::$baseUri = 'https://checkout.klarna.com/checkout/orders';
1730
        }
1731
        Klarna_Checkout_Order::$contentType = "application/vnd.klarna.checkout.aggregated-order-v2+json";
1732
        $sharedSecret = $this->Config()->get('sharedSecret');
1733
        $connector = Klarna_Checkout_Connector::create($sharedSecret);
1734
        $this->klarnaLog("Created Klarna Connector:", 4, $connector);
1735
1736
        return $connector;
1737
    }
1738
1739
    /**
1740
     * @return Klarna
1741
     */
1742
    public function onInitResourceKlarnaService()
1743
    {
1744
        require_once __DIR__ . '/Components/Klarna/Klarna.php';
1745
        require_once __DIR__ . '/Components/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
1746
1747
        $k = new Klarna();
1748
        return $k;
1749
    }
1750
1751
    /**
1752
     * Provide the file collection for less
1753
     *
1754
     * @return \Doctrine\Common\Collections\ArrayCollection
1755
     */
1756
    public function addLessFiles()
1757
    {
1758
        $less = new \Shopware\Components\Theme\LessDefinition(
1759
            [],
1760
            [
1761
                __DIR__ . '/Views/responsive/frontend/_public/src/less/all.less'
1762
            ],
1763
            __DIR__
1764
        );
1765
1766
        return new Doctrine\Common\Collections\ArrayCollection([$less]);
1767
    }
1768
1769
    /**
1770
     * @param string $requiredVersion
1771
     * @return bool|mixed
1772
     */
1773
    protected function assertMinimumVersion($requiredVersion)
1774
    {
1775
        if (Shopware::VERSION === '___VERSION___') {
1776
            return true;
1777
        }
1778
1779
        return version_compare(Shopware::VERSION, $requiredVersion, '>=');
1780
    }
1781
1782
    /**
1783
     * This event is executed when the expressAction of the checkout-controller should be executed.
1784
     * It is needed to redirect the user back to the klarna checkout after deleting an article in the klarna checkout.
1785
     *
1786
     * @param Enlight_Event_EventArgs $args
1787
     * @return bool
1788
     */
1789
    public function onCheckoutExpress(Enlight_Event_EventArgs $args)
1790
    {
1791
        /** @var $action Enlight_Controller_Action */
1792
        $action = $args->get('subject');
1793
1794
        $action->redirect(['controller' => 'payment_klarna', 'action' => 'express']);
1795
        return true;
1796
    }
1797
1798
    /**
1799
     * Helper method to read the color-config options properly.
1800
     *
1801
     * @param $config Enlight_Config
1802
     * @return mixed
1803
     */
1804
    private function getColorConfigOptions($config)
1805
    {
1806
        $options = [];
1807
        $checkoutButtonColor = $config->get('checkoutButtonColor');
1808
        $checkoutButtonTextColor = $config->get('checkoutButtonTextColor');
1809
        $checkoutCheckboxColor = $config->get('checkoutCheckboxColor');
1810
        $checkoutCheckboxCheckMarkColor = $config->get('checkoutCheckboxCheckmarkColor');
1811
        $checkoutHeaderColor = $config->get('checkoutHeaderColor');
1812
        $checkoutLinkColor = $config->get('checkoutLinkColor');
1813
1814
        if (!empty($checkoutButtonColor) && $checkoutButtonColor !== "#") {
1815
            $options['color_button'] = $checkoutButtonColor;
1816
        }
1817
        if (!empty($checkoutButtonTextColor) && $checkoutButtonTextColor !== "#") {
1818
            $options['color_button_text'] = $checkoutButtonTextColor;
1819
        }
1820
        if (!empty($checkoutCheckboxColor) && $checkoutCheckboxColor !== "#") {
1821
            $options['color_checkbox'] = $checkoutCheckboxColor;
1822
        }
1823
        if (!empty($checkoutCheckboxCheckMarkColor) && $checkoutCheckboxCheckMarkColor !== "#") {
1824
            $options['color_checkbox_checkmark'] = $checkoutCheckboxCheckMarkColor;
1825
        }
1826
        if (!empty($checkoutHeaderColor) && $checkoutHeaderColor !== "#") {
1827
            $options['color_header'] = $checkoutHeaderColor;
1828
        }
1829
        if (!empty($checkoutLinkColor) && $checkoutLinkColor !== "#") {
1830
            $options['color_link'] = $checkoutLinkColor;
1831
        }
1832
1833
        return $options;
1834
    }
1835
1836
    /**
1837
     * @param $view Enlight_View_Default
1838
     * @param $config Enlight_Config
1839
     */
1840
    public function getViewConfig($view, $config)
1841
    {
1842
        /** @var sAdmin $adminModule */
1843
        $adminModule = $this->get('modules')->Admin();
1844
        $session = $this->get('session');
1845
        $view->assign('sCountryId', $session['sCountry']);
1846
        $view->assign('sPayments', $this->filterPayments($adminModule->sGetPaymentMeans()));
1847
        $view->assign('sCountryList', $adminModule->sGetCountryList());
1848
        $view->assign('KlarnaHideCheckoutSteps', true);
1849
        $view->assign('KlarnaShowB2bSelect', (bool)$config->get('showB2bSelect'));
1850
        $view->assign('KlarnaShowBasket', (bool)$config->get('showMiniBasket'));
1851
        $view->assign('KlarnaShowDispatch', (bool)$config->get('showDispatch'));
1852
        $view->assign(
1853
            'KlarnaCDNLink',
1854
            $this->buildCDNLink()
1855
        );
1856
        $view->assign(
1857
            'KlarnaLoggedInUser',
1858
            $view->sUserData['billingaddress']['lastname'] == 'Klarna Checkout'
1859
        );
1860
        $view->assign(
1861
            'KlarnaShowLogin',
1862
            $this->getShowLoginConfig($config, !empty($session->sUserId))
1863
        );
1864
        $view->assign(
1865
            'KlarnaDisplayType',
1866
            $this->getKlarnaDisplayType($config)
1867
        );
1868
        $view->assign(
1869
            'KlarnaPositionOrder',
1870
            $this->getPositionOrder($config)
1871
        );
1872
    }
1873
1874
    /**
1875
     * Helper method to get the config whether or not to show the login-panel in the klarna-checkout.
1876
     *
1877
     * @param Enlight_Config $config
1878
     * @param $userLoggedIn
1879
     * @return bool
1880
     */
1881
    private function getShowLoginConfig($config, $userLoggedIn)
1882
    {
1883
        return (bool) $config->get('showLoginPanel') && !($userLoggedIn);
1884
    }
1885
1886
    /**
1887
     * Helper method to find the correct display-type for the frontend.
1888
     * Will return the value configured in the plugin-config, if there is at least one more payment-mean besides klarna.
1889
     * @param $config Enlight_Config
1890
     * @return int
1891
     */
1892
    private function getKlarnaDisplayType($config)
1893
    {
1894
        if (!$this->getOtherPayments()) {
1895
            return 2;
1896
        }
1897
        return $config->get('displayType');
1898
    }
1899
1900
    /**
1901
     * Helper method to find other payment-means besides klarna.
1902
     * @return bool
1903
     */
1904
    private function getOtherPayments()
1905
    {
1906
        $payments = $this->Application()->Modules()->Admin()->sGetPaymentMeans();
1907
1908
        foreach ($payments as $payment) {
1909
            if ($payment['action'] != 'payment_klarna') {
1910
                return true;
1911
            }
1912
        }
1913
1914
        return false;
1915
    }
1916
1917
    /**
1918
     * Helper method to figure out whether or not to show the extra klarna checkout button.
1919
     *
1920
     * @param array $user
1921
     * @return bool
1922
     */
1923
    private function getShowCheckoutButton($user)
1924
    {
1925
        if (!empty($user['additional']['payment']['id']) &&
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !empty($user['add...>getPayment()->getId();.
Loading history...
1926
            $user['additional']['payment']['id'] != $this->getPayment()->getId()
1927
        ) {
1928
            return true;
1929
        }
1930
1931
        return false;
1932
    }
1933
1934
    /**
1935
     * Helper method to get the correct order for the elements
1936
     *
1937
     * @param $config Enlight_Config
1938
     * @return array Array with the order of the elements
1939
     */
1940
    private function getPositionOrder($config)
1941
    {
1942
        $loginPanel = 'login_panel';
1943
        $miniBasket = 'mini_basket';
1944
        $dispatch = 'dispatch';
1945
        $payments = 'payments';
1946
        switch ($config->get('positionOrder')) {
1947
            case 1:
1948
                return [$loginPanel, $miniBasket, $dispatch, $payments];
1949
            case 2:
1950
                return [$loginPanel, $miniBasket, $payments, $dispatch];
1951
            case 3:
1952
                return [$dispatch, $payments, $loginPanel, $miniBasket];
1953
            case 4:
1954
            default:
1955
                return [$payments, $dispatch, $loginPanel, $miniBasket];
1956
        }
1957
    }
1958
1959
    /**
1960
     * Helper method to build the proper cdn-link for the image in the tabs-layout.
1961
     * @return string
1962
     */
1963
    private function buildCDNLink()
1964
    {
1965
        $validLocales = [
1966
            'de_de',
1967
            'de_at',
1968
            'en_us',
1969
            'en_gb',
1970
            'fi_fi',
1971
            'sv_se',
1972
            'nb_no',
1973
        ];
1974
        $locale = str_replace('-', '_', $this->getLocale());
1975
1976
        if (!in_array($locale, $validLocales)) {
1977
            $locale = 'en_gb';
1978
        }
1979
        return "https://cdn.klarna.com/1.0/shared/image/generic/badge/{$locale}/checkout/long-no-klarna-logo.png";
1980
    }
1981
1982
    /**
1983
     * Helper method to read the customer-data from the klarna order-object.
1984
     * @param Klarna_Checkout_Order $order
1985
     * @return array
1986
     */
1987
    private function getKlarnaCustomerData($order)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
1988
    {
1989
        $billingAddress = $order['billing_address'];
1990
1991
        return [
1992
            'personal' => [
1993
                'customer_type' => 'private',
1994
                'salutation' => $billingAddress['title'],
1995
                'firstname' => $billingAddress['given_name'],
1996
                'lastname' => $billingAddress['family_name'],
1997
                'email' => $billingAddress['email'],
1998
                'birthday' => $order['customer']['date_of_birth'],
1999
                'phone' => $billingAddress['phone']
2000
            ],
2001
            'billing' => [
2002
                'street' => $billingAddress['street_name'] . ' ' . $billingAddress['street_number'],
2003
                'zipcode' => $billingAddress['postal_code'],
2004
                'city' => $billingAddress['city']
2005
            ]
2006
        ];
2007
    }
2008
2009
    /**
2010
     * Returns an array with all translations
2011
     * @return array
2012
     */
2013
    private function getTranslationArray()
2014
    {
2015
        return [
2016
            'en_GB' => [
2017
                'testDrive' => [
2018
                    'label' => 'Activate test-modus'
2019
                ],
2020
                'merchantId' => [
2021
                    'label' => 'API merchant ID (EID)'
2022
                ],
2023
                'sharedSecret' => [
2024
                    'label' => 'API-Secret (sharedsecret)'
2025
                ],
2026
                'termSiteId' => [
2027
                    'label' => 'Shopsite including the terms and conditions'
2028
                ],
2029
                'allowSeparateShippingAddress' => [
2030
                    'label' => 'Enable differing shipping address'
2031
                ],
2032
                'supportPackstation' => [
2033
                    'label' => 'Support DHL-packstation',
2034
                    'helpText' => 'The differing shipping address must be enabled'
2035
                ],
2036
                'postnumberField' => [
2037
                    'label' => 'Alternative field for the DHL-postnumber'
2038
                ],
2039
                'mandatoryPhone' => [
2040
                    'label' => 'Phone mandatory field'
2041
                ],
2042
                'mandatoryBirthday' => [
2043
                    'label' => 'Birthday mandatory field'
2044
                ],
2045
                'disableAutofocus' => [
2046
                    'label' => 'Disable auto-focus'
2047
                ],
2048
                'showKlarnaButton' => [
2049
                    'label' => 'Show klarna-checkout button'
2050
                ],
2051
                'checkoutButtonColor' => [
2052
                    'label' => 'Checkout Button Color'
2053
                ],
2054
                'checkoutButtonTextColor' => [
2055
                    'label' => 'Checkout Buttontext Color'
2056
                ],
2057
                'checkoutCheckboxColor' => [
2058
                    'label' => 'Checkout Checkbox Color'
2059
                ],
2060
                'checkoutCheckboxCheckmarkColor' => [
2061
                    'label' => 'Checkout Checkbox Tick Color'
2062
                ],
2063
                'checkoutHeaderColor' => [
2064
                    'label' => 'Checkout Header Color'
2065
                ],
2066
                'checkoutLinkColor' => [
2067
                    'label' => 'Checkout Link Color'
2068
                ],
2069
                'KlarnaExternalPayments' => [
2070
                    'label' => 'Display external payment-methods in klarna checkout',
2071
                    'helpText' => 'Your klarna-account has to be unlocked for this feature',
2072
                ],
2073
                'displayType' => [
2074
                    'label' => 'Klarna Checkout display-type',
2075
                    'store' => [
2076
                        [1, 'Display tabs'],
2077
                        [2, 'Display only klarna checkout'],
2078
                        [3, 'One-page display']
2079
                    ],
2080
                ],
2081
                'showB2bSelect' => [
2082
                    'label' => 'Show B2B-select',
2083
                    'helpText' => 'Displays a new select-box containing "Private customer" and "Company" in the klarna checkout'
2084
                ],
2085
                'showLoginPanel' => [
2086
                    'label' => 'Show login-panel',
2087
                    'helpText' => 'Displays a login-panel in the klarna-checkout',
2088
                ],
2089
                'showMiniBasket' => [
2090
                    'label' => 'Show mini-basket',
2091
                    'helpText' => 'Displays a small overview of the basket in the klarna-checkout',
2092
                ],
2093
                'showDispatch' => [
2094
                    'label' => 'Show shipping-country and -method',
2095
                    'helpText' => 'Shows a shipping-country and shipping-method select in the klarna-checkout'
2096
                ],
2097
                'partPaymentWidget' => [
2098
                    'label' => 'Show partial-payment-widget on detail-page'
2099
                ],
2100
                'convertShippingFee' => [
2101
                    'label' => 'Convert shipping-costs to an order-position'
2102
                ],
2103
                'statusId' => [
2104
                    'label' => 'Payment status after order'
2105
                ],
2106
                'activateStatusId' => [
2107
                    'label' => 'Payment status after activation'
2108
                ],
2109
                'cancelStatusId' => [
2110
                    'label' => 'Payment status after cancellation'
2111
                ]
2112
            ]
2113
        ];
2114
    }
2115
2116
    /**
2117
     * Helper method to update the klarna-payment when updating from any version to >= 2.0 of klarna.
2118
     * It adds "austria" to the valid countries.
2119
     */
2120
    private function updatePayment()
2121
    {
2122
        /** @var \Shopware\Components\Model\ModelManager $manager */
2123
        $manager = $this->get('models');
2124
        $payment = $manager->getRepository('Shopware\Models\Payment\Payment')->findOneBy([
2125
            'name' => 'klarna_checkout'
2126
        ]);
2127
2128
        if (empty($payment)) {
2129
            return;
2130
        }
2131
2132
        $updateNeeded = true;
2133
        $countries = $payment->getCountries();
2134
        /** @var Shopware\Models\Country\Country $country */
2135
        foreach ($countries as $country) {
2136
            if ($country->getIso() == 'AT') {
2137
                $updateNeeded = false;
2138
            }
2139
        }
2140
2141
        if ($updateNeeded) {
2142
            $countries->add($manager->getRepository('Shopware\Models\Country\Country')->findOneBy(['iso' => 'AT']));
2143
            $payment->setCountries($countries);
2144
2145
            $manager->persist($payment);
2146
            $manager->flush();
2147
        }
2148
    }
2149
2150
    /**
2151
     * Method checks if selected country is valid for use with klarna
2152
     * 
2153
     * @param string $countryId
2154
     * @return boolean
2155
     */
2156
    public function checkValidKlarnaCountry($countryId)
2157
    {
2158
        $allowedCountries = [];
2159
        $countries = $this->getPayment()->getCountries();
2160
        foreach ($countries as $country) {
2161
            $allowedCountries[] = $country->getId();
2162
        }
2163
2164
        $countryPaymentisAllowed = in_array($countryId, $allowedCountries);
2165
        // early return if country is not active for KCO in backend settings
2166
        if (!$countryPaymentisAllowed) {
2167
            return false;
2168
        }
2169
2170
        // always allow austrian KCO for german shops and vice-versa
2171
        $shopCountry = $this->getCountryByShop(Shopware()->Shop());
2172
        if ($shopCountry == "2" && $countryId == "23") {
2173
            return true;
2174
        } elseif ($shopCountry == "23" && $countryId == "2") {
2175
            return true;
2176
        } else {
2177
            return ($countryId == $shopCountry);
2178
        }
2179
    }
2180
    
2181
2182
    /**
2183
     * Helper method to read all payments, that should be displayed in the klarna checkout.
2184
     * @param $basket
2185
     * @return array
2186
     */
2187
    public function getExternalPaymentMethods($basket)
2188
    {
2189
        $payments = Shopware()->Models()->getRepository('Shopware\Models\Attribute\Payment')->findBy([
2190
            'swagKlarnaShowInKlarnaIframe' => 1,
2191
            'swagKlarnaAllowInPaymentContainer' => 0
2192
        ]);
2193
2194
        $externalPayments = [];
2195
        $externalCheckouts = [];
2196
        /** @var Shopware\Models\Attribute\Payment $payment */
2197
        foreach ($payments as $payment) {
2198
            $paymentObj = $payment->getPayment();
2199
            if (is_null($paymentObj)) {
2200
                $paymentName = false;
2201
            } else {
2202
                $paymentName = $paymentObj->getName();
2203
            }
2204
            
2205
            if (!$paymentName) {
2206
                continue;
2207
            }
2208
            
2209
            if ($paymentName && $paymentName == 'klarna_checkout') {
2210
                continue;
2211
            }
2212
            $paymentArray = [
2213
                'name' => $payment->getPayment()->getDescription(),
2214
                'redirect_uri' => $this->getRedirectUri() . '/paymentId/' . $payment->getPaymentId()
2215
            ];
2216
2217
            if ($fee = $this->getFee($payment->getPayment(), $basket)) {
2218
                $paymentArray['fee'] = $fee;
2219
            }
2220
2221
            if ($description = $payment->getPayment()->getAdditionalDescription()) {
2222
                //Shorten the description to max. 500 characters
2223
                $description = strip_tags($description);
2224
                $description = preg_replace('#<!--.*-->#ms', '', $description);
2225
                $paymentArray['description'] = substr($description, 0, 497) . '...';
2226
            }
2227
2228
            //Only add to external checkouts if an image is set and if the shop supports SSL
2229
            if (Shopware()->Shop()->getSecure() && $image = $this->getImageForKlarna($payment)) {
2230
                $paymentArray['image_uri'] = $image;
2231
                $externalCheckouts[] = $paymentArray;
2232
            }
2233
2234
            $externalPayments[] = $paymentArray;
2235
        }
2236
2237
        return [$externalPayments, $externalCheckouts];
2238
    }
2239
2240
    /**
2241
     * @param Shopware\Models\Payment\Payment $payment
2242
     * @param $basket
2243
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
2244
     */
2245
    private function getFee($payment, $basket)
2246
    {
2247
        $fee = 0;
2248
        $amount = str_replace(',', '.', $basket['Amount']);
2249
2250
        if ($surcharge = $payment->getSurcharge()) {
2251
            $fee += $surcharge;
2252
            $amount += $surcharge;
2253
        }
2254
2255
        if ($percent = $payment->getDebitPercent()) {
2256
            $fee += round($amount / 100 * $percent, 3);
2257
        }
2258
2259
        return round($fee * 100);
2260
    }
2261
2262
    /**
2263
     * Helper method to get the redirect-uri
2264
     * @return string
2265
     */
2266
    private function getRedirectUri()
2267
    {
2268
        return Shopware()->Front()->Router()->assemble([
2269
            'controller' => 'PaymentKlarna',
2270
            'action' => 'setPayment'
2271
        ]);
2272
    }
2273
2274
    /**
2275
     * Helper method to read the image for the klarna-checkout if set
2276
     * @param Shopware\Models\Attribute\Payment $payment
2277
     * @return null|string
2278
     */
2279
    private function getImageForKlarna($payment)
2280
    {
2281
        $media = $payment->getSwagKlarnaKlarnaMedia();
2282
        if (!$payment->getSwagKlarnaShowInKlarnaIframe() || !empty($media)) {
2283
            if ($this->assertMinimumVersion('5.1') && version_compare(Shopware::VERSION, '5.2.0', '<=')) {
2284
                $media = $this->get('shopware_media.media_service')->getUrl($media);
2285
            } else {
2286
                /** @var Enlight_Controller_Front $front */
2287
                $front = $this->get('front');
2288
                $request = $front->Request();
2289
                if ($request && $request->getHttpHost()) {
2290
                    $url = ($request->isSecure() ? 'https' : 'http') .
2291
                        '://' . $request->getHttpHost() .
2292
                        $request->getBasePath() . "/";
2293
                } else {
2294
                    $url = $front->Router()->assemble(['controller' => 'index', 'module' => 'frontend']);
2295
                }
2296
                if (version_compare(Shopware::VERSION, '5.2.0', '>=')) {
2297
                    # make sure me get only the image name, path is set in case of upgarde from SW.5.1 to 5.2
2298
                    $parts = explode('/', $media);
2299
                    $end = end($parts);
2300
                    $media = $url . 'media/image/' . $end;
2301
                } else {
2302
                    $media = $url . $media;
2303
                }
2304
            }
2305
2306
            return $media;
2307
        }
2308
        return null;
2309
    }
2310
2311
    /**
2312
     * Helper method to filter the available payment-means.
2313
     * @param $sGetPaymentMeans
2314
     * @return array
2315
     */
2316
    public function filterPayments($sGetPaymentMeans)
2317
    {
2318
        $paymentArray = [];
2319
        foreach ($sGetPaymentMeans as $paymentMean) {
2320
            if (!$this->isPaymentAllowed($paymentMean)) {
2321
                continue;
2322
            }
2323
2324
            $paymentArray[] = $paymentMean;
2325
        }
2326
        return $paymentArray;
2327
    }
2328
2329
    /**
2330
     * Helper method to check if a payment is allowed to be
2331
     * @param $payment
2332
     * @return bool
2333
     */
2334
    private function isPaymentAllowed($payment)
2335
    {
2336
        if ($payment['name'] == 'klarna_checkout') {
2337
            return false;
2338
        }
2339
        $connection = Shopware()->Models()->getConnection();
2340
2341
        $builder = $connection->createQueryBuilder();
2342
        $builder->select('swag_klarna_allow_in_payment_container', 'swag_klarna_show_in_klarna_iframe')
2343
            ->from('s_core_paymentmeans_attributes')
2344
            ->where('paymentmeanID = :id')
2345
            ->setParameter(':id', $payment['id']);
2346
2347
        $result = reset($builder->execute()->fetchAll());
0 ignored issues
show
Bug introduced by
$builder->execute()->fetchAll() cannot be passed to reset() as the parameter $array expects a reference.
Loading history...
2348
        return !$result['swag_klarna_allow_in_payment_container'] && !$result['swag_klarna_show_in_klarna_iframe'];
2349
    }
2350
2351
    /**
2352
     * Builds the new klarna version-string.
2353
     *
2354
     * @param Klarna $klarna
2355
     * @return string
2356
     */
2357
    private function buildKlarnaVersion(Klarna $klarna)
2358
    {
2359
        $versionInfo = [
2360
            'Shopware',
2361
            $this->Application()->Config()->version,
2362
            'KCO-Plugin',
2363
            $this->getVersion(),
2364
            $klarna->getVersion()
2365
        ];
2366
2367
        return implode(':', $versionInfo);
2368
    }
2369
2370
    /**
2371
     * Helper method to find out if the kpm plugin is active
2372
     */
2373 View Code Duplication
    public function isKpmActive()
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...
2374
    {
2375
        /** @var Doctrine\DBAL\Query\QueryBuilder $queryBuilder */
2376
        $queryBuilder = Shopware()->Models()->getConnection()->createQueryBuilder();
2377
2378
        $result = $queryBuilder->select('plugin.id')
2379
            ->from('s_core_plugins', 'plugin')
2380
            ->where('plugin.name = :name')
2381
            ->andWhere('plugin.active = 1')
2382
            ->setParameter('name', 'SwagPaymentKlarnaKpm')
2383
            ->execute()
2384
            ->fetchColumn();
2385
2386
        return !empty($result);
2387
    }
2388
2389
    /**
2390
     * Helper method to find out if the kco paymentmean is active
2391
     */
2392 View Code Duplication
    public function isKcoPaymentActive()
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...
2393
    {
2394
        /** @var Doctrine\DBAL\Query\QueryBuilder $queryBuilder */
2395
        $queryBuilder = Shopware()->Models()->getConnection()->createQueryBuilder();
2396
2397
        $result = $queryBuilder->select('payment.id')
2398
            ->from('s_core_paymentmeans', 'payment')
2399
            ->where('payment.name = :name')
2400
            ->andWhere('payment.active = 1')
2401
            ->setParameter('name', 'klarna_checkout')
2402
            ->execute()
2403
            ->fetchColumn();
2404
2405
        return !empty($result);
2406
    }
2407
2408
    /**
2409
     * Helper method to find out if the klarna kco payment is active.
2410
     * Necessary to disable the checkout-button.
2411
     * @param array $user
2412
     * @return bool
2413
     */
2414
    public function isKlarnaKcoPaymentActive($user)
2415
    {
2416
        $payment = $this->getPayment();
2417
        if (!$payment) {
2418
            return false;
2419
        }
2420
        $data = $this->get('modules')->Admin()->sGetPaymentMeanById($payment->getId(), $user);
2421
        if (empty($data) || $data['id'] != $payment->getId()) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !(empty($data) ||... != $payment->getId());.
Loading history...
2422
            return false;
2423
        }
2424
        return true;
2425
    }
2426
}
2427