Completed
Push — master ( eccdf7...a581ed )
by Mario
03:04
created

Bootstrap   D

Complexity

Total Complexity 246

Size/Duplication

Total Lines 2385
Duplicated Lines 4.03 %

Coupling/Cohesion

Components 3
Dependencies 5

Importance

Changes 0
Metric Value
dl 96
loc 2385
rs 4
c 0
b 0
f 0
wmc 246
lcom 3
cbo 5

75 Methods

Rating   Name   Duplication   Size   Complexity  
A install() 0 17 2
C update() 0 28 7
B uninstall() 0 29 2
A get() 0 9 3
A getPayment() 0 10 2
A getConnector() 0 4 1
A getService() 0 22 2
A enable() 0 13 2
A disable() 0 10 2
A getKLarnaService() 0 10 2
A getKlarnaAddr() 0 8 2
B createMyEvents() 0 87 1
B onBackendOrderSaveAfter() 0 34 6
A getOrderStatusById() 0 6 1
A onBackendOrderDeleteAfter() 0 15 3
A onBeforeUpdatePayment() 0 20 3
A onAfterGetCustomerListQueryBuilder() 0 9 1
A onGetStreetSplitService() 0 9 1
C klarnaLog() 25 26 7
B getKlarnaAddrByRawOrderData() 0 33 3
C fetchStreetAndHouseNumber() 0 42 8
A convertEncoding() 0 13 3
A createMyPayment() 0 23 1
B createMyForm() 0 381 1
C createMyTranslations() 0 54 11
B createMyAttributes() 0 97 4
A registerMyTemplateDir() 0 10 3
A isTemplateResponsive() 0 9 2
A onGetControllerPathFrontend() 0 6 1
A onGetControllerPathBackend() 0 9 1
D onPostDispatch() 0 78 21
A onPostDispatchFrontendRegister() 0 16 3
A savePayment() 0 7 1
A addJsFiles() 0 8 1
A onLoadOrderBackendModule() 16 16 2
A onLoadPaymentBackendModule() 16 16 2
B updateOrderVariables() 0 30 2
A getCountryByShop() 0 13 3
A getCountryIsoById() 0 7 1
B getLocale() 0 21 6
A getCheckoutOptions() 0 16 3
B getCheckoutCart() 0 36 6
B getCheckoutMerchant() 0 42 1
D getCheckoutAddress() 9 41 9
B getCheckoutCustomer() 0 15 5
A getLabel() 0 4 1
A getVersion() 0 10 2
A getInfo() 0 8 1
A onInitResourceKlarnaCheckoutConnector() 0 15 2
A onInitResourceKlarnaService() 0 8 1
A addLessFiles() 0 12 1
A assertMinimumVersion() 0 8 2
A onCheckoutExpress() 0 8 1
C getColorConfigOptions() 0 31 13
B getViewConfig() 0 33 1
A getShowLoginConfig() 0 4 2
A getKlarnaDisplayType() 0 7 2
A getOtherPayments() 0 12 3
A getShowCheckoutButton() 0 10 3
B getPositionOrder() 0 18 5
A buildCDNLink() 0 18 2
A getKlarnaCustomerData() 0 21 1
B getTranslationArray() 0 102 1
B updatePayment() 0 29 5
C checkValidKlarnaCountry() 0 24 7
C getExternalPaymentMethods() 0 52 10
A getFee() 0 16 3
A getRedirectUri() 0 7 1
D getImageForKlarna() 0 31 9
A filterPayments() 0 12 3
A isPaymentAllowed() 0 16 3
A buildKlarnaVersion() 0 12 1
A isKpmActive() 15 15 1
A isKcoPaymentActive() 15 15 1
A isKlarnaKcoPaymentActive() 0 12 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Bootstrap often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Bootstrap, and based on these observations, apply Extract Interface, too.

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
     * @param string $name
143
     * @return mixed
144
     */
145
    public function get($name)
146
    {
147
        if (version_compare(Shopware::VERSION, '4.2.0', '<') && Shopware::VERSION != '___VERSION___') {
148
            $name = ucfirst($name);
149
            return $this->Application()->Bootstrap()->getResource($name);
150
        }
151
152
        return parent::get($name);
153
    }
154
155
    /**
156
     * Fetches and returns klarna payment row instance.
157
     *
158
     * @return \Shopware\Models\Payment\Payment
159
     */
160
    public function getPayment()
161
    {
162
        if ($this->klarnaPayment === null) {
163
            $this->klarnaPayment = $this->Payments()->findOneBy(
164
                ['name' => 'klarna_checkout']
165
            );
166
        }
167
168
        return $this->klarnaPayment;
169
    }
170
171
    /**
172
     * @return \Klarna_Checkout_Connector
173
     */
174
    public function getConnector()
175
    {
176
        return $this->Application()->KlarnaCheckoutConnector();
177
    }
178
179
    /**
180
     * @return \Klarna
181
     */
182
    public function getService()
183
    {
184
        /** @var Klarna $service */
185
        $service = $this->Application()->KlarnaService();
186
        $service->setActivateInfo('flags', KlarnaFlags::RSRV_SEND_BY_EMAIL);
187
        $service->setVersion($this->buildKlarnaVersion($service));
188
        $service->config(
189
            $this->Config()->get('merchantId'),
190
            $this->Config()->get('sharedSecret'),
191
            KlarnaCountry::DE,
192
            KlarnaLanguage::DE,
193
            KlarnaCurrency::EUR,
194
            $this->Config()->get('testDrive') ? Klarna::BETA : Klarna::LIVE,
195
            'pdo',
196
            [
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...
197
                'table' => 's_klarna_pclasses',
198
                'pdo' => $this->Application()->Db()->getConnection()
199
            ]
200
        );
201
202
        return $service;
203
    }
204
205
    /**
206
     * Activate the plugin klarna plugin.
207
     * Sets the active flag in the payment row.
208
     *
209
     * @return array
210
     */
211
    public function enable()
212
    {
213
        $payment = $this->getPayment();
214
        if ($payment !== null) {
215
            $payment->setActive(true);
216
            $this->get('models')->flush($payment);
217
        }
218
219
        return [
220
            'success' => true,
221
            'invalidateCache' => ['backend', 'frontend']
222
        ];
223
    }
224
225
    /**
226
     * Disable plugin method and sets the active flag in the payment row
227
     *
228
     * @return bool
229
     */
230
    public function disable()
231
    {
232
        $payment = $this->getPayment();
233
        if ($payment !== null) {
234
            $payment->setActive(false);
235
            $this->get('models')->flush($payment);
236
        }
237
238
        return true;
239
    }
240
    
241
    /**
242
     * Returns an instance of klarna object
243
     *
244
     * @param void
245
     * @return \Klarna
246
     */
247
    public function getKLarnaService()
248
    {
249
        if ($this->klarnaService === null) {
250
            require_once __DIR__ . '/Components/Klarna/Klarna.php';
251
            require_once __DIR__ . '/Components/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
252
            $this->klarnaService = new Klarna();
253
        }
254
255
        return $this->klarnaService;
256
    }
257
    
258
    /**
259
     * Returns an instance of klarna address object
260
     *
261
     * @param void
262
     * @return object
263
     */
264
    public function getKlarnaAddr()
265
    {
266
        if ($this->klarnaAddr === null) {
267
            $this->klarnaAddr = new KlarnaAddr();
268
        }
269
        
270
        return $this->klarnaAddr;
271
    }
272
273
    /**
274
     * Creates and subscribe the events and hooks.
275
     */
276
    protected function createMyEvents()
277
    {
278
        // BACKEND
279
        $this->subscribeEvent(
280
            'Enlight_Controller_Action_PostDispatch_Backend_Order',
281
            'onLoadOrderBackendModule'
282
        );
283
        $this->subscribeEvent(
284
            'Enlight_Controller_Action_PostDispatch_Backend_Payment',
285
            'onLoadPaymentBackendModule'
286
        );
287
288
        $this->subscribeEvent(
289
            'Enlight_Controller_Dispatcher_ControllerPath_Backend_PaymentKlarna',
290
            'onGetControllerPathBackend'
291
        );
292
293
        // FRONTEND
294
        $this->subscribeEvent(
295
            'Enlight_Controller_Dispatcher_ControllerPath_Frontend_PaymentKlarna',
296
            'onGetControllerPathFrontend'
297
        );
298
        $this->subscribeEvent(
299
            'Enlight_Controller_Action_Frontend_Checkout_Express',
300
            'onCheckoutExpress'
301
        );
302
303
        $this->subscribeEvent(
304
            'Enlight_Controller_Action_PostDispatch',
305
            'onPostDispatch',
306
            110
307
        );
308
309
        // CONNECTOR
310
        $this->subscribeEvent(
311
            'Enlight_Bootstrap_InitResource_KlarnaCheckoutConnector',
312
            'onInitResourceKlarnaCheckoutConnector'
313
        );
314
315
        // SERVICES
316
        $this->subscribeEvent(
317
            'Enlight_Bootstrap_InitResource_KlarnaService',
318
            'onInitResourceKlarnaService'
319
        );
320
321
        $this->subscribeEvent(
322
            'Enlight_Bootstrap_InitResource_StreetSplitService',
323
            'onGetStreetSplitService'
324
        );
325
326
        $this->subscribeEvent(
327
            'Enlight_Controller_Action_PostDispatch_Frontend_Register',
328
            'onPostDispatchFrontendRegister'
329
        );
330
331
        $this->subscribeEvent(
332
            'Shopware\Models\Customer\Repository::getListQueryBuilder::after',
333
            'onAfterGetCustomerListQueryBuilder'
334
        );
335
336
        $this->subscribeEvent(
337
            'Theme_Compiler_Collect_Plugin_Javascript',
338
            'addJsFiles'
339
        );
340
341
        // Subscribe the needed event for less merge and compression
342
        $this->subscribeEvent(
343
            'Theme_Compiler_Collect_Plugin_Less',
344
            'addLessFiles'
345
        );
346
347
        // Hook event subscriptions below this line
348
349
        $this->subscribeEvent(
350
            'Shopware_Controllers_Backend_Payment::updatePaymentsAction::before',
351
            'onBeforeUpdatePayment'
352
        );
353
        
354
        $this->subscribeEvent(
355
            'Shopware_Controllers_Backend_Order::saveAction::after',
356
            'onBackendOrderSaveAfter'
357
        );
358
        $this->subscribeEvent(
359
            'Shopware_Controllers_Backend_Order::deleteAction::after',
360
            'onBackendOrderDeleteAfter'
361
        );
362
    }
