Bootstrap::getCountryIsoById()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
eloc 4
nc 1
nop 1
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
                'helpText' => 'Wenn die Telefonnummer für die Registrierung eines Kunden in ' .
772
                    'den Grundeinstellungen des Shops als Pflichtfeld behandelt wird, muss auch hier "Ja" ' .
773
                    'gesetzt sein, sonst können Klarna-Bestellungen nicht angelegt werden!'
774
            ]
775
        );
776
777
        $form->setElement(
778
            'boolean',
779
            'mandatoryBirthday',
780
            [
781
                'label' => 'Geburtsdatum als Pflichtfeld',
782
                'value' => false,
783
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
784
                'position' => 8,
785
                'helpText' => 'Wenn das Geburtsdatum für die Registrierung eines Kunden in ' .
786
                    'den Grundeinstellungen des Shops als Pflichtfeld behandelt wird, muss auch hier "Ja" ' .
787
                    'gesetzt sein, sonst können Klarna-Bestellungen nicht angelegt werden!'
788
            ]
789
        );
790
791
        $form->setElement(
792
            'boolean',
793
            'disableAutofocus',
794
            [
795
                'label' => 'Autofokus deaktivieren',
796
                'value' => false,
797
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
798
                'position' => 9
799
            ]
800
        );
801
802
        $form->setElement(
803
            'boolean',
804
            'showKlarnaButton',
805
            [
806
                'label' => 'Klarna Checkout-Button anzeigen',
807
                'value' => true,
808
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
809
                'position' => 10
810
            ]
811
        );
812
813
        $form->setElement(
814
            'boolean',
815
            'preFillCheckout',
816
            [
817
                'label' => 'Klarna Checkout für registrierte Kunden vorausfüllen',
818
                'value' => true,
819
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
820
                'position' => 11
821
            ]
822
        );
823
824
        $form->setElement(
825
            'color',
826
            'checkoutButtonColor',
827
            [
828
                'label' => 'Checkout Button Farbe',
829
                'value' => null,
830
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
831
                'position' => 12
832
            ]
833
        );
834
835
        $form->setElement(
836
            'color',
837
            'checkoutButtonTextColor',
838
            [
839
                'label' => 'Checkout Buttontext Farbe',
840
                'value' => null,
841
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
842
                'position' => 13
843
            ]
844
        );
845
846
        $form->setElement(
847
            'color',
848
            'checkoutCheckboxColor',
849
            [
850
                'label' => 'Checkout Checkbox Farbe',
851
                'value' => null,
852
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
853
                'position' => 14
854
            ]
855
        );
856
857
        $form->setElement(
858
            'color',
859
            'checkoutCheckboxCheckmarkColor',
860
            [
861
                'label' => 'Checkout Checkbox Häckchen Farbe',
862
                'value' => null,
863
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
864
                'position' => 15
865
            ]
866
        );
867
868
        $form->setElement(
869
            'color',
870
            'checkoutHeaderColor',
871
            [
872
                'label' => 'Checkout Header Farbe',
873
                'value' => null,
874
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
875
                'position' => 16
876
            ]
877
        );
878
879
        $form->setElement(
880
            'color',
881
            'checkoutLinkColor',
882
            [
883
                'label' => 'Checkout Link Farbe',
884
                'value' => null,
885
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
886
                'position' => 17
887
            ]
888
        );
889
890
        $form->setElement(
891
            'boolean',
892
            'KlarnaExternalPayments',
893
            [
894
                'label' => 'Externe Zahlungsarten im Klarna Checkout darstellen',
895
                'value' => null,
896
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
897
                'helpText' => 'Ihr Klarna-Konto muss für diese Funktion freigeschaltet werden',
898
                'position' => 18
899
            ]
900
        );
901
902
        $form->setElement(
903
            'select',
904
            'displayType',
905
            [
906
                'label' => 'Klarna Checkout Darstellungs-Art',
907
                'value' => 1,
908
                'store' => [
909
                    [1, 'Tab-Darstellung'],
910
                    [2, 'Nur Klarna Checkout-Darstellung'],
911
                    [3, 'Einseiten-Darstellung']
912
                ],
913
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
914
                'position' => 19
915
            ]
916
        );
917
918
        $form->setElement(
919
            'boolean',
920
            'showB2bSelect',
921
            [
922
                'label' => 'B2B-Auswahl anzeigen',
923
                'value' => true,
924
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
925
                'helpText' => 'In dem Klarna Checkout wird eine Auswahl "Privatkunde / Firma" angezeigt',
926
                'position' => 20
927
            ]
928
        );
929
930
        $form->setElement(
931
            'boolean',
932
            'showLoginPanel',
933
            [
934
                'label' => 'Login-Formular anzeigen',
935
                'value' => true,
936
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
937
                'helpText' => 'In dem Klarna Checkout wird ein Login-Formular angezeigt',
938
                'position' => 21
939
            ]
940
        );
941
942
        $form->setElement(
943
            'boolean',
944
            'showMiniBasket',
945
            [
946
                'label' => 'Warenkorb anzeigen',
947
                'value' => true,
948
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
949
                'helpText' => 'In dem Klarna Checkout wird eine kleine Übersicht des Warenkorbs angezeigt',
950
                'position' => 22
951
            ]
952
        );
953
954
        $form->setElement(
955
            'boolean',
956
            'showDispatch',
957
            [
958
                'label' => 'Lieferland & Versandarten anzeigen',
959
                'value' => true,
960
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
961
                'helpText' => 'In dem Klarna Checkout wird eine Lieferland- sowie Versandarten-Auswahl angezeigt',
962
                'position' => 23
963
            ]
964
        );
965
966
        $form->setElement(
967
            'select',
968
            'positionOrder',
969
            [
970
                'label' => 'Reihenfolge der Elemente',
971
                'value' => 1,
972
                'store' => [
973
                    [1, 'Login-Formular, Mini-Warenkorb, Versandauswahl, Zahlungsauswahl'],
974
                    [2, 'Login-Formular, Mini-Warenkorb, Zahlungsauswahl, Versandauswahl'],
975
                    [3, 'Versandauswahl, Zahlungsauswahl, Login-Formular, Mini-Warenkorb'],
976
                    [4, 'Zahlungsauswahl, Versandauswahl, Login-Formular, Mini-Warenkorb']
977
                ],
978
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
979
                'helpText' => 'Die \'Zahlungsauswahl\' wird nur in der \'Einseitig\'-Darstellung angezeigt.',
980
                'position' => 24
981
            ]
982
        );
983
984
        $form->setElement(
985
            'boolean',
986
            'partPaymentWidget',
987
            [
988
                'label' => 'Teilzahlungs-Widget auf der Detailseite anzeigen',
989
                'value' => true,
990
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
991
                'position' => 25
992
            ]
993
        );
994
995
        $form->setElement(
996
            'boolean',
997
            'convertShippingFee',
998
            [
999
                'label' => 'Versandkosten in eine Bestellposition umwandeln',
1000
                'value' => true,
1001
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1002
                'position' => 26
1003
            ]
1004
        );
1005
1006
        $form->setElement(
1007
            'select',
1008
            'statusId',
1009
            [
1010
                'label' => 'Zahlstatus nach der Bestellung',
1011
                'value' => 18,
1012
                'store' => 'base.PaymentStatus',
1013
                'displayField' => 'description',
1014
                'valueField' => 'id',
1015
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1016
                'position' => 27
1017
            ]
1018
        );
1019
1020
        $form->setElement(
1021
            'select',
1022
            'activateStatusId',
1023
            [
1024
                'label' => 'Zahlungsstatus nach der Aktivierung',
1025
                'value' => 12,
1026
                'store' => 'base.PaymentStatus',
1027
                'displayField' => 'description',
1028
                'valueField' => 'id',
1029
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1030
                'position' => 28
1031
            ]
1032
        );
