Exchange   F
last analyzed

Complexity

Total Complexity 109

Size/Duplication

Total Lines 767
Duplicated Lines 5.22 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
dl 40
loc 767
rs 1.833
c 0
b 0
f 0
wmc 109
lcom 1
cbo 9

23 Methods

Rating   Name   Duplication   Size   Complexity  
F __construct() 0 79 12
A __destruct() 0 9 2
A makeDBBackup() 0 12 3
A get1CSettings() 0 4 1
A _install() 31 31 2
A _deinstall() 0 6 2
B error_log() 0 27 6
A __autoload() 0 4 1
A check_password() 0 9 3
A command_catalog_checkauth() 0 9 2
A checkauth() 0 8 1
A check_perm() 0 14 3
A command_catalog_init() 0 8 2
D command_catalog_file() 9 66 21
A _readXmlFile() 0 8 3
F command_catalog_import() 0 64 11
A command_sale_checkauth() 0 9 2
A command_sale_init() 0 7 2
A command_sale_file() 0 11 3
C command_sale_import() 0 54 14
A command_sale_success() 0 11 3
A getVariantCharacteristicsXML() 0 15 3
B command_sale_query() 0 150 7

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 Exchange 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 Exchange, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
(defined('BASEPATH')) or exit('No direct script access allowed');
4
5
use CMSFactory\ModuleSettings;
6
use exchange\classes\Categories;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Categories.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
use exchange\classes\Prices;
8
use exchange\classes\Products;
9
use exchange\classes\Properties;
10
use exchange\classes\VariantCharacteristics;
11
use libraries\Backup;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Backup.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
12
13
/**
14
 * Exchange Class
15
 * exchange class handles 1c import/export
16
 * @package 1C-Exchange
17
 * @author ImageCMS <[email protected]>
18
 * @link  http://docs.imagecms.net/administrirovanie-imagecms-shop/moduli/integratsiia-s-1s
19
 * @link http://v8.1c.ru/edi/edi_stnd/131/
20
 */