363
364
    /**
365
     * Method will be triggered on clicking save on order details
366
     *
367
     * @param Enlight_Hook_HookArgs $args
368
     * @return void
369
     * @throws Exception
370
     */
371
    public function onBackendOrderSaveAfter(Enlight_Hook_HookArgs $args)
372
    {
373
        $orderDataRaw = $args->getSubject()->Request()->getPost();
374
        $orderId = $orderDataRaw['id'];
375
        $paymentName = $orderDataRaw['payment'][0]['name'];
376
377
        $orderStatus = $this->getOrderStatusById($orderId);
378
379
        $validUpdateDataToKlarna = (
380
            $orderStatus != 'activate' &&
381
            (
382
                $paymentName == 'klarna_checkout' ||
383
                $paymentName == 'klarna_account' ||
384
                $paymentName == 'klarna_invoice'
385
            )
386
        );
387
388
        if ($validUpdateDataToKlarna) {
389
            $klarnaService = $this->getService();
390
391
            $klarnaAddrBilling = $this->getKlarnaAddrByRawOrderData($orderDataRaw, 'billing');
392
            $klarnaAddrShipping = $this->getKlarnaAddrByRawOrderData($orderDataRaw, 'shipping');
393
394
            $transactionId = $orderDataRaw['transactionId'];
395
            
396
            $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 391 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...
397
            $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 392 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...
398
            try {
399
                $klarnaService->update($transactionId);
400
            } catch (Exception $e) {
401
                throw new Exception($e->getMessage());
402
            }
403
        }
404
    }
405
406
    /**
407
     * @param $orderId
408
     * @return string
409
     */
410
    protected function getOrderStatusById($orderId)
411
    {
412
        $klarnaOrderStatus = Shopware()->Db()->fetchOne('SELECT swag_klarna_status FROM s_order_attributes WHERE orderID = ?', [$orderId]);
413
414
        return $klarnaOrderStatus;
415
    }
416
417
    
418
    /**
419
     * Method will be triggered on clicking delete on order overview
420
     *
421
     * @param Enlight_Hook_HookArgs $args
422
     * @return void
423
     */
424
    public function onBackendOrderDeleteAfter(Enlight_Hook_HookArgs $args)
425
    {
426
        $orderDataRaw = $args->getSubject()->Request()->getPost();
427
        $paymentName = $orderDataRaw['payment'][0]['name'];
428
        
429
        if ($paymentName == 'klarna_checkout') {
430
            $klarnaService = $this->getService();
431
            $transactionId = $orderDataRaw['transactionId'];
432
            try {
433
                $klarnaService->cancelReservation($transactionId);
434
            } catch (Exception $e) {
435
                throw new Exception($e->getMessage());
436
            }
437
        }
438
    }
439
    
440
    
441
    /**
442
     * Hook to change the absolute media-path to a normalized virtual path.
443
     * @param Enlight_Hook_HookArgs $args
444
     */
445
    public function onBeforeUpdatePayment(Enlight_Hook_HookArgs $args)
446
    {
447
        if (!$this->assertMinimumVersion('5.1')) {
448
            return;
449
        }
450
451
        /** @var Zend_Controller_Request_Http $request */
452
        $request = $args->getSubject()->Request();
453
        $attributes = $request->getParam('attribute');
454
        $attribute = reset($attributes);
455
456
        if (empty($attribute['swagKlarnaKlarnaMedia'])) {
457
            return;
458
        }
459
460
        $mediaService = $this->get('shopware_media.media_service');
461
        $attribute['swagKlarnaKlarnaMedia'] = $mediaService->normalize($attribute['swagKlarnaKlarnaMedia']);
462
        $attributes[0] = $attribute;
463
        $request->setParam('attribute', $attributes);
464
    }
465
466
    /**
467
     * Needed to implement an additional "where"-condition to filter temporary klarna-customers, so they won't be shown
468
     * in the backend anymore.
469
     *
470
     * @param Enlight_Hook_HookArgs $args
471
     */
472
    public function onAfterGetCustomerListQueryBuilder(Enlight_Hook_HookArgs $args)
473
    {
474
        /** @var \Doctrine\DBAL\Query\QueryBuilder $builder */
475
        $builder = $args->getReturn();
476
477
        $builder->andWhere('billing.lastName != :lastName')->setParameter('lastName', 'Klarna Checkout');
478
479
        $args->setReturn($builder);
480
    }
481
482
    /**
483
     * @return StreetSplitService
484
     */
485
    public function onGetStreetSplitService()
486
    {
487
        $this->Application()->Loader()->registerNamespace(
488
            'Shopware\Components',
489
            __DIR__ . '/Components/'
490
        );
491
492
        return new StreetSplitService();
493
    }
494
    
495
    /**
496
     * Logs a message
497
     *
498
     * @param string $message
499
     * @param int $logLevelMessage
500
     * @param mixed $mPrintableElement
501
     * @return void
502
     */
503 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...
504
    {
505
        $configname = 'klarnaLogLevel';
506
        $elementId = Shopware()->Db()->fetchOne('SELECT id FROM s_core_config_elements WHERE name = ?', [$configname]);
507
        $logLevelConfigSetting = Shopware()->Db()->fetchOne('SELECT value FROM s_core_config_values WHERE element_id = ?', [$elementId]);
508
        $logLevelConfigSetting = unserialize($logLevelConfigSetting);
509
        $logLevelSetting = (is_numeric($logLevelConfigSetting) && $logLevelConfigSetting >=0 && $logLevelConfigSetting <=4) ? (int)$logLevelConfigSetting : 1;
510
        
511
        if ($logLevelMessage <= $logLevelSetting) {
512
            $prefix = "[".date('Y-m-d H:i:s')."] ";
513
            $debugBacktrace = '';
514
            if ($logLevelSetting >= 4) {
515
                $debugBacktrace = print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), true);
516
            }
517
            $sPrintableElementMessage = '';
518
            if ($mPrintableElement !== null) {
519
                $sPrintableElementMessage = print_r($mPrintableElement, true);
520
            }
521
            $fullMessage = $prefix.$message."\n".$sPrintableElementMessage.$debugBacktrace;
522
            $shopPath = Shopware()->DocPath();
523
            $logfilePath = $shopPath.'/var/log/klarnaTrace.log';
524
            $fileHandler = fopen($logfilePath, 'a');
525
            fwrite($fileHandler, $fullMessage);
526
            fclose($fileHandler);
527
        }
528
    }
529
530
    /**
531
     * Method returns matching address parts by address type
532
     *
533
     * @param array $orderDataRaw
534
     * @param string $type
535
     * @return bool|KlarnaAddr
536
     */
537
    protected function getKlarnaAddrByRawOrderData($orderDataRaw, $type)
538
    {
539
        $klarnaAddr = false;
540
        $baseData = (isset($orderDataRaw[$type][0])) ? $orderDataRaw[$type][0] : false;
541
        $baseData = $this->convertEncoding($baseData);
542
        
543
        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...
544
            $addressParts = $this->fetchStreetAndHouseNumber($baseData);
545
546
            $manager = $this->get('models');
547
            $repository = 'Shopware\Models\Country\Country';
548
            $repository = $manager->getRepository($repository);
549
            $country = $repository->findOneBy(['id' => $baseData['countryId']]);
550
            $countryiso = $country->getIso();
551
552
            $klarnaAddr =  new KlarnaAddr();
553
            $klarnaAddr->setEmail($orderDataRaw['customerEmail']);
554
            $klarnaAddr->setFirstName($baseData['firstName']);
555
            $klarnaAddr->setLastName($baseData['lastName']);
556
            $klarnaAddr->setTelno($baseData['phone']);
557
            $klarnaAddr->setStreet($addressParts['street']);
558
            $klarnaAddr->setHouseNumber($addressParts['streetnr']);
559
            $klarnaAddr->setHouseExt($addressParts['streetnr_extension']);
560
            $klarnaAddr->setCompanyName($baseData['company']);
561
            $klarnaAddr->setCareof($baseData['department']);
562
            $klarnaAddr->setZipCode($baseData['zipCode']);
563
            $klarnaAddr->setCity($baseData['city']);
564
            $klarnaAddr->setCountry($countryiso);
565
        }
566
567
        $this->klarnaLog('Update order address from backend with following address data:', 3, $klarnaAddr);
568
        return $klarnaAddr;
569
    }
570
571
572
    /**
573
     * Method splits street, streetnr and streetnr extension from basestring
574
     *
575
     * @param array $baseData
576
     * @return array
577
     */
578
    protected function fetchStreetAndHouseNumber($baseData)
579
    {
580
581
        $addressParts = explode(' ', $baseData['street']);
582
        $index = 0;
583
        $street = $streetnr = '';
584
        $houseNumberFound = false;
585
586
        foreach ($addressParts as $addressPart) {
587
            if (!$houseNumberFound) {
588
                // check if current addresspart is numeric
589
                $houseNumberFound = is_numeric($addressPart);
590
            }
591
592
            $index++;
593
            if ($index == count($addressParts) || $houseNumberFound) {
594
                // at least last element should be streetnr
595
                if (!empty($streetnr)) {
596
                    $streetnr .= ' ';
597
                }
598
                $streetnr .= (string) $addressPart;
599
            } else {
600
                $street .= (string)' '.$addressPart;
601
            }
602
        }
603
604
        $streetnr_extension = '';
605
        if (!empty($baseData['additionalAddressLine1'])) {
606
            $streetnr_extension .= $baseData['additionalAddressLine1'];
607
        }
608
        if (!empty($baseData['additionalAddressLine2'])) {
609
            $streetnr_extension .= "\n".$baseData['additionalAddressLine2'];
610
        }
611
612
        $return = [
613
            'street' => $street,
614
            'streetnr' => $streetnr,
615
            'streetnr_extension' => $streetnr_extension,
616
        ];
617
618
        return $return;
619
    }
620
    
621
622
    /**
623
     * Converts encoding in all string fields of an array
624
     *
625
     * @param array $data
626
     * @return array
627
     */
628
    protected function convertEncoding($data)
629
    {
630
        $out = [];
631
        foreach ($data as $key => $value) {
632
            if (is_string($value)) {
633
                $value = mb_convert_encoding($value, 'ISO-8859-1', 'UTF-8');
634
            }
635
            
636
            $out[$key] = $value;
637
        }
638
        
639
        return $out;
640
    }
641
642
    /**
643
     * Creates and save the payment row.
644
     */
645
    protected function createMyPayment()