1033
1034
        $form->setElement(
1035
            'select',
1036
            'cancelStatusId',
1037
            [
1038
                'label' => 'Zahlungsstatus nach der Stornierung',
1039
                'value' => 17,
1040
                'store' => 'base.PaymentStatus',
1041
                'displayField' => 'description',
1042
                'valueField' => 'id',
1043
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1044
                'position' => 29
1045
            ]
1046
        );
1047
        
1048
        $form->setElement(
1049
            'select',
1050
            'klarnaLogLevel',
1051
            [
1052
                'label' => 'Detaillevel der Logeinträge zur Fehlerverfolgung',
1053
                'value' => 0,
1054
                'store' => [
1055
                    [0, 'Nichts protokollieren'],
1056
                    [1, 'Nur Fehler protokollieren'],
1057
                    [2, 'Fehler und Warnungen protokollieren'],
1058
                    [3, 'Alle Meldungen protokollieren'],
1059
                    [4, 'Alle Meldungen und zusätzlich Entwicklerinformationen protokollieren (Große Logdateien!)'],
1060
                ],
1061
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1062
                '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.',
1063
                'position' => 30
1064
            ]
1065
        );
1066
    }
1067
1068
    /**
1069
     *
1070
     */
1071
    public function createMyTranslations()
1072
    {
1073
        $form = $this->Form();
1074
        $translations = $this->getTranslationArray();
1075
1076
        // In 4.2.2 we introduced a helper function for this, so we can skip the custom logic
1077
        if ($this->assertMinimumVersion('4.2.2')) {
1078
            $this->addFormTranslations($translations);
1079
            return true;
1080
        }
1081
1082
        $shopRepository = Shopware()->Models()->getRepository('\Shopware\Models\Shop\Locale');
1083
        foreach ($translations as $locale => $snippets) {
1084
            /** @var \Shopware\Models\Shop\Locale|null $localeModel */
1085
            $localeModel = $shopRepository->findOneBy(['locale' => $locale]);
1086
            if ($localeModel === null) {
1087
                continue;
1088
            }
1089
            foreach ($snippets as $element => $snippet) {
1090
                $translationModel = null;
1091
                //get the form element by name
1092
                $elementModel = $form->getElement($element);
1093
1094
                //not found? continue with next snippet
1095
                if ($elementModel === null) {
1096
                    continue;
1097
                }
1098
1099
                // Try to load existing translation
1100
                foreach ($elementModel->getTranslations() as $translation) {
1101
                    if ($translation->getLocale()->getLocale() == $locale) {
1102
                        $translationModel = $translation;
1103
                        break;
1104
                    }
1105
                }
1106
1107
                // If none found create a new one
1108
                if (!$translationModel) {
1109
                    $translationModel = new \Shopware\Models\Config\ElementTranslation();
1110
                    $translationModel->setLocale($localeModel);
1111
                    //add the translation to the form element
1112
                    $elementModel->addTranslation($translationModel);
1113
                }
1114
1115
                if ($snippet['label']) {
1116
                    $translationModel->setLabel($snippet['label']);
1117
                }
1118
1119
                if ($snippet['description']) {
1120
                    $translationModel->setDescription($snippet['description']);
1121
                }
1122
            }
1123
        }
1124
    }
1125
1126
    /**
1127
     *
1128
     */
1129
    public function createMyAttributes()
1130
    {
1131
        try {
1132
            $this->get('models')->addAttribute(
1133
                's_order_details_attributes',
1134
                'swag_klarna',
1135
                'invoice_number',
1136
                'VARCHAR(255)'
1137
            );
1138
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1139
        }
1140
1141
        $this->get('models')->generateAttributeModels(
1142
            [
1143
                's_order_details_attributes'
1144
            ]
1145
        );
1146
1147
        try {
1148
            $this->get('models')->addAttribute(
1149
                's_order_attributes',
1150
                'swag_klarna',
1151
                'status',
1152
                'VARCHAR(255)'
1153
            );
1154
            $this->get('models')->addAttribute(
1155
                's_order_attributes',
1156
                'swag_klarna',
1157
                'invoice_number',
1158
                'VARCHAR(255)'
1159
            );
1160
1161
            $this->get('models')->addAttribute(
1162
                's_core_paymentmeans_attributes',
1163
                'swag_klarna',
1164
                'show_in_klarna_iframe',
1165
                'int(11)'
1166
            );
1167
            $this->get('models')->addAttribute(
1168
                's_core_paymentmeans_attributes',
1169
                'swag_klarna',
1170
                'allow_in_payment_container',
1171
                'int(11)'
1172
            );
1173
            $this->get('models')->addAttribute(
1174
                's_core_paymentmeans_attributes',
1175
                'swag_klarna',
1176
                'klarna_media',
1177
                'VARCHAR(255)'
1178
            );
1179
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1180
        }
1181
1182
        $this->get('models')->generateAttributeModels(
1183
            [
1184
                's_order_attributes',
1185
                's_core_paymentmeans_attributes'
1186
            ]
1187
        );
1188
        
1189
        if ($this->assertMinimumVersion('5.2')) {
1190
            $this->get('shopware_attribute.crud_service')->update(
1191
                's_core_paymentmeans_attributes',
1192
                'swag_klarna_show_in_klarna_iframe',
1193
                'boolean',
1194
                [
1195
                    'label' => 'In Klarna Checkout einbinden',
1196
                    'helpText' => 'Bindet die Zahlungsart direkt in das Klarna iFrame ein',
1197
                    'displayInBackend' => true,
1198
                    'pluginId' => $this->getId()
1199
                ]
1200
            );
1201
            $this->get('shopware_attribute.crud_service')->update(
1202
                's_core_paymentmeans_attributes',
1203
                'swag_klarna_allow_in_payment_container',
1204
                'boolean',
1205
                [
1206
                    'label' => 'Nicht neben dem Klarna Checkout anzeigen',
1207
                    'helpText' => 'Versteckt die Zahlungsart in dem "Andere Zahlungsarten-Container" im Klarna Checkout',
1208
                    'displayInBackend' => true,
1209
                    'pluginId' => $this->getId()
1210
                ]
1211
            );
1212
            $this->get('shopware_attribute.crud_service')->update(
1213
                's_core_paymentmeans_attributes',
1214
                'swag_klarna_klarna_media',
1215
                'string',
1216
                [
1217
                    'label' => 'Bild Name für Klarna Checkout',
1218
                    'helpText' => 'Zeigt die Zahlungsart zusätzlich mit einem Bild im iFrame an. Funktioniert nur, wenn SSL konfiguriert ist. Optimale Größe: 276x48px.'
1219
                    . 'Das Bild muss im Order /media/image gespeichert werden',
1220
                    'displayInBackend' => true,
1221
                    'pluginId' => $this->getId()
1222
                ]
1223
            );
1224
        }
1225
    }
1226
1227
    public function registerMyTemplateDir($isBackend = false)
1228
    {
1229
        if ($isBackend) {
1230
            $this->get('template')->addTemplateDir(__DIR__ . '/Views/', 'klarna');
1231
        } elseif ($this->isTemplateResponsive()) {
1232
            $this->get('template')->addTemplateDir(__DIR__ . '/Views/responsive', 'klarna');
1233
        } else {
1234
            $this->get('template')->addTemplateDir(__DIR__ . '/Views/_emotion', 'klarna');
1235
        }
1236
    }
1237
1238
    /**
1239
     * Checks if the the current Template is responsive
1240
     *
1241
     * @return bool
1242
     */
1243
    public function isTemplateResponsive()
1244
    {
1245
        $template = $this->Application()->Shop()->getTemplate()->getVersion();
1246
        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...
1247
            return false;
1248
        }