21
class Exchange extends \MY_Controller
22
{
23
24
    /**
25
     * array which contains 1c settings
26
     * @var array
27
     */
28
    private $my_config = [];
29
30
    /**
31
     * default directory for saving files from 1c
32
     * @var string
33
     */
34
    private $tempDir;
35
36
    /**
37
     * contains default locale
38
     * @var string
39
     */
40
    private $locale;
41
42
    /**
43
     * @var array
44
     */
45
    private $allowed_image_extensions = [];
46
47
    /**
48
     * @var null|string
49
     */
50
    private $login;
51
52
    /**
53
     * @var null|string
54
     */
55
    private $password;
56
57
    /**
58
     * @var array
59
     */
60
    private $brand = [];
61
62
    /** Runtime variable */
63
    private $time = 0;
64
65
    /**
66
     *
67
     * @var VariantCharacteristics
68
     */
69
    private $variantCharacteristics;
70
71
    /**
72
     * Exchange constructor.
73
     */
74
    public function __construct() {
75
76
        parent::__construct();
77
78
        $this->time = time();
79
        set_time_limit(0);
80
81
        $lang = new MY_Lang();
82
        $lang->load('exchange');
83
84
        $this->load->helper('translit');
85
        $this->load->helper('file');
86
        $this->load->helper('exchange');
87
88
        $this->load->config('exchange');
89
        $this->load->config('exchange_debug');
90
91
        /**
92
         * define path to folder for saving files from 1c
93
         */
94
        $this->tempDir = $this->config->item('tempDir');
95
        if (!is_dir($this->tempDir)) {
96
            mkdir($this->tempDir);
97
        }
98
99
        $storageFilePath = $this->config->item('characteristicsStorageFilePath');
100
        $this->variantCharacteristics = new VariantCharacteristics($storageFilePath);
101
102
        $this->locale = MY_Controller::getCurrentLocale();    //getting current locale
103
        $this->my_config = $this->get1CSettings();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->get1CSettings() can also be of type null or string. However, the property $my_config is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
104
105
        if (!$this->my_config) {
106
            //default settings if module is not installed yet
107
            $this->my_config['zip'] = class_exists('ZipArchive') ? 'yes' : 'no';
108
109
            $this->my_config['filesize'] = $this->config->item('filesize');
110
            $this->my_config['validIP'] = $this->config->item('validIP');
111
            $this->my_config['password'] = $this->config->item('password');
112
            $this->my_config['usepassword'] = $this->config->item('usepassword');
113
            $this->my_config['userstatuses'] = $this->config->item('userstatuses');
114
            $this->my_config['autoresize'] = $this->config->item('autoresize');
115
            $this->my_config['debug'] = $this->config->item('debug');
116
            $this->my_config['email'] = $this->config->item('email');
117
        }
118
119
        $this->brand = array_key_exists('brand', $this->my_config) ? load_brand() : [];
120
121
        $this->allowed_image_extensions = [
122
                                           'jpg',
123
                                           'jpeg',
124
                                           'png',
125
                                           'gif',
126
                                          ];
127
128
        //define first get command parameter
129
        $method = 'command_';
130
131
        $this->login = isset($_SERVER['PHP_AUTH_USER']) ? trim($_SERVER['PHP_AUTH_USER']) : null;
132
        $this->password = isset($_SERVER['PHP_AUTH_PW']) ? trim($_SERVER['PHP_AUTH_PW']) : null;
133
134
        //saving get requests to log file
135
        if ($this->input->get()) {
136
            $string = '';
137
            foreach ((array) $this->input->get() as $key => $value) {
138
                $string .= date('c') . ' GET - ' . $key . ': ' . $value . "\n";
139
            }
140
            write_file($this->tempDir . 'log.txt', $string, 'ab');
141
        }
142
143
        //preparing method and mode name from $_GET variables
144
        if (array_key_exists('type', $this->input->get()) && array_key_exists('mode', $this->input->get())) {
145
            $method .= strtolower($this->input->get('type')) . '_' . strtolower($this->input->get('mode'));
146
        }
147
148
        //run method if exist
149
        if (method_exists($this, $method)) {
150
            $this->$method();
151
        }
152
    }
153
154
    public function __destruct() {
155
156
        $this->time = time() - $this->time;
157
        foreach ((array) $this->input->get() as $get) {
158
            write_file($this->tempDir . '/time.txt', date('Y-m-d h:i:s') . ': ' . $get . PHP_EOL, FOPEN_WRITE_CREATE);
159
        }
160
        write_file($this->tempDir . '/time.txt', date('Y-m-d h:i:s') . ': time - ' . $this->time . PHP_EOL, FOPEN_WRITE_CREATE);
161
        write_file($this->tempDir . '/time.txt', '-----------------------------------------' . PHP_EOL, FOPEN_WRITE_CREATE);
162
    }
163
164
    /**
165
     * Use this function to make backup before import starts
166
     */
167
    protected function makeDBBackup() {
168
169
        if (PHP_MAJOR_VERSION === 7) {
170
            return false;
171
        }
172
173
        if (is_really_writable(BACKUPFOLDER)) {
174
            Backup::create()->createBackup('zip', 'exchange');
175
        } else {
176
            $this->error_log(langf('Can not create a database snapshot, check the folder {0} on writing possibility', 'exchange', [BACKUPFOLDER]));
177
        }
178
    }
179
180
    /**
181
     * get 1c settings from modules table
182
     * @return array|null
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null|string? Also, consider making the array more specific, something like array<String>, or String[].

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.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
183
     */
184
    private function get1CSettings() {
185
186
        return ModuleSettings::ofModule('exchange')->get();
187
    }
188
189
    /**
190
     * module install function
191
     */
192 View Code Duplication
    public function _install() {
193
194
        $this->load->dbforge();
195
        ($this->dx_auth->is_admin()) or exit;
196
        $fields = [
197
                   'id'          => [
198
                                     'type'           => 'INT',
199
                                     'auto_increment' => true,
200
                                    ],
201
                   'external_id' => [
202
                                     'type'       => 'VARCHAR',
203
                                     'constraint' => '255',
204
                                     'null'       => true,
205
                                    ],
206
                   'property_id' => [
207
                                     'type'       => 'VARCHAR',
208
                                     'constraint' => '255',
209
                                     'null'       => true,
210
                                    ],
211
                   'value'       => [
212
                                     'type'       => 'VARCHAR',
213
                                     'constraint' => '20',
214
                                     'null'       => true,
215
                                    ],
216
                  ];
217
218
        $this->dbforge->add_field($fields);
219
        $this->dbforge->add_key('id', true);
220
        $this->dbforge->create_table('mod_exchange');
221
        ModuleSettings::ofModule('exchange')->set($this->my_config);
222
    }
223
224
    public function _deinstall() {
225
226
        $this->load->dbforge();
227
        ($this->dx_auth->is_admin()) or exit;
228
        $this->dbforge->drop_table('mod_exchange');
229
    }
230
231
    /**
232
     * Error loging methods
233
     * @param string $error
234
     * @param bool|string $send_email
235
     */
236
    public function error_log($error, $send_email = false) {
237
238
        $intIp = $_SERVER['REMOTE_ADDR'];
239
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
240
            if (isset($_SERVER['HTTP_X_REAL_IP'])) {
241
                $intIp = $_SERVER['HTTP_X_REAL_IP'];
242
            } else {
243
                $intIp = $_SERVER['HTTP_X_FORWARDED_FOR'];
244
            }
245
        }
246
247
        if ($this->my_config['debug']) {
248
            write_file($this->tempDir . 'error_log.txt', $intIp . ' - ' . date('c') . ' - ' . $error . PHP_EOL, 'ab');
249
        }
250
251
        if ($send_email and $this->my_config['email']) {
252
            $this->load->library('email');
253
254
            $this->email->from("noreplay@{$_SERVER['HTTP_HOST']}");
255
            $this->email->to($this->my_config['email']);
256
257
            $this->email->subject('1C exchange');
258
            $this->email->message($intIp . ' - ' . date('c') . ' - ' . $error . PHP_EOL);
259
260
            $this->email->send();
261
        }
262
    }