646
    {
647
        /** @var \Shopware\Components\Model\ModelManager $manager */
648
        $manager = $this->get('models');
649
        $repository = 'Shopware\Models\Country\Country';
650
        $repository = $manager->getRepository($repository);
651
        $countries = [
652
            $repository->findOneBy(['iso' => 'SE']),
653
            $repository->findOneBy(['iso' => 'DE']),
654
            $repository->findOneBy(['iso' => 'NO']),
655
            $repository->findOneBy(['iso' => 'FI']),
656
            $repository->findOneBy(['iso' => 'AT'])
657
        ];
658
        $this->createPayment(
659
            [
660
                'name' => 'klarna_checkout',
661
                'description' => $this->getLabel(),
662
                'action' => 'payment_klarna',
663
                'additionalDescription' => '',
664
                'countries' => $countries
665
            ]
666
        );
667
    }
668
669
    /**
670
     * Creates and stores the payment config form.
671
     */
672
    protected function createMyForm()
673
    {
674
        $form = $this->Form();
675
676
        // API settings
677
        $form->setElement(
678
            'boolean',
679
            'testDrive',
680
            [
681
                'label' => 'Testmodus aktvieren',
682
                'value' => false,
683
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
684
                'position' => 0
685
            ]
686
        );
687
688
        $form->setElement(
689
            'text',
690
            'merchantId',
691
            [
692
                'label' => 'API-HändlerID (EID)',
693
                'required' => true,
694
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
695
                'position' => 1
696
            ]
697
        );
698
699
        $form->setElement(
700
            'text',
701
            'sharedSecret',
702
            [
703
                'label' => 'API-Secret (sharedsecret)',
704
                'required' => true,
705
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
706
                'position' => 2
707
            ]
708
        );
709
710
        $form->setElement(
711
            'number',
712
            'termSiteId',
713
            [
714
                'label' => 'Shopseite mit den Geschäftsbedingungen',
715
                'value' => 4,
716
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
717
                'position' => 3
718
            ]
719
        );
720
721
        $form->setElement(
722
            'boolean',
723
            'allowSeparateShippingAddress',
724
            [
725
                'label' => 'Abweichende Lieferadresse erlauben',
726
                'value' => true,
727
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
728
                'position' => 4
729
            ]
730
        );
731
732
        $form->setElement(
733
            'boolean',
734
            'supportPackstation',
735
            [
736
                'label' => 'DHL Packstation unterstützen',
737
                'value' => false,
738
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
739
                'position' => 5,
740
                'helpText' => 'Die abweichende Lieferadresse muss erlaubt sein'
741
            ]
742
        );
743
744
        $form->setElement(
745
            'text',
746
            'postnumberField',
747
            [
748
                'label' => 'Alternatives Feld für die DHL-Postnummer',
749
                'value' => 'attribute1',
750
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
751
                'position' => 6
752
            ]
753
        );
754
755
        $form->setElement(
756
            'boolean',
757
            'mandatoryPhone',
758
            [
759
                'label' => 'Telefonummer als Pflichtfeld',
760
                'value' => false,
761
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
762
                'position' => 7
763
            ]
764
        );
765
766
        $form->setElement(
767
            'boolean',
768
            'mandatoryBirthday',
769
            [
770
                'label' => 'Geburtsdatum als Pflichtfeld',
771
                'value' => false,
772
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
773
                'position' => 8
774
            ]
775
        );
776
777
        $form->setElement(
778
            'boolean',
779
            'disableAutofocus',
780
            [
781
                'label' => 'Autofokus deaktivieren',
782
                'value' => false,
783
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
784
                'position' => 9
785
            ]
786
        );
787
788
        $form->setElement(
789
            'boolean',
790
            'showKlarnaButton',
791
            [
792
                'label' => 'Klarna Checkout-Button anzeigen',
793
                'value' => true,
794
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
795
                'position' => 10
796
            ]
797
        );
798
799
        $form->setElement(
800
            'boolean',
801
            'preFillCheckout',
802
            [
803
                'label' => 'Klarna Checkout für registrierte Kunden vorausfüllen',
804
                'value' => true,
805
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
806
                'position' => 11
807
            ]
808
        );
809
810
        $form->setElement(
811
            'color',
812
            'checkoutButtonColor',
813
            [
814
                'label' => 'Checkout Button Farbe',
815
                'value' => null,
816
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
817
                'position' => 12
818
            ]
819
        );
820
821
        $form->setElement(
822
            'color',
823
            'checkoutButtonTextColor',
824
            [
825
                'label' => 'Checkout Buttontext Farbe',
826
                'value' => null,
827
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
828
                'position' => 13
829
            ]
830
        );
831
832
        $form->setElement(
833
            'color',
834
            'checkoutCheckboxColor',
835
            [
836
                'label' => 'Checkout Checkbox Farbe',
837
                'value' => null,
838
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
839
                'position' => 14
840
            ]
841
        );
842
843
        $form->setElement(
844
            'color',
845
            'checkoutCheckboxCheckmarkColor',
846
            [
847
                'label' => 'Checkout Checkbox Häckchen Farbe',
848
                'value' => null,
849
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
850
                'position' => 15
851
            ]
852
        );
853
854
        $form->setElement(
855
            'color',
856
            'checkoutHeaderColor',
857
            [
858
                'label' => 'Checkout Header Farbe',
859
                'value' => null,
860
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
861
                'position' => 16
862
            ]
863
        );
864
865
        $form->setElement(
866
            'color',
867
            'checkoutLinkColor',
868
            [
869
                'label' => 'Checkout Link Farbe',
870
                'value' => null,
871
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
872
                'position' => 17
873
            ]
874
        );
875
876
        $form->setElement(
877
            'boolean',
878
            'KlarnaExternalPayments',
879
            [
880
                'label' => 'Externe Zahlungsarten im Klarna Checkout darstellen',
881
                'value' => null,
882
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
883
                'helpText' => 'Ihr Klarna-Konto muss für diese Funktion freigeschaltet werden',
884
                'position' => 18
885
            ]
886
        );
887
888
        $form->setElement(
889
            'select',
890
            'displayType',
891
            [
892
                'label' => 'Klarna Checkout Darstellungs-Art',
893
                'value' => 1,
894
                'store' => [
895
                    [1, 'Tab-Darstellung'],
896
                    [2, 'Nur Klarna Checkout-Darstellung'],
897
                    [3, 'Einseiten-Darstellung']
898
                ],
899
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
900
                'position' => 19
901
            ]
902
        );
903
904
        $form->setElement(
905
            'boolean',
906
            'showB2bSelect',
907
            [
908
                'label' => 'B2B-Auswahl anzeigen',
909
                'value' => true,
910
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
911
                'helpText' => 'In dem Klarna Checkout wird eine Auswahl "Privatkunde / Firma" angezeigt',
912
                'position' => 20
913
            ]
914
        );
915
916
        $form->setElement(
917
            'boolean',
918
            'showLoginPanel',
919
            [
920
                'label' => 'Login-Formular anzeigen',
921
                'value' => true,
922
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
923
                'helpText' => 'In dem Klarna Checkout wird ein Login-Formular angezeigt',
924
                'position' => 21
925
            ]
926
        );
927
928
        $form->setElement(
929
            'boolean',
930
            'showMiniBasket',
931
            [
932
                'label' => 'Warenkorb anzeigen',
933
                'value' => true,
934
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
935
                'helpText' => 'In dem Klarna Checkout wird eine kleine Übersicht des Warenkorbs angezeigt',
936
                'position' => 22
937
            ]
938
        );
939
940
        $form->setElement(
941
            'boolean',
942
            'showDispatch',
943
            [
944
                'label' => 'Lieferland & Versandarten anzeigen',
945
                'value' => true,
946
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
947
                'helpText' => 'In dem Klarna Checkout wird eine Lieferland- sowie Versandarten-Auswahl angezeigt',
948
                'position' => 23
949
            ]
950
        );
951
952
        $form->setElement(
953
            'select',
954
            'positionOrder',
955
            [
956
                'label' => 'Reihenfolge der Elemente',
957
                'value' => 1,
958
                'store' => [
959
                    [1, 'Login-Formular, Mini-Warenkorb, Versandauswahl, Zahlungsauswahl'],
960
                    [2, 'Login-Formular, Mini-Warenkorb, Zahlungsauswahl, Versandauswahl'],
961
                    [3, 'Versandauswahl, Zahlungsauswahl, Login-Formular, Mini-Warenkorb'],
962
                    [4, 'Zahlungsauswahl, Versandauswahl, Login-Formular, Mini-Warenkorb']
963
                ],
964
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
965
                'helpText' => 'Die \'Zahlungsauswahl\' wird nur in der \'Einseitig\'-Darstellung angezeigt.',
966
                'position' => 24
967
            ]
968
        );
969
970
        $form->setElement(
971
            'boolean',
972
            'partPaymentWidget',
973
            [
974
                'label' => 'Teilzahlungs-Widget auf der Detailseite anzeigen',
975
                'value' => true,
976
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
977
                'position' => 25
978
            ]
979
        );
980
981
        $form->setElement(
982
            'boolean',
983
            'convertShippingFee',
984
            [
985
                'label' => 'Versandkosten in eine Bestellposition umwandeln',
986
                'value' => true,
987
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
988
                'position' => 26
989
            ]
990
        );
991
992
        $form->setElement(
993
            'select',
994
            'statusId',
995
            [
996
                'label' => 'Zahlstatus nach der Bestellung',
997
                'value' => 18,
998
                'store' => 'base.PaymentStatus',
999
                'displayField' => 'description',
1000
                'valueField' => 'id',
1001
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1002
                'position' => 27
1003
            ]
1004
        );
1005
1006
        $form->setElement(
1007
            'select',
1008
            'activateStatusId',
1009
            [
1010
                'label' => 'Zahlungsstatus nach der Aktivierung',
1011
                'value' => 12,
1012
                'store' => 'base.PaymentStatus',
1013
                'displayField' => 'description',
1014
                'valueField' => 'id',
1015
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1016
                'position' => 28
1017
            ]
1018
        );
1019
1020
        $form->setElement(
1021
            'select',
1022
            'cancelStatusId',
1023
            [
1024
                'label' => 'Zahlungsstatus nach der Stornierung',
1025
                'value' => 17,
1026
                'store' => 'base.PaymentStatus',
1027
                'displayField' => 'description',
1028
                'valueField' => 'id',
1029
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1030
                'position' => 29
1031
            ]
1032
        );
1033
        
1034
        $form->setElement(
1035
            'select',
1036
            'klarnaLogLevel',
1037
            [
1038
                'label' => 'Detaillevel der Logeinträge zur Fehlerverfolgung',
1039
                'value' => 0,
1040
                'store' => [
1041
                    [0, 'Nichts protokollieren'],
1042
                    [1, 'Nur Fehler protokollieren'],
1043
                    [2, 'Fehler und Warnungen protokollieren'],
1044
                    [3, 'Alle Meldungen protokollieren'],
1045
                    [4, 'Alle Meldungen und zusätzlich Entwicklerinformationen protokollieren (Große Logdateien!)'],
1046
                ],
1047
                'scope' => \Shopware\Models\Config\Element::SCOPE_SHOP,
1048
                '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.',
1049
                'position' => 30
1050
            ]
1051
        );
1052
    }