1249
1250
        return true;
1251
    }
1252
1253
    /**
1254
     * Returns the path to a frontend controller for an event.
1255
     *
1256
     * @return string
1257
     */
1258
    public function onGetControllerPathFrontend()
1259
    {
1260
        $this->registerMyTemplateDir();
1261
1262
        return __DIR__ . '/Controllers/Frontend/PaymentKlarna.php';
1263
    }
1264
1265
    /**
1266
     * Returns the path to a backend controller for an event.
1267
     *
1268
     * @return string
1269
     */
1270
    public function onGetControllerPathBackend()
1271
    {
1272
        $this->registerMyTemplateDir(true);
1273
        $this->Application()->Snippets()->addConfigDir(
1274
            __DIR__ . '/Snippets/'
1275
        );
1276
1277
        return __DIR__ . '/Controllers/Backend/PaymentKlarna.php';
1278
    }
1279
1280
    /**
1281
     * @param Enlight_Event_EventArgs $args
1282
     */
1283
    public function onPostDispatch(Enlight_Event_EventArgs $args)
1284
    {
1285
        /** @var $action Enlight_Controller_Action */
1286
        $action = $args->getSubject();
1287
        $request = $action->Request();
1288
        $response = $action->Response();
1289
        $view = $action->View();
1290
1291
        if (!$request->isDispatched()
1292
            || $response->isException()
1293
            || $request->getModuleName() != 'frontend'
1294
            || !$view->hasTemplate()
1295
        ) {
1296
            return;
1297
        }
1298
1299
        // just return in case kco payment is deactivated in backend
1300
1301
        if (!$this->isKcoPaymentActive()){
1302
            return;
1303
        }
1304
        $user = $view->getAssign('sUserData');
1305
        $config = $this->Config();
1306
1307
        // this is used for showing klarna buttons in basket
1308
        if ($request->getControllerName() == 'checkout'
1309
            && ($request->getActionName() == 'cart' || $request->getActionName() == 'ajaxCart')
1310
        ) {
1311
            $this->registerMyTemplateDir();
1312
            $view->assign('KlarnaEnableButton', (bool)$config->get('showKlarnaButton'));
1313
            $view->assign('KlarnaShowCheckoutButton', $this->getShowCheckoutButton($user));
1314
            $view->assign('klarnaKcoPaymentActive', $this->isKlarnaKcoPaymentActive($user));
1315
            $view->assign('KlarnaPaymentDescription', $this->getPayment()->getDescription());
1316
            if (!$this->isTemplateResponsive()) {
1317
                $view->extendsTemplate('frontend/payment_klarna_checkout/cart.tpl');
1318
            }
1319
        }
1320
1321
        // show klarna invoice information on article detail pages
1322
        if (!empty($config->partPaymentWidget)
1323
            && $request->getControllerName() == 'detail' && $request->getActionName() == 'index'
1324
        ) {
1325
            $this->registerMyTemplateDir();
1326
            //Do not shot the logo on the detail page if the kpm-plugin is active
1327
            $view->KlarnaShowLogo = !$this->isKpmActive();
1328
            $view->KlarnaLocale = $this->getLocale();
1329
            $view->KlarnaMerchantId = $config->get('merchantId');
1330
            if (!$this->isTemplateResponsive()) {
1331
                $view->extendsTemplate('frontend/payment_klarna_part/detail.tpl');
1332
            }
1333
        }
1334
1335
        if ($request->getControllerName() == 'register' && $request->getActionName() == 'index') {
1336
            $this->registerMyTemplateDir();
1337
            $view->assign('KlarnaLocale', $this->getLocale());
1338
            $view->assign('KlarnaMerchantId', $config->get('merchantId'));
1339
            $view->assign('KlarnaHideCheckoutSteps', true);
1340
            
1341
            if (version_compare(Shopware::VERSION, '5.2.0', '<')){
1342
                $view->assign('KlarnaSkipLoginFix', true);
1343
            }
1344
            if (!$this->isTemplateResponsive()) {
1345
                $view->extendsTemplate('frontend/payment_klarna_checkout/register.tpl');
1346
            }
1347
            
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
1348
        }
1349
1350
        if ($request->getControllerName() == 'account' && $request->getActionName() == 'ajax_login') {
1351
            $this->registerMyTemplateDir();
1352
            $view->assign('KlarnaLocale', $this->getLocale());
1353
            $view->assign('KlarnaMerchantId', $config->get('merchantId'));
1354
            
1355
            if (!$this->isTemplateResponsive()) {
1356
                $view->extendsTemplate('frontend/payment_klarna_checkout/ajax_login.tpl');
1357
            }
1358
        }
1359
1360
    }
1361
1362
    /**
1363
     * Populate register form with saved data on changing klarna and register tabs
1364
     *
1365
     * @param Enlight_Event_EventArgs $args
1366
     */
1367
    public function onPostDispatchFrontendRegister($args)
1368
    {
1369
        /** @var $action Enlight_Controller_Action */
1370
        $action = $args->getSubject();
1371
        $view = $action->View();
1372
        $request = $action->Request();
1373
        /** @var Enlight_Components_Session_Namespace $session */
1374
        $session = $this->Application()->Session();
1375
1376
         // Switch User to external PaymentId after registration
1377
         if (isset($session['KlarnaExternalPaymentId'])) {
1378
                $this->savePayment($session['KlarnaExternalPaymentId']);
1379
        }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 9 spaces, found 8
Loading history...
1380
1381
       $view->assign('klarnaRedirect', $request->has('klarnaRedirect') && $request->getParam('klarnaRedirect') == 1);
1382
    }
1383
    
1384
1385
    /**
1386
     * Helper method to set the selected payment-method into the session to change it in the customer-account after logging in
1387
     *
1388
     * @param $paymentId
1389
     * @throws Enlight_Exception
1390
     */
1391
    public function savePayment($paymentId)
1392
    {
1393
        $admin = Shopware()->Modules()->Admin();
1394
        $admin->sSYSTEM->_POST['sPayment'] = $paymentId;
1395
        $admin->sUpdatePayment($paymentId);
1396
1397
    }
1398
1399
    public function addJsFiles()
1400
    {
1401
        $jsPath = [
1402
            __DIR__ . '/Views/responsive/frontend/_public/src/js/jquery.klarna_checkout.js'
1403
        ];
1404
1405
        return new Doctrine\Common\Collections\ArrayCollection($jsPath);
1406
    }
1407
1408
    /**
1409
     * @param Enlight_Event_EventArgs $args
1410
     */
1411 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...
1412
    {
1413
        /** @var $subject Enlight_Controller_Action */
1414
        $subject = $args->getSubject();
1415
        $request = $subject->Request();
1416
        $view = $subject->View();
1417
1418
        switch ($request->getActionName()) {
1419
            case 'load':
1420
                $this->registerMyTemplateDir(true);
1421
                $view->extendsTemplate('backend/order/payment_klarna.js');
1422
                break;
1423
            default:
1424
                break;
1425
        }
1426
    }
1427
1428
    /**
1429
     * @param Enlight_Event_EventArgs $args
1430
     */
1431 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...
1432
    {
1433
        /** @var $subject Enlight_Controller_Action */
1434
        $subject = $args->getSubject();
1435
        $request = $subject->Request();
1436
        $view = $subject->View();
1437
1438
        switch ($request->getActionName()) {
1439
            case 'load':
1440
                $this->registerMyTemplateDir(true);
1441
                $view->extendsTemplate('backend/payment/payment_klarna.js');
1442
                break;
1443
            default:
1444
                break;
1445
        }
1446
    }
1447
1448
    public function updateOrderVariables()
