Completed
Pull Request — 5.5 (#1680)
by
unknown
21:02
created

Shopware_Components_Document::render()   C

Complexity

Conditions 9
Paths 32

Size

Total Lines 50
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 32
nc 32
nop 1
dl 0
loc 50
rs 6
c 0
b 0
f 0
1
<?php
2
/**
3
 * Shopware 5
4
 * Copyright (c) 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 Shopware\Components\NumberRangeIncrementerInterface;
26
27
/**
28
 * Shopware document generator
29
 *
30
 * @category  Shopware
31
 *
32
 * @copyright Copyright (c) shopware AG (http://www.shopware.de)
33
 */
34
class Shopware_Components_Document extends Enlight_Class implements Enlight_Hook
35
{
36
    /**
37
     * Object from Type Model\Order
38
     *
39
     * @var \Shopware_Models_Document_Order
40
     */
41
    public $_order;
42
43
    /**
44
     * Shopware Template Object (Smarty)
45
     *
46
     * @var \Enlight_Template_Manager
47
     */
48
    public $_template;
49
50
    /**
51
     * Shopware View Object (Smarty)
52
     *
53
     * @var \Smarty_Data
54
     */
55
    public $_view;
56
57
    /**
58
     * Configuration
59
     *
60
     * @var array
61
     */
62
    public $_config;
63
64
    /**
65
     * Define output
66
     *
67
     * @var string html,pdf,return
68
     */
69
    public $_renderer = 'html';
70
71
    /**
72
     * Are properties already assigned to smarty?
73
     *
74
     * @var bool
75
     */
76
    public $_valuesAssigend = false;
77
78
    /**
79
     * Subshop-Configuration
80
     *
81
     * @var array
82
     */
83
    public $_subshop;
84
85
    /**
86
     * Path to load templates from
87
     *
88
     * @var string
89
     */
90
    public $_defaultPath = 'templates/Bare';
91
92
    /**
93
     * Generate preview only
94
     *
95
     * @var bool
96
     */
97
    public $_preview = false;
98
99
    /**
100
     * Typ/ID of document [0,1,2,3] - s_core_documents
101
     *
102
     * @var int
103
     */
104
    public $_typID;
105
106
    /**
107
     * Document-Metadata / Properties
108
     *
109
     * @var array
110
     */
111
    public $_document;
112
113
    /**
114
     * Invoice / Document number
115
     *
116
     * @var int
117
     */
118
    public $_documentID;
119
120
    /**
121
     * Primary key of the created document row (s_order_documents)
122
     *
123
     * @var int
124
     */
125
    public $_documentRowID;
126
127
    /**
128
     * Hash of the created document row (s_order_documents.hash), will be used as filename when preview is false
129
     *
130
     * @var string
131
     */
132
    public $_documentHash;
133
134
    /**
135
     * Invoice ID for reference in shipping documents etc.
136
     *
137
     * @var string
138
     */
139
    public $_documentBid;
140
141
    /**
142
     * Ref to the translation component
143
     *
144
     * @var \Shopware_Components_Translation
145
     */
146
    public $translationComponent;
147
148
    /**
149
     * Static function to initiate document class
150
     *
151
     * @param int   $orderID    s_order.id
152
     * @param int   $documentID s_core_documents.id
153
     * @param array $config     - configuration array, for possible values see backend\document controller
154
     *
155
     * @throws Enlight_Exception
156
     *
157
     * @return \Shopware_Components_Document
158
     */
159
    public static function initDocument($orderID, $documentID, array $config = [])
160
    {
161
        if (empty($orderID)) {
162
            $config['_preview'] = true;
163
        }
164
165
        /** @var $document Shopware_Components_Document */
166
        $document = Enlight_Class::Instance('Shopware_Components_Document'); //new Shopware_Components_Document();
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
167
168
        //$d->setOrder(new Shopware_Models_Document_Order($orderID,$config));
0 ignored issues
show
Unused Code Comprehensibility introduced by
79% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
169
        $document->setOrder(Enlight_Class::Instance('Shopware_Models_Document_Order', [$orderID, $config]));
170
171
        $document->setConfig($config);
172
173
        $document->setDocumentId($documentID);
174
        if (!empty($orderID)) {
175
            $document->_subshop = Shopware()->Db()->fetchRow("
176
                SELECT
177
                    s.id,
178
                    m.document_template_id as doc_template_id,
179
                    m.template_id as template_id,
180
                    (SELECT CONCAT('templates/', template) FROM s_core_templates WHERE id = m.document_template_id) as doc_template,
181
                    (SELECT CONCAT('templates/', template) FROM s_core_templates WHERE id = m.template_id) as template,
182
                    s.id as isocode,
183
                    s.locale_id as locale
184
                FROM s_order, s_core_shops s
185
                LEFT JOIN s_core_shops m
186
                    ON m.id=s.main_id
187
                    OR (s.main_id IS NULL AND m.id=s.id)
188
                WHERE s_order.language = s.id
189
                AND s_order.id = ?
190
                ",
191
                [$orderID]
192
            );
193
194
            if (empty($document->_subshop['doc_template'])) {
195
                $document->setTemplate($document->_defaultPath);
196
            }
197
198
            if (empty($document->_subshop['id'])) {
199
                throw new Enlight_Exception("Could not load template path for order $orderID");
200
            }
201
        } else {
202
            $document->_subshop = Shopware()->Db()->fetchRow("
203
            SELECT
204
                s.id,
205
                s.document_template_id as doc_template_id,
206
                s.template_id,
207
                (SELECT CONCAT('templates/', template) FROM s_core_templates WHERE id = s.document_template_id) as doc_template,
208
                (SELECT CONCAT('templates/', template) FROM s_core_templates WHERE id = s.template_id) as template,
209
                s.id as isocode,
210
                s.locale_id as locale
211
            FROM s_core_shops s
212
            WHERE s.default = 1
213
            ");
214
215
            if (empty($document->_subshop['doc_template'])) {
216
                $document->setTemplate($document->_defaultPath);
217
                $document->_subshop['doc_template'] = $document->_defaultPath;
218
            }
219
        }
220
221
        $document->setTranslationComponent();
222
        $document->initTemplateEngine();
223
224
        return $document;
225
    }
226
227
    /**
228
     * Start renderer / pdf-generation
229
     *
230
     * @param string optional define renderer (pdf,html,return)
231
     *
232
     * @throws \Enlight_Event_Exception
233
     * @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
234
     */
235
    public function render($_renderer = '')
236
    {
237
        if (!empty($_renderer)) {
238
            $this->_renderer = $_renderer;
239
        }
240
        if ($this->_valuesAssigend == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
241
            $this->assignValues();
242
        }
243
244
        /* @var $template \Shopware\Models\Shop\Template */
245
        if (!empty($this->_subshop['doc_template_id'])) {
246
            $template = Shopware()->Container()->get('models')->find(\Shopware\Models\Shop\Template::class, $this->_subshop['doc_template_id']);
247
248
            $inheritance = Shopware()->Container()->get('theme_inheritance')->getTemplateDirectories($template);
249
            $this->_template->setTemplateDir($inheritance);
250
        }
251
252
        $html = $this->_template->fetch('documents/' . $this->_document['template'], $this->_view);
253
254
        /** @var \Enlight_Event_EventManager $eventManager */
255
        $eventManager = Shopware()->Container()->get('events');
256
        $html = $eventManager->filter('Shopware_Components_Document_Render_FilterHtml', $html, [
257
            'document' => $this,
258
        ]);
259
260
        if ($this->_renderer === 'html' || !$this->_renderer) {
261
            echo $html;
262
        } elseif ($this->_renderer === 'pdf') {
263
            $mpdfConfig = array_replace_recursive(
264
                Shopware()->Container()->getParameter('shopware.mpdf.defaultConfig'),
265
                [
266
                    'margin_left' => $this->_document['left'],
267
                    'margin_right' => $this->_document['right'],
268
                    'margin_top' => $this->_document['top'],
269
                    'margin_bottom' => $this->_document['bottom'],
270
                ]
271
            );
272
            if ($this->_preview == true || !$this->_documentHash) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
273
                $mpdf = new \Mpdf\Mpdf($mpdfConfig);
274
                $mpdf->WriteHTML($html);
275
                $mpdf->Output();
276
                exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method render() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
277
            }
278
            $documentsPath = rtrim(Shopware()->Container()->getParameter('shopware.app.documentsdir'), '/');
279
            $path = $documentsPath . '/' . $this->_documentHash . '.pdf';
280
            $mpdf = new \Mpdf\Mpdf($mpdfConfig);
281
            $mpdf->WriteHTML($html);
282
            $mpdf->Output($path, 'F');
283
        }
284
    }
285
286
    /**
287
     * Assign configuration / data to template
288
     */
289
    public function assignValues()
290
    {
291
        $this->loadConfiguration4x();
292
293
        if (!$this->_preview) {
294
            $this->saveDocument();
295
        }
296
297
        return $this->assignValues4x();
298
    }
299
300
    /**
301
     * Set template path
302
     *
303
     * @param string $path
304
     */
305
    public function setTemplate($path)
306
    {
307
        if (!empty($path)) {
308
            $this->_subshop['doc_template'] = $path;
309
        }
310
    }
311
312
    /**
313
     * Set renderer
314
     *
315
     * @param string $renderer
316
     */
317
    public function setRenderer($renderer)
318
    {
319
        $this->_renderer = $renderer;
320
    }
321
322
    /**
323
     * Set type of document (0,1,2,3) > s_core_documents
324
     *
325
     * @param int $id
326
     */
327
    public function setDocumentId($id)
328
    {
329
        $this->_typID = $id;
330
    }
331
332
    /**
333
     * Get voucher (s_vouchers.id)
334
     *
335
     * @param $id
336
     *
337
     * @return bool|mixed
338
     */
339
    public function getVoucher($id)
340
    {
341
        if (empty($id)) {
342
            return false;
343
        }
344
345
        // Check if voucher is available
346
        $sqlVoucher = 'SELECT s_emarketing_voucher_codes.id AS id, code, description, value, percental FROM s_emarketing_vouchers, s_emarketing_voucher_codes
347
         WHERE  modus = 1 AND (valid_to >= CURDATE() OR valid_to IS NULL)
348
         AND s_emarketing_voucher_codes.voucherID = s_emarketing_vouchers.id
349
         AND s_emarketing_voucher_codes.userID IS NULL
350
         AND s_emarketing_voucher_codes.cashed = 0
351
         AND s_emarketing_vouchers.id=?
352
         Limit 1
353
         ';
354
355
        $getVoucher = Shopware()->Db()->fetchRow($sqlVoucher, [$id]);
356
        if ($getVoucher['id']) {
357
            // Update Voucher and pass-information to template
358
            Shopware()->Db()->query('
359
            UPDATE s_emarketing_voucher_codes
360
            SET
361
                userID = ?
362
            WHERE
363
                id = ?
364
            ', [$this->_order->userID, $getVoucher['id']]);
365
            if ($this->_order->currency->factor != 1) {
366
                $getVoucher['value'] *= $this->_order->currency->factor;
367
            }
368
            if (!empty($getVoucher['percental'])) {
369
                $getVoucher['prefix'] = '%';
370
            } else {
371
                $getVoucher['prefix'] = $this->_order->currency->char;
372
            }
373
        }
374
375
        return $getVoucher;
376
    }
377
378
    /**
379
     * Assign configuration / data to template, new template base
380
     */
381
    protected function assignValues4x()
382
    {
383
        if ($this->_preview == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
384
            $id = 12345;
385
        } else {
386
            $id = $this->_documentID;
387
        }
388
389
        $Document = $this->_document->getArrayCopy();
0 ignored issues
show
Bug introduced by
The method getArrayCopy cannot be called on $this->_document (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
390
        if (empty($this->_config['date'])) {
391
            $this->_config['date'] = date('d.m.Y');
392
        }
393
        $Document = array_merge(
394
            $Document,
395
            [
396
                'comment' => $this->_config['docComment'],
397
                'id' => $id,
398
                'bid' => $this->_documentBid,
399
                'date' => $this->_config['date'],
400
                'deliveryDate' => $this->_config['delivery_date'],
401
                // The "netto" config flag, if set to true, allows creating
402
                // netto documents for brutto orders. Setting it to false,
403
                // does not however create brutto documents for netto orders.
404
                'netto' => $this->_order->order->taxfree ? true : $this->_config['netto'],
405
                'nettoPositions' => $this->_order->order->net,
406
            ]
407
        );
408
        $Document['voucher'] = $this->getVoucher($this->_config['voucher']);
409
        $this->_view->assign('Document', $Document);
410
411
        // Translate payment and dispatch depending on the order's language
412
        // and replace the default payment/dispatch text
413
        $dispatchId = $this->_order->order->dispatchID;
414
        $paymentId = $this->_order->order->paymentID;
415
        $translationPayment = $this->readTranslationWithFallback($this->_order->order->language, 'config_payment');
416
        $translationDispatch = $this->readTranslationWithFallback($this->_order->order->language, 'config_dispatch');
417
418
        if (isset($translationPayment[$paymentId])) {
419
            if (isset($translationPayment[$paymentId]['description'])) {
420
                $this->_order->payment->description = $translationPayment[$paymentId]['description'];
421
            }
422
            if (isset($translationPayment[$paymentId]['additionalDescription'])) {
423
                $this->_order->payment->additionaldescription = $translationPayment[$paymentId]['additionalDescription'];
424
            }
425
        }
426
427
        if (isset($translationDispatch[$dispatchId])) {
428
            if (isset($translationDispatch[$dispatchId]['dispatch_name'])) {
429
                $this->_order->dispatch->name = $translationDispatch[$dispatchId]['dispatch_name'];
430
            }
431
            if (isset($translationDispatch[$dispatchId]['dispatch_description'])) {
432
                $this->_order->dispatch->description = $translationDispatch[$dispatchId]['dispatch_description'];
433
            }
434
        }
435
436
        $this->_view->assign('Order', $this->_order->__toArray());
437
        $this->_view->assign('Containers', $this->_document->containers->getArrayCopy());
438
439
        $order = clone $this->_order;
440
441
        $positions = $order->positions->getArrayCopy();
442
443
        $articleModule = Shopware()->Modules()->Articles();
444
        foreach ($positions as &$position) {
445
            if ($position['modus'] == 0) {
446
                $position['meta'] = $articleModule->sGetPromotionById('fix', 0, $position['articleordernumber']);
447
            }
448
        }
449
450
        if ($this->_config['_previewForcePagebreak']) {
451
            $positions = array_merge($positions, $positions);
452
        }
453
454
        $positions = array_chunk($positions, $this->_document['pagebreak'], true);
455
        $this->_view->assign('Pages', $positions);
456
457
        $user = [
458
            'shipping' => $order->shipping,
459
            'billing' => $order->billing,
460
            'additional' => [
461
                'countryShipping' => $order->shipping->country,
462
                'country' => $order->billing->country,
463
            ],
464
        ];
465
        $this->_view->assign('User', $user);
466
    }
467
468
    /**
469
     * Loads translations including fallbacks
470
     *
471
     * @param string $languageId
472
     * @param string $type
473
     *
474
     * @return array
475
     */
476
    protected function readTranslationWithFallback($languageId, $type)
477
    {
478
        $fallbackLanguageId = Shopware()->Db()->fetchOne(
479
            'SELECT fallback_id FROM s_core_shops WHERE id = ?',
480
            [$languageId]
481
        );
482
483
        return $this->translationComponent->readBatchWithFallback($languageId, $fallbackLanguageId, $type);
484
    }
485
486
    /**
487
     * Load template / document configuration (s_core_documents / s_core_documents_box)
488
     */
489
    protected function loadConfiguration4x()
490
    {
491
        $id = $this->_typID;
492
493
        $this->_document = new ArrayObject(
0 ignored issues
show
Documentation Bug introduced by
It seems like new \ArrayObject(Shopwar...d), \PDO::FETCH_ASSOC)) of type object<ArrayObject> is incompatible with the declared type array of property $_document.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
494
            Shopware()->Db()->fetchRow(
495
                'SELECT * FROM s_core_documents WHERE id = ?',
496
                [$id],
497
                \PDO::FETCH_ASSOC
498
            )
499
        );
500
501
        // Load Containers
502
        $containers = Shopware()->Db()->fetchAll(
503
            'SELECT * FROM s_core_documents_box WHERE documentID = ?',
504
            [$id],
505
            \PDO::FETCH_ASSOC
506
        );
507
508
        $translation = $this->translationComponent->read($this->_order->order->language, 'documents', 1);
509
        $this->_document->containers = new ArrayObject();
0 ignored issues
show
Bug introduced by
The property containers does not seem to exist in ArrayObject.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
510
        foreach ($containers as $key => $container) {
511
            if (!is_numeric($key)) {
512
                continue;
513
            }
514
            if (!empty($translation[$id][$container['name'] . '_Value'])) {
515
                $containers[$key]['value'] = $translation[$id][$container['name'] . '_Value'];
516
            }
517
            if (!empty($translation[$id][$container['name'] . '_Style'])) {
518
                $containers[$key]['style'] = $translation[$id][$container['name'] . '_Style'];
519
            }
520
521
            // parse smarty tags
522
            $containers[$key]['value'] = $this->_template->fetch('string:' . $containers[$key]['value']);
523
524
            $this->_document->containers->offsetSet($container['name'], $containers[$key]);
525
        }
526
    }
527
528
    /**
529
     * Initiate smarty template engine
530
     *
531
     * @throws \Exception
532
     */
533
    protected function initTemplateEngine()
534
    {
535
        $frontendThemeDirectory = Shopware()->Container()->get('theme_path_resolver')->getFrontendThemeDirectory();
536
537
        $this->_template = clone Shopware()->Template();
538
        $this->_view = $this->_template->createData();
539
540
        $path = basename($this->_subshop['doc_template']);
541
542
        if ($this->_template->security_policy) {
543
            $this->_template->security_policy->secure_dir[] = $frontendThemeDirectory . DIRECTORY_SEPARATOR . $path;
544
        }
545
        $this->_template->setTemplateDir(['custom' => $path]);
546
        $this->_template->setCompileId(str_replace('/', '_', $path) . '_' . $this->_subshop['id']);
547
    }
548
549
    /**
550
     * Sets the translation component
551
     *
552
     * @throws \Exception
553
     */
554
    protected function setTranslationComponent()
555
    {
556
        $this->translationComponent = Shopware()->Container()->get('translation');
557
    }
558
559
    /**
560
     * @param Shopware_Models_Document_Order $order
561
     *
562
     * @throws \Exception
563
     */
564
    protected function setOrder(Shopware_Models_Document_Order $order)
565
    {
566
        $this->_order = $order;
567
568
        $repository = Shopware()->Models()->getRepository(\Shopware\Models\Shop\Shop::class);
569
        // "language" actually refers to a language-shop and not to a locale
570
        $shop = $repository->getById($this->_order->order->language);
571
        if (!empty($this->_order->order->currencyID)) {
572
            $repository = Shopware()->Models()->getRepository(\Shopware\Models\Shop\Currency::class);
573
            $shop->setCurrency($repository->find($this->_order->order->currencyID));
574
        }
575
        $shop->registerResources();
576
    }
577
578
    /**
579
     * Set object configuration from array
580
     *
581
     * @param array $config
582
     */
583
    protected function setConfig(array $config)
584
    {
585
        $this->_config = $config;
586
        foreach ($config as $key => $v) {
587
            if (property_exists($this, $key)) {
588
                $this->$key = $v;
589
            }
590
        }
591
    }
592
593
    /**
594
     * Save document in database / generate number
595
     *
596
     * @throws \Exception
597
     * @throws \RuntimeException
598
     * @throws \Zend_Db_Adapter_Exception
599
     * @throws \Doctrine\ORM\OptimisticLockException
600
     */
601
    protected function saveDocument()
602
    {
603
        if ($this->_preview == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
604
            return;
605
        }
606
607
        $bid = $this->_config['bid'];
608
        if (!empty($bid)) {
609
            $this->_documentBid = $bid;
610
        }
611
        if (empty($bid)) {
612
            $bid = 0;
613
        }
614
615
        // Check if this kind of document already exists
616
        $typID = $this->_typID;
617
618
        $checkForExistingDocument = Shopware()->Db()->fetchRow('
619
        SELECT ID,docID,hash FROM s_order_documents WHERE userID = ? AND orderID = ? AND type = ?
620
        ', [$this->_order->userID, $this->_order->id, $typID]);
621
622
        if (!empty($checkForExistingDocument['ID'])) {
623
            // Document already exist. Update date and amount!
624
            $update = '
625
            UPDATE `s_order_documents` SET `date` = now(),`amount` = ?
626
            WHERE `type` = ? AND userID = ? AND orderID = ? LIMIT 1
627
            ';
628
            $amount = ($this->_order->order->taxfree ? true : $this->_config['netto']) ? round($this->_order->amountNetto, 2) : round($this->_order->amount, 2);
629
            if ($typID == 4) {
630
                $amount *= -1;
631
            }
632
            Shopware()->Db()->query($update, [
633
                    $amount,
634
                    $typID,
635
                    $this->_order->userID,
636
                    $this->_order->id,
637
                ]);
638
639
            if (!empty($this->_config['attributes'])) {
640
                // Get the updated document
641
                $updatedDocument = Shopware()->Models()->getRepository(\Shopware\Models\Order\Document\Document::class)->findOneBy([
642
                    'type' => $typID,
643
                    'customerId' => $this->_order->userID,
644
                    'orderId' => $this->_order->id,
645
                ]);
646
                // Check its attributes
647
                if ($updatedDocument->getAttribute() === null) {
648
                    // Create a new attributes entity for the document
649
                    $documentAttributes = new \Shopware\Models\Attribute\Document();
650
                    $updatedDocument->setAttribute($documentAttributes);
651
                    // Persist the document
652
                    Shopware()->Models()->flush($updatedDocument);
653
                }
654
                // Save all given attributes
655
                $updatedDocument->getAttribute()->fromArray($this->_config['attributes']);
656
                // Persist the attributes
657
                Shopware()->Models()->flush($updatedDocument->getAttribute());
658
            }
659
660
            $rowID = $checkForExistingDocument['ID'];
661
            $bid = $checkForExistingDocument['docID'];
662
            $hash = $checkForExistingDocument['hash'];
663
        } else {
664
            // Create new document
665
666
            $hash = md5(uniqid(rand()));
667
668
            $amount = ($this->_order->order->taxfree ? true : $this->_config['netto']) ? round($this->_order->amountNetto, 2) : round($this->_order->amount, 2);
669
            if ($typID == 4) {
670
                $amount *= -1;
671
            }
672
            $sql = '
673
            INSERT INTO s_order_documents (`date`, `type`, `userID`, `orderID`, `amount`, `docID`,`hash`)
674
            VALUES ( NOW() , ? , ? , ?, ?, ?,?)
675
            ';
676
            Shopware()->Db()->query($sql, [
677
                $typID,
678
                $this->_order->userID,
679
                $this->_order->id,
680
                $amount,
681
                $bid,
682
                $hash,
683
            ]);
684
            $rowID = Shopware()->Db()->lastInsertId();
685
686
            // Add an entry in s_order_documents_attributes for the created document
687
            // containing all values found in the 'attributes' element of '_config'
688
            $createdDocument = Shopware()->Models()->getRepository('\Shopware\Models\Order\Document\Document')->findOneById($rowID);
689
            // Create a new attributes entity for the document
690
            $documentAttributes = new \Shopware\Models\Attribute\Document();
691
            $createdDocument->setAttribute($documentAttributes);
692
            if (!empty($this->_config['attributes'])) {
693
                // Save all given attributes
694
                $createdDocument->getAttribute()->fromArray($this->_config['attributes']);
695
            }
696
            // Persist the document
697
            Shopware()->Models()->flush($createdDocument);
698
699
            // Update numberrange, except for cancellations
700
            if ($typID != 4) {
701
                if (!empty($this->_document['numbers'])) {
702
                    $numberrange = $this->_document['numbers'];
703
                } else {
704
                    // The typID is indexed with base 0, so we need increase the typID
705
                    if (!in_array($typID, ['1', '2', '3'])) {
706
                        $typID = $typID + 1;
707
                    }
708
                    $numberrange = 'doc_' . $typID;
709
                }
710
711
                /** @var NumberRangeIncrementerInterface $incrementer */
712
                $incrementer = Shopware()->Container()->get('shopware.number_range_incrementer');
713
714
                // Get the next number and save it in the document
715
                $nextNumber = $incrementer->increment($numberrange);
716
717
                Shopware()->Db()->query('
718
                    UPDATE `s_order_documents` SET `docID` = ? WHERE `ID` = ? LIMIT 1 ;
719
                ', [$nextNumber, $rowID]);
720
721
                $bid = $nextNumber;
722
            }
723
        }
724
        $this->_documentID = $bid;
725
        $this->_documentRowID = $rowID;
726
        $this->_documentHash = $hash;
727
    }
728
}
729