1053
1054
    /**
1055
     *
1056
     */
1057
    public function createMyTranslations()
1058
    {
1059
        $form = $this->Form();
1060
        $translations = $this->getTranslationArray();
1061
1062
        // In 4.2.2 we introduced a helper function for this, so we can skip the custom logic
1063
        if ($this->assertMinimumVersion('4.2.2')) {
1064
            $this->addFormTranslations($translations);
1065
            return true;
1066
        }
1067
1068
        $shopRepository = Shopware()->Models()->getRepository('\Shopware\Models\Shop\Locale');
1069
        foreach ($translations as $locale => $snippets) {
1070
            /** @var \Shopware\Models\Shop\Locale|null $localeModel */
1071
            $localeModel = $shopRepository->findOneBy(['locale' => $locale]);
1072
            if ($localeModel === null) {
1073
                continue;
1074
            }
1075
            foreach ($snippets as $element => $snippet) {
1076
                $translationModel = null;
1077
                //get the form element by name
1078
                $elementModel = $form->getElement($element);
1079
1080
                //not found? continue with next snippet
1081
                if ($elementModel === null) {
1082
                    continue;
1083
                }
1084
1085
                // Try to load existing translation
1086
                foreach ($elementModel->getTranslations() as $translation) {
1087
                    if ($translation->getLocale()->getLocale() == $locale) {
1088
                        $translationModel = $translation;
1089
                        break;
1090
                    }
1091
                }
1092
1093
                // If none found create a new one
1094
                if (!$translationModel) {
1095
                    $translationModel = new \Shopware\Models\Config\ElementTranslation();
1096
                    $translationModel->setLocale($localeModel);
1097
                    //add the translation to the form element
1098
                    $elementModel->addTranslation($translationModel);
1099
                }
1100
1101
                if ($snippet['label']) {
1102
                    $translationModel->setLabel($snippet['label']);
1103
                }
1104
1105
                if ($snippet['description']) {
1106
                    $translationModel->setDescription($snippet['description']);
1107
                }
1108
            }
1109
        }
1110
    }
1111
1112
    /**
1113
     *
1114
     */
1115
    public function createMyAttributes()
1116
    {
1117
        try {
1118
            $this->get('models')->addAttribute(
1119
                's_order_details_attributes',
1120
                'swag_klarna',
1121
                'invoice_number',
1122
                'VARCHAR(255)'
1123
            );
1124
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1125
        }
1126
1127
        $this->get('models')->generateAttributeModels(
1128
            [
1129
                's_order_details_attributes'
1130
            ]
1131
        );
1132
1133
        try {
1134
            $this->get('models')->addAttribute(
1135
                's_order_attributes',
1136
                'swag_klarna',
1137
                'status',
1138
                'VARCHAR(255)'
1139
            );
1140
            $this->get('models')->addAttribute(
1141
                's_order_attributes',
1142
                'swag_klarna',
1143
                'invoice_number',
1144
                'VARCHAR(255)'
1145
            );
1146
1147
            $this->get('models')->addAttribute(
1148
                's_core_paymentmeans_attributes',
1149
                'swag_klarna',
1150
                'show_in_klarna_iframe',
1151
                'int(11)'
1152
            );
1153
            $this->get('models')->addAttribute(
1154
                's_core_paymentmeans_attributes',
1155
                'swag_klarna',
1156
                'allow_in_payment_container',
1157
                'int(11)'
1158
            );
1159
            $this->get('models')->addAttribute(
1160
                's_core_paymentmeans_attributes',
1161
                'swag_klarna',
1162
                'klarna_media',
1163
                'VARCHAR(255)'
1164
            );
1165
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1166
        }
1167
1168
        $this->get('models')->generateAttributeModels(
1169
            [
1170
                's_order_attributes',
1171
                's_core_paymentmeans_attributes'
1172
            ]
1173
        );
1174
        
1175
        if ($this->assertMinimumVersion('5.2')) {
1176
            $this->get('shopware_attribute.crud_service')->update(
1177
                's_core_paymentmeans_attributes',
1178
                'swag_klarna_show_in_klarna_iframe',
1179
                'boolean',
1180
                [
1181
                    'label' => 'In Klarna Checkout einbinden',
1182
                    'helpText' => 'Bindet die Zahlungsart direkt in das Klarna iFrame ein',
1183
                    'displayInBackend' => true,
1184
                    'pluginId' => $this->getId()
1185
                ]
1186
            );
1187
            $this->get('shopware_attribute.crud_service')->update(
1188
                's_core_paymentmeans_attributes',
1189
                'swag_klarna_allow_in_payment_container',
1190
                'boolean',
1191
                [
1192
                    'label' => 'Nicht neben dem Klarna Checkout anzeigen',
1193
                    'helpText' => 'Versteckt die Zahlungsart in dem "Andere Zahlungsarten-Container" im Klarna Checkout',
1194
                    'displayInBackend' => true,
1195
                    'pluginId' => $this->getId()
1196
                ]
1197
            );
1198
            $this->get('shopware_attribute.crud_service')->update(
1199
                's_core_paymentmeans_attributes',
1200
                'swag_klarna_klarna_media',
1201
                'string',
1202
                [
1203
                    'label' => 'Bild Name für Klarna Checkout',
1204
                    'helpText' => 'Zeigt die Zahlungsart zusätzlich mit einem Bild im iFrame an. Funktioniert nur, wenn SSL konfiguriert ist. Optimale Größe: 276x48px.'
1205
                    . 'Das Bild muss im Order /media/image gespeichert werden',
1206
                    'displayInBackend' => true,
1207
                    'pluginId' => $this->getId()
1208
                ]
1209
            );
1210
        }
1211
    }
1212
1213
    public function registerMyTemplateDir($isBackend = false)
1214
    {
1215
        if ($isBackend) {
1216
            $this->get('template')->addTemplateDir(__DIR__ . '/Views/', 'klarna');
1217
        } elseif ($this->isTemplateResponsive()) {
1218
            $this->get('template')->addTemplateDir(__DIR__ . '/Views/responsive', 'klarna');
1219
        } else {
1220
            $this->get('template')->addTemplateDir(__DIR__ . '/Views/_emotion', 'klarna');
1221
        }
1222
    }
1223
1224
    /**
1225
     * Checks if the the current Template is responsive
1226
     *
1227
     * @return bool
1228
     */
1229
    public function isTemplateResponsive()
1230
    {
1231
        $template = $this->Application()->Shop()->getTemplate()->getVersion();
1232
        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...
1233
            return false;
1234
        }
1235
1236
        return true;
1237
    }
1238
1239
    /**
1240
     * Returns the path to a frontend controller for an event.
1241
     *
1242
     * @return string
1243
     */
1244
    public function onGetControllerPathFrontend()
1245
    {
1246
        $this->registerMyTemplateDir();
1247
1248
        return __DIR__ . '/Controllers/Frontend/PaymentKlarna.php';
1249
    }
1250
1251
    /**
1252
     * Returns the path to a backend controller for an event.
1253
     *
1254
     * @return string
1255
     */
1256
    public function onGetControllerPathBackend()
1257
    {
1258
        $this->registerMyTemplateDir(true);
1259
        $this->Application()->Snippets()->addConfigDir(
1260
            __DIR__ . '/Snippets/'
1261
        );
1262
1263
        return __DIR__ . '/Controllers/Backend/PaymentKlarna.php';
1264
    }
1265
1266
    /**
1267
     * @param Enlight_Event_EventArgs $args
1268
     */
1269
    public function onPostDispatch(Enlight_Event_EventArgs $args)
1270
    {
1271
        /** @var $action Enlight_Controller_Action */
1272
        $action = $args->getSubject();
1273
        $request = $action->Request();
1274
        $response = $action->Response();
1275
        $view = $action->View();
1276
1277
        if (!$request->isDispatched()
1278
            || $response->isException()
1279
            || $request->getModuleName() != 'frontend'
1280
            || !$view->hasTemplate()
1281
        ) {
1282
            return;
1283
        }
1284
1285
        // just return in case kco payment is deactivated in backend
1286
1287
        if (!$this->isKcoPaymentActive()){
1288
            return;
1289
        }
1290
        $user = $view->getAssign('sUserData');
1291
        $config = $this->Config();
1292
1293
        // this is used for showing klarna buttons in basket
1294
        if ($request->getControllerName() == 'checkout'
1295
            && ($request->getActionName() == 'cart' || $request->getActionName() == 'ajaxCart')
1296
        ) {
1297
            $this->registerMyTemplateDir();
1298
            $view->assign('KlarnaEnableButton', (bool)$config->get('showKlarnaButton'));
1299
            $view->assign('KlarnaShowCheckoutButton', $this->getShowCheckoutButton($user));
1300
            $view->assign('klarnaKcoPaymentActive', $this->isKlarnaKcoPaymentActive($user));
1301
            $view->assign('KlarnaPaymentDescription', $this->getPayment()->getDescription());
1302
            if (!$this->isTemplateResponsive()) {
1303
                $view->extendsTemplate('frontend/payment_klarna_checkout/cart.tpl');
1304
            }
1305
        }
1306
1307
        // show klarna invoice information on article detail pages
1308
        if (!empty($config->partPaymentWidget)
1309
            && $request->getControllerName() == 'detail' && $request->getActionName() == 'index'
1310
        ) {
1311
            $this->registerMyTemplateDir();
1312
            //Do not shot the logo on the detail page if the kpm-plugin is active
1313
            $view->KlarnaShowLogo = !$this->isKpmActive();
1314
            $view->KlarnaLocale = $this->getLocale();
1315
            $view->KlarnaMerchantId = $config->get('merchantId');
1316
            if (!$this->isTemplateResponsive()) {
1317
                $view->extendsTemplate('frontend/payment_klarna_part/detail.tpl');
1318
            }
1319
        }
1320
1321
        if ($request->getControllerName() == 'register' && $request->getActionName() == 'index') {
1322
            $this->registerMyTemplateDir();
1323
            $view->assign('KlarnaLocale', $this->getLocale());
1324
            $view->assign('KlarnaMerchantId', $config->get('merchantId'));
1325
            $view->assign('KlarnaHideCheckoutSteps', true);
1326
            
1327
            if (version_compare(Shopware::VERSION, '5.2.0', '<')){
1328
                $view->assign('KlarnaSkipLoginFix', true);
1329
            }
1330
            if (!$this->isTemplateResponsive()) {
1331
                $view->extendsTemplate('frontend/payment_klarna_checkout/register.tpl');
1332
            }
1333
            
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
1334
        }
1335
1336
        if ($request->getControllerName() == 'account' && $request->getActionName() == 'ajax_login') {
1337
            $this->registerMyTemplateDir();
1338
            $view->assign('KlarnaLocale', $this->getLocale());
1339
            $view->assign('KlarnaMerchantId', $config->get('merchantId'));
1340
            
1341
            if (!$this->isTemplateResponsive()) {
1342
                $view->extendsTemplate('frontend/payment_klarna_checkout/ajax_login.tpl');
1343
            }
1344
        }
1345
1346
    }