1449
    {
1450
        $session = Shopware()->Session();
1451
        $admin = Shopware()->Modules()->Admin();
1452
        /** @var ArrayObject $orderVariables */
1453
        $orderVariables = $session['sOrderVariables'];
1454
        $userData = $admin->sGetUserData();
1455
        $userData['payment'] = $orderVariables['sUserData']['payment'];
1456
        $userData['additional'] = array_merge(
1457
            $orderVariables['sUserData']['additional'],
1458
            $userData['additional']
1459
        );
1460
        
1461
        if (isset($session['sChangedCountry'])){
1462
            
1463
            /** @var \Shopware\Components\Model\ModelManager $em */
1464
            $em = $this->get('models');
1465
1466
            /** @var \Shopware\Models\Customer\Customer $customer */
1467
            $country = $em->getRepository('Shopware\Models\Country\Country')->findOneBy(['id' => $session['sChangedCountry']]);
1468
            $userData['shippingaddress']['country'] =$country;     
1469
            $userData['billingaddress']['country'] =$country;   
1470
            $userData['shippingaddress']['countryID'] = $session['sChangedCountry'];
1471
            $userData['billingaddress']['countryID'] = $session['sChangedCountry'];
1472
         }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 8 spaces, found 9
Loading history...
1473
        
1474
        $orderVariables['sUserData'] = $userData;
1475
        $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...
1476
1477
    }
1478
1479
    /**
1480
     * @param $shop Shopware\Models\Shop\Shop
1481
     * @return int|null
1482
     */
1483
    public function getCountryByShop($shop)
1484
    {
1485
        $locale = $shop->getLocale()->getLocale();
1486
        $this->klarnaLog("Entering Bootstrap::getCountryByShop", 3);
1487
        $locale = explode('_', $locale);
1488
        $locale = isset($locale[1]) ? $locale[1] : $locale[0];
1489
        $this->klarnaLog("Bootstrap::getCountryByShop locale to request for:".$locale,3);
1490
        $sql = 'SELECT id FROM s_core_countries WHERE countryiso=?';
1491
        $countryId = Shopware()->Db()->fetchOne($sql, [$locale]);
1492
        $countryId = ($countryId) ? (int)$countryId : null;
1493
                
1494
        return $countryId;
1495
    }
1496
1497
    /**
1498
     * Get user country by country id
1499
     *
1500
     * @param $id
1501
     * @return string
1502
     */
1503
    public function getCountryIsoById($id)
1504
    {
1505
        $sql = 'SELECT countryiso FROM s_core_countries WHERE id = ?';
1506
        $countryIso = Shopware()->Db()->fetchOne($sql, [$id]);
1507
1508
        return $countryIso;
1509
    }
1510
1511
    public function getLocale($underscore = false, $countryIso = null)
1512
    {
1513
        /** @var \Shopware\Models\Shop\Shop $shop */
1514
        $shop = $this->Application()->Shop();
1515
        $locale = $shop->getLocale()->getLocale();
1516
        $locale = strtolower($locale);
1517
        if (!$underscore) {
1518
            $locale = str_replace('_', '-', $locale);
1519
        }
1520
        $locale = $locale == 'nn-no' ? 'nb-no' : $locale;
1521
1522
        if ($locale == 'de-de') {
1523
            if($countryIso == 'CH') {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
1524
                $locale = 'de-ch';
1525
            } elseif ($countryIso == 'AT') {
1526
                $locale = 'de-at';
1527
            }
1528
        }
1529
1530
        return $locale;
1531
    }
1532
1533
    public function getCheckoutOptions($allowPackstation = true, $dispatch = [])
1534
    {
1535
        $config = $this->Config();
1536
        $options = $this->getColorConfigOptions($config);
1537
1538
        $options['allow_separate_shipping_address'] = (bool)$config->get('allowSeparateShippingAddress');
1539
        $options['packstation_enabled'] = (bool)$config->get('supportPackstation') && $allowPackstation;
1540
        $options['phone_mandatory'] = (bool)$config->get('mandatoryPhone');
1541
        $options['date_of_birth_mandatory'] = (bool)$config->get('mandatoryBirthday');
1542
1543
        if (!empty($dispatch)) {
1544
            $options['shipping_details'] = $dispatch['description'];
1545
        }
1546
1547
        return $options;
1548
    }
1549
1550
    public function getCheckoutCart($basket)
1551
    {
1552
        $cart = [];
1553
        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...
1554
            // compatibility to shopware plugin custom products
1555
            if (isset($basketItem['custom_product_prices'])) {
1556
                $basketItemPrice = (double)$basketItem['custom_product_prices']['total'];
1557
            }
1558
            else {
1559
                $basketItemPrice = (double)str_replace(',', '.', $basketItem['price']);
1560
            }
1561
            $unitPrice = round($basketItemPrice * 100);
1562
            $cart[] = [
1563
                'type' => $unitPrice >= 0 ? 'physical' : 'discount',
1564
                'reference' => $basketItem['ordernumber'],
1565
                'name' => $basketItem['articlename'],
1566
                'quantity' => (int)$basketItem['quantity'],
1567
                'unit_price' => (int)$unitPrice,
1568
                'tax_rate' => (int)round($basketItem['tax_rate'] * 100)
1569
            ];
1570
        }
1571
        if (!empty($basket['sShippingcosts'])) {
1572
            $shippingCostsWithTax = $basket['sShippingcostsWithTax'];
1573
            $shippingAmount = !empty($shippingCostsWithTax) ? $shippingCostsWithTax : $basket['sShippingcosts'];
1574
            $cart[] = [
1575
                'type' => 'shipping_fee',
1576
                'reference' => 'SHIPPING',
1577
                'name' => 'Shipping Fee',
1578
                'quantity' => 1,
1579
                'unit_price' => (int)round($shippingAmount * 100),
1580
                'tax_rate' => (int)round($basket['sShippingcostsTax'] * 100),
1581
            ];
1582
        }
1583
1584
        return $cart;
1585
    }
1586
1587
    public function getCheckoutMerchant()
1588
    {
1589
        /** @var \Shopware\Components\Routing\RouterInterface $router */
1590
        $router = $this->Application()->Front()->Router();
1591
        $merchant = [];
1592
        $merchant['id'] = $this->Config()->get('merchantId');
1593
        $merchant['terms_uri'] = $router->assemble(
1594
            [
1595
                'controller' => 'custom',
1596
                'sCustom' => $this->Config()->get('termSiteId', 4),
1597
                'forceSecure' => true
1598
            ]
1599
        );
1600
        $merchant['checkout_uri'] = $router->assemble(
1601
            [
1602
                'action' => 'confirm'
1603
            ]
1604
        );
1605
        $merchant['confirmation_uri'] = $router->assemble(
1606
            [
1607
                'controller' => 'payment_klarna',
1608
                'action' => 'return',
1609
                'forceSecure' => true
1610
            ]
1611
        ) . "?transactionId={checkout.order.uri}";
1612
        $merchant['push_uri'] = $router->assemble(
1613
            [
1614
                'controller' => 'payment_klarna',
1615
                'action' => 'push',
1616
                'forceSecure' => true,
1617
                'appendSession' => true
1618
            ]
1619
        ) . "&transactionId={checkout.order.uri}";
1620
        $merchant['back_to_store_uri'] = $router->assemble(
1621
            [
1622
                'controller' => 'index',
1623
                'action' => 'index'
1624
            ]
1625
        );
1626
1627
        return $merchant;
1628
    }
1629
1630
    public function getCheckoutAddress($user, $type = 'billing')