263
264
    public function __autoload() {
265
266
        return;
267
    }
268
269
    /**
270
     * checking password from $_GET['password'] if use_password option in settings is "On"
271
     */
272
    private function check_password() {
273
274
        if (($this->my_config['login'] == $this->login) && ($this->my_config['password'] == $this->password)) {
275
            $this->checkauth();
276
        } else {
277
            echo 'failure. wrong password';
278
            $this->error_log(lang('Wrong password', 'exchange'), true);
279
        }
280
    }
281
282
    /**
283
     * return to 1c session id and success status
284
     * to initialize import start
285
     */
286
    private function command_catalog_checkauth() {
287
288
        if ($this->my_config['usepassword'] == 'on') {
289
            $this->check_password();
290
        } else {
291
            $this->checkauth();
292
        }
293
        exit();
294
    }
295
296
    /**
297
     * preparing to import
298
     * writing session id to txt file in md5
299
     * deleting old import files
300
     */
301
    private function checkauth() {
302
303
        echo "success\n";
304
        echo session_name() . "\n";
305
        echo session_id() . "\n";
306
        $string = md5(session_id());
307
        write_file($this->tempDir . 'session.txt', $string, 'w');
308
    }
309
310
    /**
311
     * checking if current session id matches session id in txt files
312
     * @return boolean|null
313
     */
314
    private function check_perm() {
315
316
        if ($this->my_config['debug']) {
317
            return true;
318
        }
319
320
        $string = read_file($this->tempDir . 'session.txt');
321
        if (md5(session_id()) == $string) {
322
            return true;
323
        } else {
324
            $this->error_log(lang('Security Error!!!', 'exchange'), true);
325
            die(lang('Security Error!!!', 'exchange'));
326
        }
327
    }
328
329
    /**
330
     * returns exchange settings to 1c
331
     * @zip no
332
     * @file_limit in bytes
333
     */