1347
1348
    /**
1349
     * Populate register form with saved data on changing klarna and register tabs
1350
     *
1351
     * @param Enlight_Event_EventArgs $args
1352
     */
1353
    public function onPostDispatchFrontendRegister($args)
1354
    {
1355
        /** @var $action Enlight_Controller_Action */
1356
        $action = $args->getSubject();
1357
        $view = $action->View();
1358
        $request = $action->Request();
1359
        /** @var Enlight_Components_Session_Namespace $session */
1360
        $session = $this->Application()->Session();
1361
1362
         // Switch User to external PaymentId after registration
1363
         if (isset($session['KlarnaExternalPaymentId'])) {
1364
                $this->savePayment($session['KlarnaExternalPaymentId']);
1365
        }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 9 spaces, found 8
Loading history...
1366
1367
       $view->assign('klarnaRedirect', $request->has('klarnaRedirect') && $request->getParam('klarnaRedirect') == 1);
1368
    }
1369
    
1370
1371
    /**
1372
     * Helper method to set the selected payment-method into the session to change it in the customer-account after logging in
1373
     *
1374
     * @param $paymentId
1375
     * @throws Enlight_Exception
1376
     */
1377
    public function savePayment($paymentId)
1378
    {
1379
        $admin = Shopware()->Modules()->Admin();
1380
        $admin->sSYSTEM->_POST['sPayment'] = $paymentId;
1381
        $admin->sUpdatePayment($paymentId);
1382
1383
    }
1384
1385
    public function addJsFiles()
1386
    {
1387
        $jsPath = [
1388
            __DIR__ . '/Views/responsive/frontend/_public/src/js/jquery.klarna_checkout.js'
1389
        ];
1390
1391
        return new Doctrine\Common\Collections\ArrayCollection($jsPath);
1392
    }
1393
1394
    /**
1395
     * @param Enlight_Event_EventArgs $args
1396
     */
1397 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...
1398
    {
1399
        /** @var $subject Enlight_Controller_Action */
1400
        $subject = $args->getSubject();
1401
        $request = $subject->Request();
1402
        $view = $subject->View();
1403
1404
        switch ($request->getActionName()) {
1405
            case 'load':
1406
                $this->registerMyTemplateDir(true);
1407
                $view->extendsTemplate('backend/order/payment_klarna.js');
1408
                break;
1409
            default:
1410
                break;
1411
        }
1412
    }
1413
1414
    /**
1415
     * @param Enlight_Event_EventArgs $args
1416
     */
1417 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...
1418
    {
1419
        /** @var $subject Enlight_Controller_Action */
1420
        $subject = $args->getSubject();
1421
        $request = $subject->Request();
1422
        $view = $subject->View();
1423
1424
        switch ($request->getActionName()) {
1425
            case 'load':
1426
                $this->registerMyTemplateDir(true);
1427
                $view->extendsTemplate('backend/payment/payment_klarna.js');
1428
                break;
1429
            default:
1430
                break;
1431
        }
1432
    }
1433
1434
    public function updateOrderVariables()
1435
    {
1436
        $session = Shopware()->Session();
1437
        $admin = Shopware()->Modules()->Admin();
1438
        /** @var ArrayObject $orderVariables */
1439
        $orderVariables = $session['sOrderVariables'];
1440
        $userData = $admin->sGetUserData();
1441
        $userData['payment'] = $orderVariables['sUserData']['payment'];
1442
        $userData['additional'] = array_merge(
1443
            $orderVariables['sUserData']['additional'],
1444
            $userData['additional']
1445
        );
1446
        
1447
        if (isset($session['sChangedCountry'])){
1448
            
1449
            /** @var \Shopware\Components\Model\ModelManager $em */
1450
            $em = $this->get('models');
1451
1452
            /** @var \Shopware\Models\Customer\Customer $customer */
1453
            $country = $em->getRepository('Shopware\Models\Country\Country')->findOneBy(['id' => $session['sChangedCountry']]);
1454
            $userData['shippingaddress']['country'] =$country;     
1455
            $userData['billingaddress']['country'] =$country;   
1456
            $userData['shippingaddress']['countryID'] = $session['sChangedCountry'];
1457
            $userData['billingaddress']['countryID'] = $session['sChangedCountry'];
1458
         }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 8 spaces, found 9
Loading history...
1459
        
1460
        $orderVariables['sUserData'] = $userData;
1461
        $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...
1462
1463
    }
1464
1465
    /**
1466
     * @param $shop Shopware\Models\Shop\Shop
1467
     * @return int|null
1468
     */
1469
    public function getCountryByShop($shop)
1470
    {
1471
        $locale = $shop->getLocale()->getLocale();
1472
        $this->klarnaLog("Entering Bootstrap::getCountryByShop", 3);
1473
        $locale = explode('_', $locale);
1474
        $locale = isset($locale[1]) ? $locale[1] : $locale[0];
1475
        $this->klarnaLog("Bootstrap::getCountryByShop locale to request for:".$locale,3);
1476
        $sql = 'SELECT id FROM s_core_countries WHERE countryiso=?';
1477
        $countryId = Shopware()->Db()->fetchOne($sql, [$locale]);
1478
        $countryId = ($countryId) ? (int)$countryId : null;
1479
                
1480
        return $countryId;
1481
    }
1482
1483
    /**
1484
     * Get user country by country id
1485
     *
1486
     * @param $id
1487
     * @return string
1488
     */
1489
    public function getCountryIsoById($id)
1490
    {
1491
        $sql = 'SELECT countryiso FROM s_core_countries WHERE id = ?';
1492
        $countryIso = Shopware()->Db()->fetchOne($sql, [$id]);
1493
1494
        return $countryIso;
1495
    }
1496
1497
    public function getLocale($underscore = false, $countryIso = null)
1498
    {
1499
        /** @var \Shopware\Models\Shop\Shop $shop */
1500
        $shop = $this->Application()->Shop();
1501
        $locale = $shop->getLocale()->getLocale();
1502
        $locale = strtolower($locale);
1503
        if (!$underscore) {
1504
            $locale = str_replace('_', '-', $locale);
1505
        }
1506
        $locale = $locale == 'nn-no' ? 'nb-no' : $locale;
1507
1508
        if ($locale == 'de-de') {
1509
            if($countryIso == 'CH') {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
1510
                $locale = 'de-ch';
1511
            } elseif ($countryIso == 'AT') {
1512
                $locale = 'de-at';
1513
            }
1514
        }
1515
1516
        return $locale;
1517
    }
1518
1519
    public function getCheckoutOptions($allowPackstation = true, $dispatch = [])
1520
    {
1521
        $config = $this->Config();
1522
        $options = $this->getColorConfigOptions($config);
1523
1524
        $options['allow_separate_shipping_address'] = (bool)$config->get('allowSeparateShippingAddress');
1525
        $options['packstation_enabled'] = (bool)$config->get('supportPackstation') && $allowPackstation;
1526
        $options['phone_mandatory'] = (bool)$config->get('mandatoryPhone');
1527
        $options['date_of_birth_mandatory'] = (bool)$config->get('mandatoryBirthday');
1528
1529
        if (!empty($dispatch)) {
1530
            $options['shipping_details'] = $dispatch['description'];
1531
        }
1532
1533
        return $options;
1534
    }
1535
1536
    public function getCheckoutCart($basket)
1537
    {
1538
        $cart = [];
1539
        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...
1540
            // compatibility to shopware plugin custom products
1541
            if (isset($basketItem['custom_product_prices'])) {
1542
                $basketItemPrice = (double)$basketItem['custom_product_prices']['total'];
1543
            }
1544
            else {
1545
                $basketItemPrice = (double)str_replace(',', '.', $basketItem['price']);
1546
            }
1547
            $unitPrice = round($basketItemPrice * 100);
1548
            $cart[] = [
1549
                'type' => $unitPrice >= 0 ? 'physical' : 'discount',
1550
                'reference' => $basketItem['ordernumber'],
1551
                'name' => $basketItem['articlename'],
1552
                'quantity' => (int)$basketItem['quantity'],
1553
                'unit_price' => (int)$unitPrice,
1554
                'tax_rate' => (int)round($basketItem['tax_rate'] * 100)
1555
            ];
1556
        }
1557
        if (!empty($basket['sShippingcosts'])) {
1558
            $shippingCostsWithTax = $basket['sShippingcostsWithTax'];
1559
            $shippingAmount = !empty($shippingCostsWithTax) ? $shippingCostsWithTax : $basket['sShippingcosts'];
1560
            $cart[] = [
1561
                'type' => 'shipping_fee',
1562
                'reference' => 'SHIPPING',
1563
                'name' => 'Shipping Fee',
1564
                'quantity' => 1,
1565
                'unit_price' => (int)round($shippingAmount * 100),
1566
                'tax_rate' => (int)round($basket['sShippingcostsTax'] * 100),
1567
            ];
1568
        }
1569
1570
        return $cart;
1571
    }
1572
1573
    public function getCheckoutMerchant()