1631
    {
1632
        if (empty($user[$type . 'address']['zipcode']) || $user[$type . 'address']['zipcode'] == '00000') {
1633
            return [];
1634
        }
1635
1636
        $address = [
1637
            'given_name' => $user[$type . 'address']['firstname'],
1638
            'family_name' => $user[$type . 'address']['lastname'],
1639
            'postal_code' => $user[$type . 'address']['zipcode'],
1640
            'city' => $user[$type . 'address']['city'],
1641
            'country' => $user['additional'][$type == 'billing' ? 'country' : 'countryShipping']['countryiso'],
1642
            'email' => $user['additional']['user']['email'],
1643
            'phone' => $user['billingaddress']['phone'],
1644
        ];
1645
        $address['country'] = strtolower($address['country']);
1646
        if ($address['country'] == 'de' || $address['country'] == 'nl') {
1647
            $address['title'] = $user[$type . 'address']['salutation'] == 'ms' ? 'Frau' : 'Herr';
1648
            if ($this->assertMinimumVersion('5.0.0')) {
1649
                /** @var StreetSplitService $streetSplitService */
1650
                $streetSplitService = Shopware()->StreetSplitService();
1651
                $streetAndNumber = $streetSplitService->split($user[$type . 'address']['street']);
1652
1653
                $address['street_name'] = $streetAndNumber['streetName'];
1654
                $address['street_number'] = $streetAndNumber['streetNumber'];
1655 View Code Duplication
            } else {
1656
                $address['street_name'] = $user[$type . 'address']['street'];
1657
                $address['street_number'] = $user[$type . 'address']['streetnumber'];
1658
            }
1659 View Code Duplication
        } else {
1660
            $address['street_address'] = trim(
1661
                $user[$type . 'address']['street'] . ' ' . $user[$type . 'address']['streetnumber']
1662
            );
1663
        }
1664
1665
        // Make sure phone number is unset if empty
1666
        if ($address['phone'] === null){
1667
            unset($address['phone']);
1668
        }
1669
        return $address;
1670
    }
1671
1672
    public function getCheckoutCustomer($user)
1673
    {
1674
        $customer = [
1675
            'type' => 'person'
1676
        ];
1677
        if (!empty($user['billingaddress']['birthday']) && $user['billingaddress']['birthday'] != '0000-00-00') {
1678
            $customer['date_of_birth'] = $user['billingaddress']['birthday'];
1679
        }
1680
        // SW 5.2 and newer
1681
        if (!empty($user['additional']['user']['birthday']) && $user['additional']['user'] != '0000-00-00') {
1682
            $customer['date_of_birth'] = $user['additional']['user']['birthday'];
1683
        }
1684
1685
        return $customer;
1686
    }
1687
1688
    /**
1689
     *
1690
     * @return string
1691
     */
1692
    public function getLabel()
1693
    {
1694
        return 'Klarna Checkout';
1695
    }
1696
1697
    /**
1698
     * @return string
1699
     * @throws Exception
1700
     */
1701
    public function getVersion()
1702
    {
1703
        $info = json_decode(file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'plugin.json'), true);
1704
1705
        if ($info) {
1706
            return $info['currentVersion'];
1707
        } else {
1708
            throw new Exception('The plugin has an invalid version file.');
1709
        }
1710
    }
1711
1712
    /**
1713
     * @return array
1714
     */
1715
    public function getInfo()
1716
    {
1717
        return [
1718
            'version' => $this->getVersion(),
1719
            'label' => $this->getLabel(),
1720
            'description' => file_get_contents(__DIR__ . '/info.txt')
1721
        ];
1722
    }
1723
1724
    /**
1725
     * Creates and returns the klarna client for an event.
1726
     *
1727
     * @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...
1728
     */
1729
    public function onInitResourceKlarnaCheckoutConnector()
1730
    {
1731
        require_once __DIR__ . '/Components/KlarnaCheckout/Checkout.php';
1732
        if ($this->Config()->get('testDrive')) {
1733
            Klarna_Checkout_Order::$baseUri = 'https://checkout.testdrive.klarna.com/checkout/orders';
1734
        } else {
1735
            Klarna_Checkout_Order::$baseUri = 'https://checkout.klarna.com/checkout/orders';
1736
        }
1737
        Klarna_Checkout_Order::$contentType = "application/vnd.klarna.checkout.aggregated-order-v2+json";
1738
        $sharedSecret = $this->Config()->get('sharedSecret');
1739
        $connector = Klarna_Checkout_Connector::create($sharedSecret);
1740
        $this->klarnaLog("Created Klarna Connector:", 4, $connector);
1741
1742
        return $connector;
1743
    }
1744
1745
    /**
1746
     * @return Klarna
1747
     */
1748
    public function onInitResourceKlarnaService()
1749
    {
1750
        require_once __DIR__ . '/Components/Klarna/Klarna.php';
1751
        require_once __DIR__ . '/Components/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
1752
1753
        $k = new Klarna();
1754
        return $k;
1755
    }
1756
1757
    /**
1758
     * Provide the file collection for less
1759
     *
1760
     * @return \Doctrine\Common\Collections\ArrayCollection
1761
     */
1762
    public function addLessFiles()
1763
    {
1764
        $less = new \Shopware\Components\Theme\LessDefinition(
1765
            [],
1766
            [
1767
                __DIR__ . '/Views/responsive/frontend/_public/src/less/all.less'
1768
            ],
1769
            __DIR__
1770
        );
1771
1772
        return new Doctrine\Common\Collections\ArrayCollection([$less]);
1773
    }
1774
1775
    /**
1776
     * @param string $requiredVersion
1777
     * @return bool|mixed
1778
     */
1779
    protected function assertMinimumVersion($requiredVersion)
1780
    {
1781
        if (Shopware::VERSION === '___VERSION___') {
1782
            return true;
1783
        }
1784
1785
        return version_compare(Shopware::VERSION, $requiredVersion, '>=');
1786
    }
1787
1788
    /**
1789
     * This event is executed when the expressAction of the checkout-controller should be executed.
1790
     * It is needed to redirect the user back to the klarna checkout after deleting an article in the klarna checkout.
1791
     *
1792
     * @param Enlight_Event_EventArgs $args
1793
     * @return bool
1794
     */
1795
    public function onCheckoutExpress(Enlight_Event_EventArgs $args)
1796
    {
1797
        /** @var $action Enlight_Controller_Action */
1798
        $action = $args->get('subject');
1799
1800
        $action->redirect(['controller' => 'payment_klarna', 'action' => 'express']);
1801
        return true;
1802
    }
1803
1804
    /**
1805
     * Helper method to read the color-config options properly.
1806
     *
1807
     * @param $config Enlight_Config
1808
     * @return mixed
1809
     */
1810
    private function getColorConfigOptions($config)
1811
    {
1812
        $options = [];
1813
        $checkoutButtonColor = $config->get('checkoutButtonColor');
1814
        $checkoutButtonTextColor = $config->get('checkoutButtonTextColor');
1815
        $checkoutCheckboxColor = $config->get('checkoutCheckboxColor');
1816
        $checkoutCheckboxCheckMarkColor = $config->get('checkoutCheckboxCheckmarkColor');
1817
        $checkoutHeaderColor = $config->get('checkoutHeaderColor');
1818
        $checkoutLinkColor = $config->get('checkoutLinkColor');
1819
1820
        if (!empty($checkoutButtonColor) && $checkoutButtonColor !== "#") {
1821
            $options['color_button'] = $checkoutButtonColor;
1822
        }
1823
        if (!empty($checkoutButtonTextColor) && $checkoutButtonTextColor !== "#") {
1824
            $options['color_button_text'] = $checkoutButtonTextColor;
1825
        }
1826
        if (!empty($checkoutCheckboxColor) && $checkoutCheckboxColor !== "#") {
1827
            $options['color_checkbox'] = $checkoutCheckboxColor;
1828
        }
1829
        if (!empty($checkoutCheckboxCheckMarkColor) && $checkoutCheckboxCheckMarkColor !== "#") {
1830
            $options['color_checkbox_checkmark'] = $checkoutCheckboxCheckMarkColor;
1831
        }
1832
        if (!empty($checkoutHeaderColor) && $checkoutHeaderColor !== "#") {
1833
            $options['color_header'] = $checkoutHeaderColor;
1834
        }
1835
        if (!empty($checkoutLinkColor) && $checkoutLinkColor !== "#") {
1836
            $options['color_link'] = $checkoutLinkColor;
1837
        }
1838
1839
        return $options;
1840
    }