334
    private function command_catalog_init() {
335
336
        if ($this->check_perm() === true) {
337
            echo 'zip=' . $this->my_config['zip'] . "\n";
338
            echo 'file_limit=' . $this->my_config['filesize'] . "\n";
339
        }
340
        exit();
341
    }
342
343
    /**
344
     * saves exchange files to tempDir
345
     * xml files will be saved to tempDir/
346
     * images wil be saved  to tempDir/images as jpg files
347
     */
348
    private function command_catalog_file() {
349
350
        if ($this->check_perm() === true) {
351
            $file_info = pathinfo($this->input->get('filename'));
352
            $file_extension = $file_info['extension'];
353
            $path = $file_info['dirname'];
354
355
            if ($file_extension != 'zip' && $file_extension != 'xml' && in_array($file_extension, $this->allowed_image_extensions)) {
356
                //saving images to cmlTemp/images folder
357
                @mkdir($this->tempDir . $path, 0777, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
358 View Code Duplication
                if (write_file($this->tempDir . $this->input->get('filename'), file_get_contents('php://input'), 'w+')) {
359
                    echo 'success';
360
                }
361 View Code Duplication
            } else {
362
                //saving xml files to cmlTemp
363
                if (write_file($this->tempDir . $this->input->get('filename'), file_get_contents('php://input'), 'w+')) {
364
                    echo 'success';
365
                }
366
            }
367
            //extracting filles
368
            if ($file_extension == 'zip' && class_exists('ZipArchive')) {
369
                $zip = new ZipArchive();
370
                $zip->open($this->tempDir . $this->input->get('filename'));
371
                if ($res > 0 && $res != true) {
372
                    switch ($res) {
0 ignored issues
show
Bug introduced by
The variable $res does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
373
                        case ZipArchive::ER_NOZIP:
374
                            $this->error_log('Not a zip archive.');
375
                            break;
376
                        case ZipArchive::ER_INCONS:
377
                            $this->error_log('Zip archive inconsistent.');
378
                            break;
379
                        case ZipArchive::ER_CRC:
380
                            $this->error_log('checksum failed');
381
                            break;
382
                        case ZipArchive::ER_EXISTS:
383
                            $this->error_log('File already exists.');
384
                            break;
385
                        case ZipArchive::ER_INVAL:
386
                            $this->error_log('Invalid argument.');
387
                            break;
388
                        case ZipArchive::ER_MEMORY:
389
                            $this->error_log('Malloc failure.');
390
                            break;
391
                        case ZipArchive::ER_NOENT:
392
                            $this->error_log('No such file.');
393
                            break;
394
                        case ZipArchive::ER_OPEN:
395
                            $this->error_log("Can't open file.");
396
                            break;
397
                        case ZipArchive::ER_READ:
398
                            $this->error_log('Read error.');
399
                            break;
400
                        case ZipArchive::ER_SEEK:
401
                            $this->error_log('Seek error.');
402
                            break;
403
                    }
404
                    echo 'failure';
405
                    exit();
406
                } else {
407
                    $zip->extractTo($this->tempDir);
408
                }
409
                $zip->close();
410
            }
411
        }
412
        exit();
413
    }
414
415
    /**
416
     * loading xml file to $this->xml variable
417
     * uses simple xml extension
418
     * @param string $file
419
     * @return null|SimpleXMLElement
420
     */
421
    private function _readXmlFile($file) {
422
423
        $path = $this->tempDir . $file;
424
        if (!file_exists($path) || !is_file($path)) {
425
            exit('Error opening file: ' . $path);
426
        }
427
        return simplexml_load_file($path);
428
    }
429
430
    public function command_catalog_import() {
431
432
        if ($this->check_perm() === true) {
433
            if ($this->my_config['backup']) {
434
                $this->makeDBBackup();
435
            }
436
            // getting xml
437
            $xml = $this->_readXmlFile($_GET['filename']);
438
439
            try {
440
                // IMPORT PROPERTIES
441
                if (isset($xml->Классификатор->Свойства)) {
442
                    $props = $xml->Классификатор->Свойства;
443
                    $propertiesData = isset($props->СвойствоНоменклатуры) ? $props->СвойствоНоменклатуры : $props->Свойство;
444
                    Properties::getInstance()
0 ignored issues
show
Bug introduced by
The method setBrandIdentif does only exist in exchange\classes\Properties, but not in exchange\classes\Products.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
445
                        ->setBrandIdentif($this->my_config['brand'])
446
                        ->import($propertiesData);
447
                }
448
449
                // IMPORT CATEGORIES
450
                if (isset($xml->Классификатор->Группы)) {
451
                    Categories::getInstance()->import($xml->Классификатор->Группы->Группа);
452
                }
453
454
                // IMPORT PRODUCTS
455
                if (isset($xml->Каталог->Товары)) {
456
                    if ($this->my_config['autoresize'] == 'on') {
457
                        $res = true;
458
                    } else {
459
                        $res = false;
460
                    }
461
462
                    Products::getInstance()
0 ignored issues
show
Bug introduced by
The method setTempDir does only exist in exchange\classes\Products, but not in exchange\classes\Properties.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
463
                        ->setTempDir($this->tempDir)
464
                        ->setResize($res)
465
                        ->import($xml->Каталог->Товары->Товар);
466
                }
467
468
                // IMPORT PRICES (IF THERE ARE ANY)
469
                Prices::getInstance()->setXml($xml);
470
                if (isset($xml->ПакетПредложений->Предложения)) {
471
                    Prices::getInstance()
472
                        ->import($xml->ПакетПредложений->Предложения->Предложение);
473
                }
474
475
                /**
476
                 * send notifications if changes products quantity
477
                 */
478
                Notificator::run();
479
            } catch (\Propel\Runtime\Exception\PropelException $e) {
480
                $this->error_log(lang('Import error', 'exchange') . ': ' . $e->getPrevious()->getMessage() . $e->getPrevious()->getFile() . $e->getPrevious()->getLine());
481
                echo $e->getPrevious()->getMessage() . $e->getPrevious()->getFile() . $e->getPrevious()->getLine();
482
                echo 'failure';
483
                exit;
484
            } catch (Exception $e) {
485
                $this->error_log(lang('Import error', 'exchange') . ': ' . $e->getMessage() . $e->getFile() . $e->getLine());
486
                echo $e->getMessage() . $e->getFile() . $e->getLine();
487
                echo 'failure';
488
                exit;
489
            }
490
            $this->cache->delete_all();
491
            exit('success');
492
        }
493
    }
494
495
    /**
496
     * checkauth for orders import
497
     */
498
    private function command_sale_checkauth() {
499
500
        if ($this->my_config['usepassword'] == 'on') {
501
            $this->check_password();
502
        } else {
503
            $this->checkauth();
504
        }
505
        exit();
506
    }
507
508
    /**
509
     * returns exchange settings to 1c
510
     * @zip no
511
     * @file_limit in bytes
512
     */
513
    private function command_sale_init() {
514
515
        if ($this->check_perm() === true) {
516
            $this->command_catalog_init();
517
        }
518
        exit();
519
    }
520
521
    /**
522
     * saving xml files with orders from 1c
523
     * and runs orders import
524
     */
525
    private function command_sale_file() {
526
527
        if ($this->check_perm() === true) {
528
            $this->load->helper('file');
529
            if (write_file($this->tempDir . $_GET['filename'], file_get_contents('php://input'), 'a+')) {
530
                echo 'success';
531
            }
532
            $this->command_sale_import();
533
        }
534
        exit();
535
    }
536
537
    /**
538
     * procced orders import
539
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be null|string?

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...
540
     */
541
    private function command_sale_import() {
542
543
        if ($this->check_perm() != true) {
544
            exit();
545
        }
546
547
        $this->xml = $this->_readXmlFile($_GET['filename']);
548
        if (!$this->xml) {
549
            return 'failure';
550
        }
551
        foreach ($this->xml->Документ as $order) {
552
            $orderId = (string) $order->Номер;
553
            $model = SOrdersQuery::create()->setComment(__METHOD__)->findOneById($orderId);
554
            if ($model) {
555
                $model->setExternalId((string) $order->Ид);
556
                $usr = SUserProfileQuery::create()->setComment(__METHOD__)->findById((string) $order->Контрагенты->Контрагент->Ид);
0 ignored issues
show
Unused Code introduced by
$usr 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...
557
                $model->setTotalPrice((string) $order->Сумма);
558
                $model->setDateUpdated(date('U'));
559
                foreach ($order->ЗначенияРеквизитов->ЗначениеРеквизита as $item) {
560
                    if ((string) $item->Наименование == 'ПометкаУдаления') {
561
                        if ($item->Значение == true) {
562
                            $model->setStatus(1);
563
                        }
564
                    }
565
                    if ((string) $item->Наименование . '' == 'Проведен') {
566
                        if ((string) $item->Значение == true) {
567
                            $model->setStatus(10);
568
                        }
569
                    }
570
571
                    if ((string) $item->Наименование . '' == 'Дата оплаты по 1С') {
572
                        if (strtotime((string) $item->Значение)) {
573
                            if ((string) $item->Значение . '' != 'Т') {
574
                                $model->setPaid(1);
575
                                echo 'success</br>';
576
                            }
577
                        }
578
                    }
579
                    /* if ($item->Наименование == 'Номер отгрузки по 1С') {
580
                      $model->setStatus(3);
581
                      } */
582
                }
583
                $model->save();
584
            } else {
585
                echo sprintf('Error - order with id [%s] not found', $orderId);
586
            }
587
        }
588
589
        if (!$this->my_config['debug']) {
590
            rename($this->tempDir . $_GET['filename'], $this->tempDir . 'success_' . $_GET['filename']);
591
        }
592
593
        exit('success');
594
    }
595
596
    /**
597
     * runs when orders from site succesfully uploaded to 1c server
598
     * and sets some status for imported orders "waiting" for example
599
     */
600
    private function command_sale_success() {
601
602
        if ($this->check_perm() === true) {
603
            $model = SOrdersQuery::create()->setComment(__METHOD__)->findByStatus($this->my_config['userstatuses']);
604
            foreach ($model as $order) {
605
                $order->SetStatus($this->my_config['userstatuses_after']);
606
                $order->save();
607
            }
608
        }
609
        exit();
610
    }
611
612
    /**
613
     *
614
     * @param string $variantName
615
     * @return string part of xml
616
     */
617
    private function getVariantCharacteristicsXML($variantName) {
618
619
        $characteristics = $this->variantCharacteristics->getVariantCharacteristics($variantName);
620
        if (count($characteristics) == 0) {
621
            return '';
622
        }
623
        $characteristicsXml = '';
624
        foreach ($characteristics as $name => $value) {
625
            $nameTag = create_tag('Наименование', $name);
626
            $valueTag = create_tag('Значение', $value);
627
            $characteristicTag = create_tag('ХарактеристикаТовара', $nameTag . $valueTag);
628
            $characteristicsXml .= $characteristicTag;
629
        }
630
        return create_tag('ХарактеристикиТовара', $characteristicsXml);
631
    }
632
633
    /**
634
     * creating xml document with orders to make possible for 1c to grab it
635
     */
636
    private function command_sale_query() {
637
638
        $xml_order = '';
639
640
        if ($this->check_perm() === true) {
641
            $this->load->helper('html');
642
            $model = SOrdersQuery::create()->setComment(__METHOD__)->findByStatus($this->my_config['userstatuses']);
643
            header('content-type: text/xml; charset=utf-8');
644
            $xml_order .= "<?xml version='1.0' encoding='UTF-8'?>" . "\n" .
645
                "<КоммерческаяИнформация ВерсияСхемы='2.03' ДатаФормирования='" . date('Y-m-d') . "'>" . "\n";
646
            foreach ($model as $order) {
647
                $xml_order .= "<Документ>\n" .
648
                    '<Ид>' . $order->Id . "</Ид>\n" .
649
                    '<Номер>' . $order->Id . "</Номер>\n" .
650
                    '<Дата>' . date('Y-m-d', $order->date_created) . "</Дата>\n" .
651
                    "<ХозОперация>Заказ товара</ХозОперация>\n" .
652
                    "<Роль>Продавец</Роль>\n" .
653
                    '<Валюта>' . \Currency\Currency::create()->main->getCode() . "</Валюта>\n" .
654
                    "<Курс>1</Курс>\n" .
655
                    '<Сумма>' . $order->totalprice . "</Сумма>\n" .
656
                    "<Контрагенты>\n" .
657
                    "<Контрагент>\n" .
658
                    '<Ид>' . $order->user_id . "</Ид>\n" .
659
                    '<Наименование>' . $order->UserFullName . "</Наименование>\n" .
660
                    '<Роль>Покупатель</Роль>' .
661
                    '<ПолноеНаименование>' . $order->UserFullName . "</ПолноеНаименование>\n" .
662
                    '<Фамилия>' . $order->UserFullName . '</Фамилия>' .
663
                    '<Имя>' . $order->UserFullName . '</Имя>' .
664
                    '<АдресРегистрации>' .
665
                    '<Представление>' . $order->user_deliver_to . '</Представление>' .
666
                    '<Комментарий></Комментарий>'
667
                    . '</АдресРегистрации>' .
668
                    '<Контакты>' .
669
                    '<Контакт>' .
670
                    '<Тип>ТелефонРабочий</Тип>' .
671
                    '<Значение>' . $order->user_phone . '</Значение>' .
672
                    '<Комментарий></Комментарий>' .
673
                    '</Контакт>' .
674
                    '<Контакт>' .
675
                    '<Тип>Почта</Тип>' .
676
                    '<Значение>' . $order->user_email . '</Значение>' .
677
                    '<Комментарий>Пользовательская почта</Комментарий>' .
678
                    '</Контакт>' .
679
                    '</Контакты>' .
680
                    "</Контрагент>\n" .
681
                    "</Контрагенты>\n" .
682
                    '<Время>' . date('G:i:s', $order->date_created) . "</Время>\n" .
683
                    '<Комментарий>' . $order->user_comment . "</Комментарий>\n" .
684
                    "<Товары>\n";
685
                $ordered_products = SOrderProductsQuery::create()
686
                    ->joinSProducts()
687
                    ->findByOrderId($order->Id);
688
                if ($order->deliverymethod != null) {
689
                    $xml_order .= "<Товар>\n" .
690
                        "<Ид>ORDER_DELIVERY</Ид>\n" .
691
                        "<Наименование>Доставка заказа</Наименование>\n" .
692
                        '<БазоваяЕдиница Код="2009" НаименованиеПолное="Штука" МеждународноеСокращение="PCE">шт</БазоваяЕдиница>' . "\n" .
693
                        '<ЦенаЗаЕдиницу>' . $order->deliveryprice . "</ЦенаЗаЕдиницу>\n" .
694
                        "<Количество>1</Количество>\n" .
695
                        '<Сумма>' . $order->deliveryprice . "</Сумма>\n" .
696
                        "<ЗначенияРеквизитов>\n" .
697
                        "<ЗначениеРеквизита>\n" .
698
                        "<Наименование>ВидНоменклатуры</Наименование>\n" .
699
                        "<Значение>Услуга</Значение>\n" .
700
                        "</ЗначениеРеквизита>\n" .
701
                        "<ЗначениеРеквизита>\n" .
702
                        "<Наименование>ТипНоменклатуры</Наименование>\n" .
703
                        "<Значение>Услуга</Значение>\n" .
704
                        "</ЗначениеРеквизита>\n" .
705
                        "</ЗначенияРеквизитов>\n" .
706
                        "</Товар>\n";
707
                }
708
                /* @var $product SOrderProducts */
709
                foreach ($ordered_products as $product) {
710
                    $category = get_product_category($product->product_id);
711
712
                    if ($this->config->item('salesQuery:exportCharacteristics') == true) {
713
                        $variantCharacteristicsXmlPart = $this->getVariantCharacteristicsXML($product->variant_name);
714
                    } else {
715
                        $variantCharacteristicsXmlPart = '';
716
                    }
717
718
                    $xml_order .= "<Товар>\n" .
719
                        '<Ид>' . $product->getSProducts()->getExternalId() . "</Ид>\n" .
720
                        "<ИдКаталога>{$category['external_id']}</ИдКаталога>\n" .
721
                        '<Наименование>' . ShopCore::encode($product->product_name) . "</Наименование>\n" .
722
                        '<БазоваяЕдиница Код="2009" НаименованиеПолное="Штука" МеждународноеСокращение="PCE">шт</БазоваяЕдиница>' . "\n" .
723
                        '<ЦенаЗаЕдиницу>' . $product->price . "</ЦенаЗаЕдиницу>\n" .
724
                        "<Количество>$product->quantity</Количество>\n" .
725
                        '<Сумма>' . ($product->price) * ($product->quantity) . "</Сумма>\n" .
726
                        $variantCharacteristicsXmlPart .
727
                        "<ЗначенияРеквизитов>\n" .
728
                        "<ЗначениеРеквизита>\n" .
729
                        "<Наименование>ВидНоменклатуры</Наименование>\n" .
730
                        "<Значение>Товар</Значение>\n" .
731
                        "</ЗначениеРеквизита>\n" .
732
                        "<ЗначениеРеквизита>\n" .
733
                        "<Наименование>ТипНоменклатуры</Наименование>\n" .
734
                        "<Значение>Товар</Значение>\n" .
735
                        "</ЗначениеРеквизита>\n" .
736
                        "</ЗначенияРеквизитов>\n" .
737
                        "</Товар>\n";
738
                }
739
                $xml_order .= "</Товары>\n";
740
                if ($order->paid == 0) {
741
                    $paid_status = 'false';
742
                } else {
743
                    $paid_status = 'true';
744
                }
745
                $status = SOrders::getStatusName('Id', $order->getStatus());
746
                $xml_order .= "<ЗначенияРеквизитов>\n" .
747
                    "<ЗначениеРеквизита>\n" .
748
                    "<Наименование>Метод оплаты</Наименование>\n" .
749
                    '<Значение>' . $order->getPaymentMethodName() . "</Значение>\n" .
750
                    "</ЗначениеРеквизита>\n" .
751
                    "<ЗначениеРеквизита>\n" .
752
                    "<Наименование>Заказ оплачен</Наименование>\n" .
753
                    '<Значение>' . $paid_status . "</Значение>\n" .
754
                    "</ЗначениеРеквизита>\n" .
755
                    "<ЗначениеРеквизита>\n" .
756
                    "<Наименование>Доставка разрешена</Наименование>\n" .
757
                    "<Значение>true</Значение>\n" .
758
                    "</ЗначениеРеквизита>\n" .
759
                    "<ЗначениеРеквизита>\n" .
760
                    "<Наименование>Отменен</Наименование>\n" .
761
                    "<Значение>false</Значение>\n" .
762
                    "</ЗначениеРеквизита>\n" .
763
                    "<ЗначениеРеквизита>\n" .
764
                    "<Наименование>Финальный статус</Наименование>\n" .
765
                    "<Значение>false</Значение>\n" .
766
                    "</ЗначениеРеквизита>\n" .
767
                    "<ЗначениеРеквизита>\n" .
768
                    "<Наименование>Статус заказа</Наименование>\n" .
769
                    '<Значение>' . $status . "</Значение>\n" .
770
                    "</ЗначениеРеквизита>\n" .
771
                    "<ЗначениеРеквизита>\n" .
772
                    "<Наименование>Дата изменения статуса</Наименование>\n" .
773
                    '<Значение>' . date('Y-m-d H:i:s', $order->date_updated) . "</Значение>\n" .
774
                    "</ЗначениеРеквизита>\n" .
775
                    "</ЗначенияРеквизитов>\n";
776
                $xml_order .= "</Документ>\n";
777
            }
778
            $xml_order .= '</КоммерческаяИнформация>';
779
780
            $xml_order = iconv('UTF-8', 'Windows-1251', $xml_order);
781
782
            echo $xml_order;
783
        }
784
        exit();
785
    }
786
787
}