1574
    {
1575
        /** @var \Shopware\Components\Routing\RouterInterface $router */
1576
        $router = $this->Application()->Front()->Router();
1577
        $merchant = [];
1578
        $merchant['id'] = $this->Config()->get('merchantId');
1579
        $merchant['terms_uri'] = $router->assemble(
1580
            [
1581
                'controller' => 'custom',
1582
                'sCustom' => $this->Config()->get('termSiteId', 4),
1583
                'forceSecure' => true
1584
            ]
1585
        );
1586
        $merchant['checkout_uri'] = $router->assemble(
1587
            [
1588
                'action' => 'confirm'
1589
            ]
1590
        );
1591
        $merchant['confirmation_uri'] = $router->assemble(
1592
            [
1593
                'controller' => 'payment_klarna',
1594
                'action' => 'return',
1595
                'forceSecure' => true
1596
            ]
1597
        ) . "?transactionId={checkout.order.uri}";
1598
        $merchant['push_uri'] = $router->assemble(
1599
            [
1600
                'controller' => 'payment_klarna',
1601
                'action' => 'push',
1602
                'forceSecure' => true,
1603
                'appendSession' => true
1604
            ]
1605
        ) . "&transactionId={checkout.order.uri}";
1606
        $merchant['back_to_store_uri'] = $router->assemble(
1607
            [
1608
                'controller' => 'index',
1609
                'action' => 'index'
1610
            ]
1611
        );
1612
1613
        return $merchant;
1614
    }
1615
1616
    public function getCheckoutAddress($user, $type = 'billing')
1617
    {
1618
        if (empty($user[$type . 'address']['zipcode']) || $user[$type . 'address']['zipcode'] == '00000') {
1619
            return [];
1620
        }
1621
1622
        $address = [
1623
            'given_name' => $user[$type . 'address']['firstname'],
1624
            'family_name' => $user[$type . 'address']['lastname'],
1625
            'postal_code' => $user[$type . 'address']['zipcode'],
1626
            'city' => $user[$type . 'address']['city'],
1627
            'country' => $user['additional'][$type == 'billing' ? 'country' : 'countryShipping']['countryiso'],
1628
            'email' => $user['additional']['user']['email'],
1629
            'phone' => $user['billingaddress']['phone'],
1630
        ];
1631
        $address['country'] = strtolower($address['country']);
1632
        if ($address['country'] == 'de' || $address['country'] == 'nl') {
1633
            $address['title'] = $user[$type . 'address']['salutation'] == 'ms' ? 'Frau' : 'Herr';
1634
            if ($this->assertMinimumVersion('5.0.0')) {
1635
                /** @var StreetSplitService $streetSplitService */
1636
                $streetSplitService = Shopware()->StreetSplitService();
1637
                $streetAndNumber = $streetSplitService->split($user[$type . 'address']['street']);
1638
1639
                $address['street_name'] = $streetAndNumber['streetName'];
1640
                $address['street_number'] = $streetAndNumber['streetNumber'];
1641 View Code Duplication
            } else {
1642
                $address['street_name'] = $user[$type . 'address']['street'];
1643
                $address['street_number'] = $user[$type . 'address']['streetnumber'];
1644
            }
1645 View Code Duplication
        } else {
1646
            $address['street_address'] = trim(
1647
                $user[$type . 'address']['street'] . ' ' . $user[$type . 'address']['streetnumber']
1648
            );
1649
        }
1650
1651
        // Make sure phone number is unset if empty
1652
        if ($address['phone'] === null){
1653
            unset($address['phone']);
1654
        }
1655
        return $address;
1656
    }
1657
1658
    public function getCheckoutCustomer($user)
1659
    {
1660
        $customer = [
1661
            'type' => 'person'
1662
        ];
1663
        if (!empty($user['billingaddress']['birthday']) && $user['billingaddress']['birthday'] != '0000-00-00') {
1664
            $customer['date_of_birth'] = $user['billingaddress']['birthday'];
1665
        }
1666
        // SW 5.2 and newer
1667
        if (!empty($user['additional']['user']['birthday']) && $user['additional']['user'] != '0000-00-00') {
1668
            $customer['date_of_birth'] = $user['additional']['user']['birthday'];
1669
        }
1670
1671
        return $customer;
1672
    }
1673
1674
    /**
1675
     *
1676
     * @return string
1677
     */
1678
    public function getLabel()
1679
    {
1680
        return 'Klarna Checkout';
1681
    }
1682
1683
    /**
1684
     * @return string
1685
     * @throws Exception
1686
     */
1687
    public function getVersion()
1688
    {
1689
        $info = json_decode(file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'plugin.json'), true);
1690
1691
        if ($info) {
1692
            return $info['currentVersion'];
1693
        } else {
1694
            throw new Exception('The plugin has an invalid version file.');
1695
        }
1696
    }
1697
1698
    /**
1699
     * @return array
1700
     */
1701
    public function getInfo()
1702
    {
1703
        return [
1704
            'version' => $this->getVersion(),
1705
            'label' => $this->getLabel(),
1706
            'description' => file_get_contents(__DIR__ . '/info.txt')
1707
        ];
1708
    }
1709
1710
    /**
1711
     * Creates and returns the klarna client for an event.
1712
     *
1713
     * @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...
1714
     */
1715
    public function onInitResourceKlarnaCheckoutConnector()
1716
    {
1717
        require_once __DIR__ . '/Components/KlarnaCheckout/Checkout.php';
1718
        if ($this->Config()->get('testDrive')) {
1719
            Klarna_Checkout_Order::$baseUri = 'https://checkout.testdrive.klarna.com/checkout/orders';
1720
        } else {
1721
            Klarna_Checkout_Order::$baseUri = 'https://checkout.klarna.com/checkout/orders';
1722
        }
1723
        Klarna_Checkout_Order::$contentType = "application/vnd.klarna.checkout.aggregated-order-v2+json";
1724
        $sharedSecret = $this->Config()->get('sharedSecret');
1725
        $connector = Klarna_Checkout_Connector::create($sharedSecret);
1726
        $this->klarnaLog("Created Klarna Connector:", 4, $connector);
1727
1728
        return $connector;
1729
    }
1730
1731
    /**
1732
     * @return Klarna
1733
     */
1734
    public function onInitResourceKlarnaService()
1735
    {
1736
        require_once __DIR__ . '/Components/Klarna/Klarna.php';
1737
        require_once __DIR__ . '/Components/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
1738
1739
        $k = new Klarna();
1740
        return $k;
1741
    }
1742
1743
    /**
1744
     * Provide the file collection for less
1745
     *
1746
     * @return \Doctrine\Common\Collections\ArrayCollection
1747
     */
1748
    public function addLessFiles()
1749
    {
1750
        $less = new \Shopware\Components\Theme\LessDefinition(
1751
            [],
1752
            [
1753
                __DIR__ . '/Views/responsive/frontend/_public/src/less/all.less'
1754
            ],
1755
            __DIR__
1756
        );
1757
1758
        return new Doctrine\Common\Collections\ArrayCollection([$less]);
1759
    }
1760
1761
    /**
1762
     * @param string $requiredVersion
1763
     * @return bool|mixed
1764
     */
1765
    protected function assertMinimumVersion($requiredVersion)
1766
    {
1767
        if (Shopware::VERSION === '___VERSION___') {
1768
            return true;
1769
        }
1770
1771
        return version_compare(Shopware::VERSION, $requiredVersion, '>=');
1772
    }
1773
1774
    /**
1775
     * This event is executed when the expressAction of the checkout-controller should be executed.
1776
     * It is needed to redirect the user back to the klarna checkout after deleting an article in the klarna checkout.
1777
     *
1778
     * @param Enlight_Event_EventArgs $args
1779
     * @return bool
1780
     */
1781
    public function onCheckoutExpress(Enlight_Event_EventArgs $args)
1782
    {
1783
        /** @var $action Enlight_Controller_Action */
1784
        $action = $args->get('subject');
1785
1786
        $action->redirect(['controller' => 'payment_klarna', 'action' => 'express']);
1787
        return true;
1788
    }
1789
1790
    /**
1791
     * Helper method to read the color-config options properly.
1792
     *
1793
     * @param $config Enlight_Config
1794
     * @return mixed
1795
     */
1796
    private function getColorConfigOptions($config)
1797
    {
1798
        $options = [];
1799
        $checkoutButtonColor = $config->get('checkoutButtonColor');
1800
        $checkoutButtonTextColor = $config->get('checkoutButtonTextColor');
1801
        $checkoutCheckboxColor = $config->get('checkoutCheckboxColor');
1802
        $checkoutCheckboxCheckMarkColor = $config->get('checkoutCheckboxCheckmarkColor');
1803
        $checkoutHeaderColor = $config->get('checkoutHeaderColor');
1804
        $checkoutLinkColor = $config->get('checkoutLinkColor');
1805
1806
        if (!empty($checkoutButtonColor) && $checkoutButtonColor !== "#") {
1807
            $options['color_button'] = $checkoutButtonColor;
1808
        }
1809
        if (!empty($checkoutButtonTextColor) && $checkoutButtonTextColor !== "#") {
1810
            $options['color_button_text'] = $checkoutButtonTextColor;
1811
        }
1812
        if (!empty($checkoutCheckboxColor) && $checkoutCheckboxColor !== "#") {
1813
            $options['color_checkbox'] = $checkoutCheckboxColor;
1814
        }
1815
        if (!empty($checkoutCheckboxCheckMarkColor) && $checkoutCheckboxCheckMarkColor !== "#") {
1816
            $options['color_checkbox_checkmark'] = $checkoutCheckboxCheckMarkColor;
1817
        }
1818
        if (!empty($checkoutHeaderColor) && $checkoutHeaderColor !== "#") {
1819
            $options['color_header'] = $checkoutHeaderColor;
1820
        }
1821
        if (!empty($checkoutLinkColor) && $checkoutLinkColor !== "#") {
1822
            $options['color_link'] = $checkoutLinkColor;
1823
        }
1824
1825
        return $options;
1826
    }
1827
1828
    /**
1829
     * @param $view Enlight_View_Default
1830
     * @param $config Enlight_Config
1831
     */
1832
    public function getViewConfig($view, $config)