1841
1842
    /**
1843
     * @param $view Enlight_View_Default
1844
     * @param $config Enlight_Config
1845
     */
1846
    public function getViewConfig($view, $config)
1847
    {
1848
        /** @var sAdmin $adminModule */
1849
        $adminModule = $this->get('modules')->Admin();
1850
        $session = $this->get('session');
1851
        $view->assign('sCountryId', $session['sCountry']);
1852
        $view->assign('sPayments', $this->filterPayments($adminModule->sGetPaymentMeans()));
1853
        $view->assign('sCountryList', $adminModule->sGetCountryList());
1854
        $view->assign('KlarnaHideCheckoutSteps', true);
1855
        $view->assign('KlarnaShowB2bSelect', (bool)$config->get('showB2bSelect'));
1856
        $view->assign('KlarnaShowBasket', (bool)$config->get('showMiniBasket'));
1857
        $view->assign('KlarnaShowDispatch', (bool)$config->get('showDispatch'));
1858
        $view->assign(
1859
            'KlarnaCDNLink',
1860
            $this->buildCDNLink()
1861
        );
1862
        $view->assign(
1863
            'KlarnaLoggedInUser',
1864
            $view->sUserData['billingaddress']['lastname'] == 'Klarna Checkout'
1865
        );
1866
        $view->assign(
1867
            'KlarnaShowLogin',
1868
            $this->getShowLoginConfig($config, !empty($session->sUserId))
1869
        );
1870
        $view->assign(
1871
            'KlarnaDisplayType',
1872
            $this->getKlarnaDisplayType($config)
1873
        );
1874
        $view->assign(
1875
            'KlarnaPositionOrder',
1876
            $this->getPositionOrder($config)
1877
        );
1878
    }
1879
1880
    /**
1881
     * Helper method to get the config whether or not to show the login-panel in the klarna-checkout.
1882
     *
1883
     * @param Enlight_Config $config
1884
     * @param $userLoggedIn
1885
     * @return bool
1886
     */
1887
    private function getShowLoginConfig($config, $userLoggedIn)
1888
    {
1889
        return (bool) $config->get('showLoginPanel') && !($userLoggedIn);
1890
    }
1891
1892
    /**
1893
     * Helper method to find the correct display-type for the frontend.
1894
     * Will return the value configured in the plugin-config, if there is at least one more payment-mean besides klarna.
1895
     * @param $config Enlight_Config
1896
     * @return int
1897
     */
1898
    private function getKlarnaDisplayType($config)
1899
    {
1900
        if (!$this->getOtherPayments()) {
1901
            return 2;
1902
        }
1903
        return $config->get('displayType');
1904
    }
1905
1906
    /**
1907
     * Helper method to find other payment-means besides klarna.
1908
     * @return bool
1909
     */
1910
    private function getOtherPayments()
1911
    {
1912
        $payments = $this->Application()->Modules()->Admin()->sGetPaymentMeans();
1913
1914
        foreach ($payments as $payment) {
1915
            if ($payment['action'] != 'payment_klarna') {
1916
                return true;
1917
            }
1918
        }
1919
1920
        return false;
1921
    }
1922
1923
    /**
1924
     * Helper method to figure out whether or not to show the extra klarna checkout button.
1925
     *
1926
     * @param array $user
1927
     * @return bool
1928
     */
1929
    private function getShowCheckoutButton($user)
1930
    {
1931
        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...
1932
            $user['additional']['payment']['id'] != $this->getPayment()->getId()
1933
        ) {
1934
            return true;
1935
        }
1936
1937
        return false;
1938
    }
1939
1940
    /**
1941
     * Helper method to get the correct order for the elements
1942
     *
1943
     * @param $config Enlight_Config
1944
     * @return array Array with the order of the elements
1945
     */
1946
    private function getPositionOrder($config)
1947
    {
1948
        $loginPanel = 'login_panel';
1949
        $miniBasket = 'mini_basket';
1950
        $dispatch = 'dispatch';
1951
        $payments = 'payments';
1952
        switch ($config->get('positionOrder')) {
1953
            case 1:
1954
                return [$loginPanel, $miniBasket, $dispatch, $payments];
1955
            case 2:
1956
                return [$loginPanel, $miniBasket, $payments, $dispatch];
1957
            case 3:
1958
                return [$dispatch, $payments, $loginPanel, $miniBasket];
1959
            case 4:
1960
            default:
1961
                return [$payments, $dispatch, $loginPanel, $miniBasket];
1962
        }
1963
    }
1964
1965
    /**
1966
     * Helper method to build the proper cdn-link for the image in the tabs-layout.
1967
     * @return string
1968
     */
1969
    private function buildCDNLink()
1970
    {
1971
        $validLocales = [
1972
            'de_de',
1973
            'de_at',
1974
            'en_us',
1975
            'en_gb',
1976
            'fi_fi',
1977
            'sv_se',
1978
            'nb_no',
1979
        ];
1980
        $locale = str_replace('-', '_', $this->getLocale());
1981
1982
        if (!in_array($locale, $validLocales)) {
1983
            $locale = 'en_gb';
1984
        }
1985
        return "https://cdn.klarna.com/1.0/shared/image/generic/badge/{$locale}/checkout/long-no-klarna-logo.png";
1986
    }
1987
1988
    /**
1989
     * Helper method to read the customer-data from the klarna order-object.
1990
     * @param Klarna_Checkout_Order $order
1991
     * @return array
1992
     */
1993
    private function getKlarnaCustomerData($order)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
1994
    {
1995
        $billingAddress = $order['billing_address'];
1996
1997
        return [
1998
            'personal' => [
1999
                'customer_type' => 'private',
2000
                'salutation' => $billingAddress['title'],
2001
                'firstname' => $billingAddress['given_name'],
2002
                'lastname' => $billingAddress['family_name'],
2003
                'email' => $billingAddress['email'],
2004
                'birthday' => $order['customer']['date_of_birth'],
2005
                'phone' => $billingAddress['phone']
2006
            ],
2007
            'billing' => [
2008
                'street' => $billingAddress['street_name'] . ' ' . $billingAddress['street_number'],
2009
                'zipcode' => $billingAddress['postal_code'],
2010
                'city' => $billingAddress['city']
2011
            ]
2012
        ];
2013
    }
2014
2015
    /**
2016
     * Returns an array with all translations
2017
     * @return array
2018
     */
2019
    private function getTranslationArray()