1833
    {
1834
        /** @var sAdmin $adminModule */
1835
        $adminModule = $this->get('modules')->Admin();
1836
        $session = $this->get('session');
1837
        $view->assign('sCountryId', $session['sCountry']);
1838
        $view->assign('sPayments', $this->filterPayments($adminModule->sGetPaymentMeans()));
1839
        $view->assign('sCountryList', $adminModule->sGetCountryList());
1840
        $view->assign('KlarnaHideCheckoutSteps', true);
1841
        $view->assign('KlarnaShowB2bSelect', (bool)$config->get('showB2bSelect'));
1842
        $view->assign('KlarnaShowBasket', (bool)$config->get('showMiniBasket'));
1843
        $view->assign('KlarnaShowDispatch', (bool)$config->get('showDispatch'));
1844
        $view->assign(
1845
            'KlarnaCDNLink',
1846
            $this->buildCDNLink()
1847
        );
1848
        $view->assign(
1849
            'KlarnaLoggedInUser',
1850
            $view->sUserData['billingaddress']['lastname'] == 'Klarna Checkout'
1851
        );
1852
        $view->assign(
1853
            'KlarnaShowLogin',
1854
            $this->getShowLoginConfig($config, !empty($session->sUserId))
1855
        );
1856
        $view->assign(
1857
            'KlarnaDisplayType',
1858
            $this->getKlarnaDisplayType($config)
1859
        );
1860
        $view->assign(
1861
            'KlarnaPositionOrder',
1862
            $this->getPositionOrder($config)
1863
        );
1864
    }
1865
1866
    /**
1867
     * Helper method to get the config whether or not to show the login-panel in the klarna-checkout.
1868
     *
1869
     * @param Enlight_Config $config
1870
     * @param $userLoggedIn
1871
     * @return bool
1872
     */
1873
    private function getShowLoginConfig($config, $userLoggedIn)
1874
    {
1875
        return (bool) $config->get('showLoginPanel') && !($userLoggedIn);
1876
    }
1877
1878
    /**
1879
     * Helper method to find the correct display-type for the frontend.
1880
     * Will return the value configured in the plugin-config, if there is at least one more payment-mean besides klarna.
1881
     * @param $config Enlight_Config
1882
     * @return int
1883
     */
1884
    private function getKlarnaDisplayType($config)
1885
    {
1886
        if (!$this->getOtherPayments()) {
1887
            return 2;
1888
        }
1889
        return $config->get('displayType');
1890
    }
1891
1892
    /**
1893
     * Helper method to find other payment-means besides klarna.
1894
     * @return bool
1895
     */
1896
    private function getOtherPayments()
1897
    {
1898
        $payments = $this->Application()->Modules()->Admin()->sGetPaymentMeans();
1899
1900
        foreach ($payments as $payment) {
1901
            if ($payment['action'] != 'payment_klarna') {
1902
                return true;
1903
            }
1904
        }
1905
1906
        return false;
1907
    }
1908
1909
    /**
1910
     * Helper method to figure out whether or not to show the extra klarna checkout button.
1911
     *
1912
     * @param array $user
1913
     * @return bool
1914
     */
1915
    private function getShowCheckoutButton($user)
1916
    {
1917
        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...
1918
            $user['additional']['payment']['id'] != $this->getPayment()->getId()
1919
        ) {
1920
            return true;
1921
        }
1922
1923
        return false;
1924
    }
1925
1926
    /**
1927
     * Helper method to get the correct order for the elements
1928
     *
1929
     * @param $config Enlight_Config
1930
     * @return array Array with the order of the elements
1931
     */
1932
    private function getPositionOrder($config)
1933
    {
1934
        $loginPanel = 'login_panel';
1935
        $miniBasket = 'mini_basket';
1936
        $dispatch = 'dispatch';
1937
        $payments = 'payments';
1938
        switch ($config->get('positionOrder')) {
1939
            case 1:
1940
                return [$loginPanel, $miniBasket, $dispatch, $payments];
1941
            case 2:
1942
                return [$loginPanel, $miniBasket, $payments, $dispatch];
1943
            case 3:
1944
                return [$dispatch, $payments, $loginPanel, $miniBasket];
1945
            case 4:
1946
            default:
1947
                return [$payments, $dispatch, $loginPanel, $miniBasket];
1948
        }
1949
    }
1950
1951
    /**
1952
     * Helper method to build the proper cdn-link for the image in the tabs-layout.
1953
     * @return string
1954
     */
1955
    private function buildCDNLink()
1956
    {
1957
        $validLocales = [
1958
            'de_de',
1959
            'de_at',
1960
            'en_us',
1961
            'en_gb',
1962
            'fi_fi',
1963
            'sv_se',
1964
            'nb_no',
1965
        ];
1966
        $locale = str_replace('-', '_', $this->getLocale());
1967
1968
        if (!in_array($locale, $validLocales)) {
1969
            $locale = 'en_gb';
1970
        }
1971
        return "https://cdn.klarna.com/1.0/shared/image/generic/badge/{$locale}/checkout/long-no-klarna-logo.png";
1972
    }
1973
1974
    /**
1975
     * Helper method to read the customer-data from the klarna order-object.
1976
     * @param Klarna_Checkout_Order $order
1977
     * @return array
1978
     */
1979
    private function getKlarnaCustomerData($order)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
1980
    {
1981
        $billingAddress = $order['billing_address'];
1982
1983
        return [
1984
            'personal' => [
1985
                'customer_type' => 'private',
1986
                'salutation' => $billingAddress['title'],
1987
                'firstname' => $billingAddress['given_name'],
1988
                'lastname' => $billingAddress['family_name'],
1989
                'email' => $billingAddress['email'],
1990
                'birthday' => $order['customer']['date_of_birth'],
1991
                'phone' => $billingAddress['phone']
1992
            ],
1993
            'billing' => [
1994
                'street' => $billingAddress['street_name'] . ' ' . $billingAddress['street_number'],
1995
                'zipcode' => $billingAddress['postal_code'],
1996
                'city' => $billingAddress['city']
1997
            ]
1998
        ];
1999
    }
2000
2001
    /**
2002
     * Returns an array with all translations
2003
     * @return array
2004
     */
2005
    private function getTranslationArray()
2006
    {
2007
        return [
2008
            'en_GB' => [
2009
                'testDrive' => [
2010
                    'label' => 'Activate test-modus'
2011
                ],
2012
                'merchantId' => [
2013
                    'label' => 'API merchant ID (EID)'
2014
                ],
2015
                'sharedSecret' => [
2016
                    'label' => 'API-Secret (sharedsecret)'
2017
                ],
2018
                'termSiteId' => [
2019
                    'label' => 'Shopsite including the terms and conditions'
2020
                ],
2021
                'allowSeparateShippingAddress' => [
2022
                    'label' => 'Enable differing shipping address'
2023
                ],
2024
                'supportPackstation' => [
2025
                    'label' => 'Support DHL-packstation',
2026
                    'helpText' => 'The differing shipping address must be enabled'
2027
                ],
2028
                'postnumberField' => [
2029
                    'label' => 'Alternative field for the DHL-postnumber'
2030
                ],
2031
                'mandatoryPhone' => [
2032
                    'label' => 'Phone mandatory field'
2033
                ],
2034
                'mandatoryBirthday' => [
2035
                    'label' => 'Birthday mandatory field'
2036
                ],
2037
                'disableAutofocus' => [
2038
                    'label' => 'Disable auto-focus'
2039
                ],
2040
                'showKlarnaButton' => [
2041
                    'label' => 'Show klarna-checkout button'
2042
                ],
2043
                'checkoutButtonColor' => [
2044
                    'label' => 'Checkout Button Color'
2045
                ],
2046
                'checkoutButtonTextColor' => [
2047
                    'label' => 'Checkout Buttontext Color'
2048
                ],
2049
                'checkoutCheckboxColor' => [
2050
                    'label' => 'Checkout Checkbox Color'
2051
                ],
2052
                'checkoutCheckboxCheckmarkColor' => [
2053
                    'label' => 'Checkout Checkbox Tick Color'
2054
                ],
2055
                'checkoutHeaderColor' => [
2056
                    'label' => 'Checkout Header Color'
2057
                ],
2058
                'checkoutLinkColor' => [
2059
                    'label' => 'Checkout Link Color'
2060
                ],
2061
                'KlarnaExternalPayments' => [
2062
                    'label' => 'Display external payment-methods in klarna checkout',
2063
                    'helpText' => 'Your klarna-account has to be unlocked for this feature',
2064
                ],
2065
                'displayType' => [
2066
                    'label' => 'Klarna Checkout display-type',
2067
                    'store' => [
2068
                        [1, 'Display tabs'],
2069
                        [2, 'Display only klarna checkout'],
2070
                        [3, 'One-page display']
2071
                    ],
2072
                ],
2073
                'showB2bSelect' => [
2074
                    'label' => 'Show B2B-select',
2075
                    'helpText' => 'Displays a new select-box containing "Private customer" and "Company" in the klarna checkout'
2076
                ],
2077
                'showLoginPanel' => [
2078
                    'label' => 'Show login-panel',
2079
                    'helpText' => 'Displays a login-panel in the klarna-checkout',
2080
                ],
2081
                'showMiniBasket' => [
2082
                    'label' => 'Show mini-basket',
2083
                    'helpText' => 'Displays a small overview of the basket in the klarna-checkout',
2084
                ],
2085
                'showDispatch' => [
2086
                    'label' => 'Show shipping-country and -method',
2087
                    'helpText' => 'Shows a shipping-country and shipping-method select in the klarna-checkout'
2088
                ],
2089
                'partPaymentWidget' => [
2090
                    'label' => 'Show partial-payment-widget on detail-page'
2091
                ],
2092
                'convertShippingFee' => [
2093
                    'label' => 'Convert shipping-costs to an order-position'
2094
                ],
2095
                'statusId' => [
2096
                    'label' => 'Payment status after order'
2097
                ],
2098
                'activateStatusId' => [
2099
                    'label' => 'Payment status after activation'
2100
                ],
2101
                'cancelStatusId' => [
2102
                    'label' => 'Payment status after cancellation'
2103
                ]
2104
            ]
2105
        ];
2106
    }
2107
2108
    /**
2109
     * Helper method to update the klarna-payment when updating from any version to >= 2.0 of klarna.
2110
     * It adds "austria" to the valid countries.
2111
     */
2112
    private function updatePayment()
2113
    {
2114
        /** @var \Shopware\Components\Model\ModelManager $manager */
2115
        $manager = $this->get('models');
2116
        $payment = $manager->getRepository('Shopware\Models\Payment\Payment')->findOneBy([
2117
            'name' => 'klarna_checkout'
2118
        ]);
2119
2120
        if (empty($payment)) {
2121
            return;
2122
        }
2123
2124
        $updateNeeded = true;
2125
        $countries = $payment->getCountries();
2126
        /** @var Shopware\Models\Country\Country $country */
2127
        foreach ($countries as $country) {
2128
            if ($country->getIso() == 'AT') {
2129
                $updateNeeded = false;
2130
            }
2131
        }
2132
2133
        if ($updateNeeded) {
2134
            $countries->add($manager->getRepository('Shopware\Models\Country\Country')->findOneBy(['iso' => 'AT']));
2135
            $payment->setCountries($countries);
2136
2137
            $manager->persist($payment);
2138
            $manager->flush();
2139
        }
2140
    }
2141
2142
    /**
2143
     * Method checks if selected country is valid for use with klarna
2144
     * 
2145
     * @param string $countryId
2146
     * @return boolean
2147
     */
2148
    public function checkValidKlarnaCountry($countryId)
2149
    {
2150
        $allowedCountries = [];
2151
        $countries = $this->getPayment()->getCountries();
2152
        foreach ($countries as $country) {
2153
            $allowedCountries[] = $country->getId();
2154
        }
2155
2156
        $countryPaymentisAllowed = in_array($countryId, $allowedCountries);
2157
        // early return if country is not active for KCO in backend settings
2158
        if (!$countryPaymentisAllowed) {
2159
            return false;
2160
        }
2161
2162
        // always allow austrian KCO for german shops and vice-versa
2163
        $shopCountry = $this->getCountryByShop(Shopware()->Shop());
2164
        if ($shopCountry == "2" && $countryId == "23") {
2165
            return true;
2166
        } elseif ($shopCountry == "23" && $countryId == "2") {
2167
            return true;
2168
        } else {
2169
            return ($countryId == $shopCountry);
2170
        }
2171
    }
2172
    
2173
2174
    /**
2175
     * Helper method to read all payments, that should be displayed in the klarna checkout.
2176
     * @param $basket
2177
     * @return array
2178
     */
2179
    public function getExternalPaymentMethods($basket)
2180
    {
2181
        $payments = Shopware()->Models()->getRepository('Shopware\Models\Attribute\Payment')->findBy([
2182
            'swagKlarnaShowInKlarnaIframe' => 1,
2183
            'swagKlarnaAllowInPaymentContainer' => 0
2184
        ]);
2185
2186
        $externalPayments = [];
2187
        $externalCheckouts = [];
2188
        /** @var Shopware\Models\Attribute\Payment $payment */
2189
        foreach ($payments as $payment) {
2190
            $paymentObj = $payment->getPayment();
2191
            if (is_null($paymentObj)) {
2192
                $paymentName = false;
2193
            } else {
2194
                $paymentName = $paymentObj->getName();
2195
            }
2196
            
2197
            if (!$paymentName) {
2198
                continue;
2199
            }
2200
            
2201
            if ($paymentName && $paymentName == 'klarna_checkout') {
2202
                continue;
2203
            }
2204
            $paymentArray = [
2205
                'name' => $payment->getPayment()->getDescription(),
2206
                'redirect_uri' => $this->getRedirectUri() . '/paymentId/' . $payment->getPaymentId()
2207
            ];
2208
2209
            if ($fee = $this->getFee($payment->getPayment(), $basket)) {
2210
                $paymentArray['fee'] = $fee;
2211
            }
2212
2213
            if ($description = $payment->getPayment()->getAdditionalDescription()) {
2214
                //Shorten the description to max. 500 characters
2215
                $description = strip_tags($description);
2216
                $description = preg_replace('#<!--.*-->#ms', '', $description);
2217
                $paymentArray['description'] = substr($description, 0, 497) . '...';
2218
            }
2219
2220
            //Only add to external checkouts if an image is set and if the shop supports SSL
2221
            if (Shopware()->Shop()->getSecure() && $image = $this->getImageForKlarna($payment)) {
2222
                $paymentArray['image_uri'] = $image;
2223
                $externalCheckouts[] = $paymentArray;
2224
            }
2225
2226
            $externalPayments[] = $paymentArray;
2227
        }
2228
2229
        return [$externalPayments, $externalCheckouts];
2230
    }
2231
2232
    /**
2233
     * @param Shopware\Models\Payment\Payment $payment
2234
     * @param $basket
2235
     * @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...
2236
     */
2237
    private function getFee($payment, $basket)
2238
    {
2239
        $fee = 0;
2240
        $amount = str_replace(',', '.', $basket['Amount']);
2241
2242
        if ($surcharge = $payment->getSurcharge()) {
2243
            $fee += $surcharge;
2244
            $amount += $surcharge;
2245
        }
2246
2247
        if ($percent = $payment->getDebitPercent()) {
2248
            $fee += round($amount / 100 * $percent, 3);
2249
        }
2250
2251
        return round($fee * 100);
2252
    }
2253
2254
    /**
2255
     * Helper method to get the redirect-uri
2256
     * @return string
2257
     */
2258
    private function getRedirectUri()
2259
    {
2260
        return Shopware()->Front()->Router()->assemble([
2261
            'controller' => 'PaymentKlarna',
2262
            'action' => 'setPayment'
2263
        ]);
2264
    }
2265
2266
    /**
2267
     * Helper method to read the image for the klarna-checkout if set
2268
     * @param Shopware\Models\Attribute\Payment $payment
2269
     * @return null|string
2270
     */
2271
    private function getImageForKlarna($payment)
2272
    {
2273
        $media = $payment->getSwagKlarnaKlarnaMedia();
2274
        if (!$payment->getSwagKlarnaShowInKlarnaIframe() || !empty($media)) {
2275
            if ($this->assertMinimumVersion('5.1') && version_compare(Shopware::VERSION, '5.2.0', '<=')) {
2276
                $media = $this->get('shopware_media.media_service')->getUrl($media);
2277
            } else {
2278
                /** @var Enlight_Controller_Front $front */
2279
                $front = $this->get('front');
2280
                $request = $front->Request();
2281
                if ($request && $request->getHttpHost()) {
2282
                    $url = ($request->isSecure() ? 'https' : 'http') .
2283
                        '://' . $request->getHttpHost() .
2284
                        $request->getBasePath() . "/";
2285
                } else {
2286
                    $url = $front->Router()->assemble(['controller' => 'index', 'module' => 'frontend']);
2287
                }
2288
                if (version_compare(Shopware::VERSION, '5.2.0', '>=')) {
2289
                    # make sure me get only the image name, path is set in case of upgarde from SW.5.1 to 5.2
2290
                    $parts = explode('/', $media);
2291
                    $end = end($parts);
2292
                    $media = $url . 'media/image/' . $end;
2293
                } else {
2294
                    $media = $url . $media;
2295
                }
2296
            }
2297
2298
            return $media;
2299
        }
2300
        return null;
2301
    }
2302
2303
    /**
2304
     * Helper method to filter the available payment-means.
2305
     * @param $sGetPaymentMeans
2306
     * @return array
2307
     */
2308
    public function filterPayments($sGetPaymentMeans)
2309
    {
2310
        $paymentArray = [];
2311
        foreach ($sGetPaymentMeans as $paymentMean) {
2312
            if (!$this->isPaymentAllowed($paymentMean)) {
2313
                continue;
2314
            }
2315
2316
            $paymentArray[] = $paymentMean;
2317
        }
2318
        return $paymentArray;
2319
    }
2320
2321
    /**
2322
     * Helper method to check if a payment is allowed to be
2323
     * @param $payment
2324
     * @return bool
2325
     */
2326
    private function isPaymentAllowed($payment)
2327
    {
2328
        if ($payment['name'] == 'klarna_checkout') {
2329
            return false;
2330
        }
2331
        $connection = Shopware()->Models()->getConnection();
2332
2333
        $builder = $connection->createQueryBuilder();
2334
        $builder->select('swag_klarna_allow_in_payment_container', 'swag_klarna_show_in_klarna_iframe')
2335
            ->from('s_core_paymentmeans_attributes')
2336
            ->where('paymentmeanID = :id')
2337
            ->setParameter(':id', $payment['id']);
2338
2339
        $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...
2340
        return !$result['swag_klarna_allow_in_payment_container'] && !$result['swag_klarna_show_in_klarna_iframe'];
2341
    }
2342
2343
    /**
2344
     * Builds the new klarna version-string.
2345
     *
2346
     * @param Klarna $klarna
2347
     * @return string
2348
     */
2349
    private function buildKlarnaVersion(Klarna $klarna)
2350
    {
2351
        $versionInfo = [
2352
            'Shopware',
2353
            $this->Application()->Config()->version,
2354
            'KCO-Plugin',
2355
            $this->getVersion(),
2356
            $klarna->getVersion()
2357
        ];
2358
2359
        return implode(':', $versionInfo);
2360
    }
2361
2362
    /**
2363
     * Helper method to find out if the kpm plugin is active
2364
     */
2365 View Code Duplication
    public function isKpmActive()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2366
    {
2367
        /** @var Doctrine\DBAL\Query\QueryBuilder $queryBuilder */
2368
        $queryBuilder = Shopware()->Models()->getConnection()->createQueryBuilder();
2369
2370
        $result = $queryBuilder->select('plugin.id')
2371
            ->from('s_core_plugins', 'plugin')
2372
            ->where('plugin.name = :name')
2373
            ->andWhere('plugin.active = 1')
2374
            ->setParameter('name', 'SwagPaymentKlarnaKpm')
2375
            ->execute()
2376
            ->fetchColumn();
2377
2378
        return !empty($result);
2379
    }
2380
2381
    /**
2382
     * Helper method to find out if the kco paymentmean is active
2383
     */
2384 View Code Duplication
    public function isKcoPaymentActive()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2385
    {
2386
        /** @var Doctrine\DBAL\Query\QueryBuilder $queryBuilder */
2387
        $queryBuilder = Shopware()->Models()->getConnection()->createQueryBuilder();
2388
2389
        $result = $queryBuilder->select('payment.id')
2390
            ->from('s_core_paymentmeans', 'payment')
2391
            ->where('payment.name = :name')
2392
            ->andWhere('payment.active = 1')
2393
            ->setParameter('name', 'klarna_checkout')
2394
            ->execute()
2395
            ->fetchColumn();
2396
2397
        return !empty($result);
2398
    }
2399
2400
    /**
2401
     * Helper method to find out if the klarna kco payment is active.
2402
     * Necessary to disable the checkout-button.
2403
     * @param array $user
2404
     * @return bool
2405
     */
2406
    public function isKlarnaKcoPaymentActive($user)
2407
    {
2408
        $payment = $this->getPayment();
2409
        if (!$payment) {
2410
            return false;
2411
        }
2412
        $data = $this->get('modules')->Admin()->sGetPaymentMeanById($payment->getId(), $user);
2413
        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...
2414
            return false;
2415
        }
2416
        return true;
2417
    }
2418
}
2419