2020
    {
2021
        return [
2022
            'en_GB' => [
2023
                'testDrive' => [
2024
                    'label' => 'Activate test-modus'
2025
                ],
2026
                'merchantId' => [
2027
                    'label' => 'API merchant ID (EID)'
2028
                ],
2029
                'sharedSecret' => [
2030
                    'label' => 'API-Secret (sharedsecret)'
2031
                ],
2032
                'termSiteId' => [
2033
                    'label' => 'Shopsite including the terms and conditions'
2034
                ],
2035
                'allowSeparateShippingAddress' => [
2036
                    'label' => 'Enable differing shipping address'
2037
                ],
2038
                'supportPackstation' => [
2039
                    'label' => 'Support DHL-packstation',
2040
                    'helpText' => 'The differing shipping address must be enabled'
2041
                ],
2042
                'postnumberField' => [
2043
                    'label' => 'Alternative field for the DHL-postnumber'
2044
                ],
2045
                'mandatoryPhone' => [
2046
                    'label' => 'Phone mandatory field'
2047
                ],
2048
                'mandatoryBirthday' => [
2049
                    'label' => 'Birthday mandatory field'
2050
                ],
2051
                'disableAutofocus' => [
2052
                    'label' => 'Disable auto-focus'
2053
                ],
2054
                'showKlarnaButton' => [
2055
                    'label' => 'Show klarna-checkout button'
2056
                ],
2057
                'checkoutButtonColor' => [
2058
                    'label' => 'Checkout Button Color'
2059
                ],
2060
                'checkoutButtonTextColor' => [
2061
                    'label' => 'Checkout Buttontext Color'
2062
                ],
2063
                'checkoutCheckboxColor' => [
2064
                    'label' => 'Checkout Checkbox Color'
2065
                ],
2066
                'checkoutCheckboxCheckmarkColor' => [
2067
                    'label' => 'Checkout Checkbox Tick Color'
2068
                ],
2069
                'checkoutHeaderColor' => [
2070
                    'label' => 'Checkout Header Color'
2071
                ],
2072
                'checkoutLinkColor' => [
2073
                    'label' => 'Checkout Link Color'
2074
                ],
2075
                'KlarnaExternalPayments' => [
2076
                    'label' => 'Display external payment-methods in klarna checkout',
2077
                    'helpText' => 'Your klarna-account has to be unlocked for this feature',
2078
                ],
2079
                'displayType' => [
2080
                    'label' => 'Klarna Checkout display-type',
2081
                    'store' => [
2082
                        [1, 'Display tabs'],
2083
                        [2, 'Display only klarna checkout'],
2084
                        [3, 'One-page display']
2085
                    ],
2086
                ],
2087
                'showB2bSelect' => [
2088
                    'label' => 'Show B2B-select',
2089
                    'helpText' => 'Displays a new select-box containing "Private customer" and "Company" in the klarna checkout'
2090
                ],
2091
                'showLoginPanel' => [
2092
                    'label' => 'Show login-panel',
2093
                    'helpText' => 'Displays a login-panel in the klarna-checkout',
2094
                ],
2095
                'showMiniBasket' => [
2096
                    'label' => 'Show mini-basket',
2097
                    'helpText' => 'Displays a small overview of the basket in the klarna-checkout',
2098
                ],
2099
                'showDispatch' => [
2100
                    'label' => 'Show shipping-country and -method',
2101
                    'helpText' => 'Shows a shipping-country and shipping-method select in the klarna-checkout'
2102
                ],
2103
                'partPaymentWidget' => [
2104
                    'label' => 'Show partial-payment-widget on detail-page'
2105
                ],
2106
                'convertShippingFee' => [
2107
                    'label' => 'Convert shipping-costs to an order-position'
2108
                ],
2109
                'statusId' => [
2110
                    'label' => 'Payment status after order'
2111
                ],
2112
                'activateStatusId' => [
2113
                    'label' => 'Payment status after activation'
2114
                ],
2115
                'cancelStatusId' => [
2116
                    'label' => 'Payment status after cancellation'
2117
                ]
2118
            ]
2119
        ];
2120
    }
2121
2122
    /**
2123
     * Helper method to update the klarna-payment when updating from any version to >= 2.0 of klarna.
2124
     * It adds "austria" to the valid countries.
2125
     */
2126
    private function updatePayment()
2127
    {
2128
        /** @var \Shopware\Components\Model\ModelManager $manager */
2129
        $manager = $this->get('models');
2130
        $payment = $manager->getRepository('Shopware\Models\Payment\Payment')->findOneBy([
2131
            'name' => 'klarna_checkout'
2132
        ]);
2133
2134
        if (empty($payment)) {
2135
            return;
2136
        }
2137
2138
        $updateNeeded = true;
2139
        $countries = $payment->getCountries();
2140
        /** @var Shopware\Models\Country\Country $country */
2141
        foreach ($countries as $country) {
2142
            if ($country->getIso() == 'AT') {
2143
                $updateNeeded = false;
2144
            }
2145
        }
2146
2147
        if ($updateNeeded) {
2148
            $countries->add($manager->getRepository('Shopware\Models\Country\Country')->findOneBy(['iso' => 'AT']));
2149
            $payment->setCountries($countries);
2150
2151
            $manager->persist($payment);
2152
            $manager->flush();
2153
        }
2154
    }
2155
2156
    /**
2157
     * Method checks if selected country is valid for use with klarna
2158
     * 
2159
     * @param string $countryId
2160
     * @return boolean
2161
     */
2162
    public function checkValidKlarnaCountry($countryId)
2163
    {
2164
        $allowedCountries = [];
2165
        $countries = $this->getPayment()->getCountries();
2166
        foreach ($countries as $country) {
2167
            $allowedCountries[] = $country->getId();
2168
        }
2169
2170
        $countryPaymentisAllowed = in_array($countryId, $allowedCountries);
2171
        // early return if country is not active for KCO in backend settings
2172
        if (!$countryPaymentisAllowed) {
2173
            return false;
2174
        }
2175
2176
        // always allow austrian KCO for german shops and vice-versa
2177
        $shopCountry = $this->getCountryByShop(Shopware()->Shop());
2178
        if ($shopCountry == "2" && $countryId == "23") {
2179
            return true;
2180
        } elseif ($shopCountry == "23" && $countryId == "2") {
2181
            return true;
2182
        } else {
2183
            return ($countryId == $shopCountry);
2184
        }
2185
    }
2186
    
2187
2188
    /**
2189
     * Helper method to read all payments, that should be displayed in the klarna checkout.
2190
     * @param $basket
2191
     * @return array
2192
     */
2193
    public function getExternalPaymentMethods($basket)
2194
    {
2195
        $payments = Shopware()->Models()->getRepository('Shopware\Models\Attribute\Payment')->findBy([
2196
            'swagKlarnaShowInKlarnaIframe' => 1,
2197
            'swagKlarnaAllowInPaymentContainer' => 0
2198
        ]);
2199
2200
        $externalPayments = [];
2201
        $externalCheckouts = [];
2202
        /** @var Shopware\Models\Attribute\Payment $payment */
2203
        foreach ($payments as $payment) {
2204
            $paymentObj = $payment->getPayment();
2205
            if (is_null($paymentObj)) {
2206
                $paymentName = false;
2207
            } else {
2208
                $paymentName = $paymentObj->getName();
2209
            }
2210
            
2211
            if (!$paymentName) {
2212
                continue;
2213
            }
2214
            
2215
            if ($paymentName && $paymentName == 'klarna_checkout') {
2216
                continue;
2217
            }
2218
            $paymentArray = [
2219
                'name' => $payment->getPayment()->getDescription(),
2220
                'redirect_uri' => $this->getRedirectUri() . '/paymentId/' . $payment->getPaymentId()
2221
            ];
2222
2223
            if ($fee = $this->getFee($payment->getPayment(), $basket)) {
2224
                $paymentArray['fee'] = $fee;
2225
            }
2226
2227
            if ($description = $payment->getPayment()->getAdditionalDescription()) {
2228
                //Shorten the description to max. 500 characters
2229
                $description = strip_tags($description);
2230
                $description = preg_replace('#<!--.*-->#ms', '', $description);
2231
                $paymentArray['description'] = substr($description, 0, 497) . '...';
2232
            }
2233
2234
            //Only add to external checkouts if an image is set and if the shop supports SSL
2235
            if (Shopware()->Shop()->getSecure() && $image = $this->getImageForKlarna($payment)) {
2236
                $paymentArray['image_uri'] = $image;
2237
                $externalCheckouts[] = $paymentArray;
2238
            }
2239
2240
            $externalPayments[] = $paymentArray;
2241
        }
2242
2243
        return [$externalPayments, $externalCheckouts];
2244
    }
2245
2246
    /**
2247
     * @param Shopware\Models\Payment\Payment $payment
2248
     * @param $basket
2249
     * @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...
2250
     */
2251
    private function getFee($payment, $basket)
2252
    {
2253
        $fee = 0;
2254
        $amount = str_replace(',', '.', $basket['Amount']);
2255
2256
        if ($surcharge = $payment->getSurcharge()) {
2257
            $fee += $surcharge;
2258
            $amount += $surcharge;
2259
        }
2260
2261
        if ($percent = $payment->getDebitPercent()) {
2262
            $fee += round($amount / 100 * $percent, 3);
2263
        }
2264
2265
        return round($fee * 100);
2266
    }
2267
2268
    /**
2269
     * Helper method to get the redirect-uri
2270
     * @return string
2271
     */
2272
    private function getRedirectUri()
2273
    {
2274
        return Shopware()->Front()->Router()->assemble([
2275
            'controller' => 'PaymentKlarna',
2276
            'action' => 'setPayment'
2277
        ]);
2278
    }
2279
2280
    /**
2281
     * Helper method to read the image for the klarna-checkout if set
2282
     * @param Shopware\Models\Attribute\Payment $payment
2283
     * @return null|string
2284
     */
2285
    private function getImageForKlarna($payment)
2286
    {
2287
        $media = $payment->getSwagKlarnaKlarnaMedia();
2288
        if (!$payment->getSwagKlarnaShowInKlarnaIframe() || !empty($media)) {
2289
            if ($this->assertMinimumVersion('5.1') && version_compare(Shopware::VERSION, '5.2.0', '<=')) {
2290
                $media = $this->get('shopware_media.media_service')->getUrl($media);
2291
            } else {
2292
                /** @var Enlight_Controller_Front $front */
2293
                $front = $this->get('front');
2294
                $request = $front->Request();
2295
                if ($request && $request->getHttpHost()) {
2296
                    $url = ($request->isSecure() ? 'https' : 'http') .
2297
                        '://' . $request->getHttpHost() .
2298
                        $request->getBasePath() . "/";
2299
                } else {
2300
                    $url = $front->Router()->assemble(['controller' => 'index', 'module' => 'frontend']);
2301
                }
2302
                if (version_compare(Shopware::VERSION, '5.2.0', '>=')) {
2303
                    # make sure me get only the image name, path is set in case of upgarde from SW.5.1 to 5.2
2304
                    $parts = explode('/', $media);
2305
                    $end = end($parts);
2306
                    $media = $url . 'media/image/' . $end;
2307
                } else {
2308
                    $media = $url . $media;
2309
                }
2310
            }
2311
2312
            return $media;
2313
        }
2314
        return null;
2315
    }
2316
2317
    /**
2318
     * Helper method to filter the available payment-means.
2319
     * @param $sGetPaymentMeans
2320
     * @return array
2321
     */
2322
    public function filterPayments($sGetPaymentMeans)
2323
    {
2324
        $paymentArray = [];
2325
        foreach ($sGetPaymentMeans as $paymentMean) {
2326
            if (!$this->isPaymentAllowed($paymentMean)) {
2327
                continue;
2328
            }
2329
2330
            $paymentArray[] = $paymentMean;
2331
        }
2332
        return $paymentArray;
2333
    }
2334
2335
    /**
2336
     * Helper method to check if a payment is allowed to be
2337
     * @param $payment
2338
     * @return bool
2339
     */
2340
    private function isPaymentAllowed($payment)
2341
    {
2342
        if ($payment['name'] == 'klarna_checkout') {
2343
            return false;
2344
        }
2345
        $connection = Shopware()->Models()->getConnection();
2346
2347
        $builder = $connection->createQueryBuilder();
2348
        $builder->select('swag_klarna_allow_in_payment_container', 'swag_klarna_show_in_klarna_iframe')
2349
            ->from('s_core_paymentmeans_attributes')
2350
            ->where('paymentmeanID = :id')
2351
            ->setParameter(':id', $payment['id']);
2352
2353
        $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...
2354
        return !$result['swag_klarna_allow_in_payment_container'] && !$result['swag_klarna_show_in_klarna_iframe'];
2355
    }
2356
2357
    /**
2358
     * Builds the new klarna version-string.
2359
     *
2360
     * @param Klarna $klarna
2361
     * @return string
2362
     */
2363
    private function buildKlarnaVersion(Klarna $klarna)
2364
    {
2365
        $versionInfo = [
2366
            'Shopware',
2367
            $this->Application()->Config()->version,
2368
            'KCO-Plugin',
2369
            $this->getVersion(),
2370
            $klarna->getVersion()
2371
        ];
2372
2373
        return implode(':', $versionInfo);
2374
    }
2375
2376
    /**
2377
     * Helper method to find out if the kpm plugin is active
2378
     */
2379
    public function isKpmActive()
2380
    {
2381
        /** @var Doctrine\DBAL\Query\QueryBuilder $queryBuilder */
2382
        $queryBuilder = Shopware()->Models()->getConnection()->createQueryBuilder();
2383
2384
        $result = $queryBuilder->select('plugin.id')
2385
            ->from('s_core_plugins', 'plugin')
2386
            ->where('plugin.name = :name')
2387
            ->andWhere('plugin.active = 1')
2388
            ->setParameter('name', 'SwagPaymentKlarnaKpm')
2389
            ->execute()
2390
            ->fetchColumn();
2391
2392
        return !empty($result);
2393
    }
2394
2395
    /**
2396
     * Helper method to find out if the kco paymentmean is active
2397
     */
2398
    public function isKcoPaymentActive()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
2399
    {
2400
        $sql = '
2401
                SELECT 1
2402
                FROM s_core_paymentmeans p
2403
2404
                LEFT JOIN s_core_paymentmeans_subshops ps
2405
                ON ps.subshopID = ?
2406
                AND ps.paymentID = p.id
2407
2408
                WHERE (ps.paymentID IS NOT NULL OR (
2409
                  SELECT paymentID FROM s_core_paymentmeans_subshops WHERE paymentID=p.id LIMIT 1
2410
                ) IS NULL)
2411
2412
                AND p.active=1
2413
2414
                AND id = ?
2415
            ';
2416
2417
        $contextService = $this->get('shopware_storefront.context_service');
2418
2419
        $active = Shopware()->Db()->fetchOne(
2420
            $sql,
2421
            [
2422
                $contextService->getShopContext()->getShop()->getId(),
2423
                $this->getPaymentIdKlarnaKCO()
2424
            ]
2425
        );
2426
        return $active;
2427
    }
2428
2429
    /**
2430
     * Fetches and returns KCO paymentID.
2431
     *
2432
     * @return \Shopware\Models\Payment\Payment
2433
     */
2434
    public function getPaymentIdKlarnaKCO()
2435
    {
2436
        $paymentKlarnaKCO = Shopware()->Models()->getRepository('Shopware\Models\Payment\Payment')->findOneBy(
2437
            ['name' => 'klarna_checkout']
2438
        );
2439
        return $paymentKlarnaKCO->getId();
2440
    }
2441
2442
    /**
2443
     * Helper method to find out if the klarna kco payment is active.
2444
     * Necessary to disable the checkout-button.
2445
     * @param array $user
2446
     * @return bool
2447
     */
2448
    public function isKlarnaKcoPaymentActive($user)
2449
    {
2450
        $payment = $this->getPayment();
2451
        if (!$payment) {
2452
            return false;
2453
        }
2454
        $data = $this->get('modules')->Admin()->sGetPaymentMeanById($payment->getId(), $user);
2455
        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...
2456
            return false;
2457
        }
2458
        return true;
2459
    }
2460
}
2461