diff --git a/.gitignore b/.gitignore index e6ebec2..5e911ac 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ /debian/multiflexi-discomp2abraflexi/ /debian/multiflexi-discomp2abraflexi.debhelper.log /debian/multiflexi-discomp2abraflexi.substvars +/.build/ diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..52a09c3 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Ergebnis\PhpCsFixer\Config\Factory; +use Ergebnis\PhpCsFixer\Config\Rules; +use Ergebnis\PhpCsFixer\Config\RuleSet\Php74; + +$header = <<<'HEADER' +This file is part of the discomp2abraflexi package + +https://github.com/Spoje-NET/discomp2abraflexi + +(c) SpojeNet s.r.o. + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. +HEADER; + +$ruleSet = Php74::create()->withHeader($header)->withRules(Rules::fromArray([ + 'blank_line_before_statement' => [ + 'statements' => [ + 'break', + 'continue', + 'declare', + 'default', + 'do', + 'exit', + 'for', + 'foreach', + 'goto', + 'if', + 'include', + 'include_once', + 'require', + 'require_once', + 'return', + 'switch', + 'throw', + 'try', + 'while', + ], + ], + 'concat_space' => [ + 'spacing' => 'none', + ], + 'date_time_immutable' => false, + 'error_suppression' => false, + 'final_class' => false, + 'mb_str_functions' => false, + 'native_function_invocation' => [ + 'exclude' => [ + 'sprintf', + ], + 'include' => [ + '@compiler_optimized', + ], + 'scope' => 'all', + 'strict' => false, + ], + 'php_unit_internal_class' => false, + 'php_unit_test_annotation' => [ + 'style' => 'prefix', + ], + 'php_unit_test_class_requires_covers' => false, + 'return_to_yield_from' => false, + 'phpdoc_array_type' => false, + 'phpdoc_list_type' => false, + 'attribute_empty_parentheses' => false, + 'final_public_method_for_abstract_class' => false, + 'class_attributes_separation' => [ + 'elements' => [ + 'const' => 'only_if_meta', + 'property' => 'only_if_meta', + 'trait_import' => 'none', + 'case' => 'none', + ], + ], + 'yoda_style' => false, + 'php_unit_test_case_static_method_calls' => false, +])); + +$config = Factory::fromRuleSet($ruleSet); + +$config->getFinder() + ->append([ + __DIR__.'/.php-cs-fixer.dist.php', + ]) + ->in('src') + ->in('tests'); + +$config->setCacheFile(__DIR__.'/.build/php-cs-fixer/.php-cs-fixer.cache'); + +return $config; diff --git a/Makefile b/Makefile index 6015d7c..780d651 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,30 @@ +# vim: set tabstop=8 softtabstop=8 noexpandtab: +.PHONY: help +help: ## Displays this list of targets with descriptions + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: static-code-analysis +static-code-analysis: vendor ## Runs a static code analysis with phpstan/phpstan + vendor/bin/phpstan analyse --configuration=phpstan-default.neon.dist --memory-limit=-1 + +.PHONY: static-code-analysis-baseline +static-code-analysis-baseline: check-symfony vendor ## Generates a baseline for static code analysis with phpstan/phpstan + vendor/bin/phpstan analyze --configuration=phpstan-default.neon.dist --generate-baseline=phpstan-default-baseline.neon --memory-limit=-1 + +.PHONY: tests +tests: vendor + vendor/bin/phpunit tests + +.PHONY: vendor +vendor: composer.json composer.lock ## Installs composer dependencies + composer install + +.PHONY: cs +cs: ## Update Coding Standards + vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --diff --verbose + + + buildimage: docker build -t vitexsoftware/discomp2abraflexi:latest . diff --git a/composer.json b/composer.json index d2e11b1..94e3bf7 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,11 @@ "spojenet/flexibee": "dev-main" }, "require-dev": { - "phpunit/phpunit": "11.0.x-dev" + "phpunit/phpunit": "*", + "phpstan/phpstan": "*", + "friendsofphp/php-cs-fixer": "^3.61", + "ergebnis/composer-normalize": "^2.43", + "ergebnis/php-cs-fixer-config": "^6.34" }, "license": "MIT", "autoload": { @@ -20,5 +24,10 @@ "email": "info@vitexsoftware.cz" } ], - "minimum-stability": "dev" + "minimum-stability": "dev", + "config": { + "allow-plugins": { + "ergebnis/composer-normalize": true + } + } } diff --git a/discomp2abraflexi.svg b/discomp2abraflexi.svg index 8fe7f81..2918326 100644 --- a/discomp2abraflexi.svg +++ b/discomp2abraflexi.svg @@ -20,21 +20,34 @@ id="metadata8">image/svg+xml + id="g2800" + transform="translate(1.1982888e-7,2.9410087)"> diff --git a/phpstan-default-baseline.neon b/phpstan-default-baseline.neon new file mode 100644 index 0000000..364905f --- /dev/null +++ b/phpstan-default-baseline.neon @@ -0,0 +1,2 @@ +parameters: + ignoreErrors: diff --git a/phpstan-default.neon.dist b/phpstan-default.neon.dist new file mode 100644 index 0000000..ead7041 --- /dev/null +++ b/phpstan-default.neon.dist @@ -0,0 +1,9 @@ +includes: + - phpstan-default-baseline.neon + +parameters: + inferPrivatePropertyTypeFromConstructor: true + level: 6 + paths: + - src + - tests diff --git a/social-preview.png b/social-preview.png new file mode 100644 index 0000000..63fe711 Binary files /dev/null and b/social-preview.png differ diff --git a/social-preview.svg b/social-preview.svg index c0d89a0..394c9cf 100644 --- a/social-preview.svg +++ b/social-preview.svg @@ -29,44 +29,26 @@ showgrid="false" showguides="true" inkscape:zoom="0.2102413" - inkscape:cx="2456.7009" - inkscape:cy="1705.1835" + inkscape:cx="2432.9187" + inkscape:cy="1702.8053" inkscape:window-width="1920" - inkscape:window-height="1130" + inkscape:window-height="1125" inkscape:window-x="1920" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="layer1" /> - - - - + x="-0.012506707" + width="1.0250134"> + + + + + + + + + + + + + + + + + + + Import the Discomp price list into Abra Flexi + id="g2800" + transform="matrix(6.3983944,0,0,-6.3983944,8.3148954,583.13557)"> - - - - + id="g742" + transform="matrix(0.12358533,0,0,0.12358533,13.362157,1.0237774)"> + + + + + + + + + + + + + + + + + + + + + + transform="matrix(0.28374388,0,0,0.28374388,50.243663,30.482836)"> - - - - - Import the Discomp price list into Abra Flexi diff --git a/src/Discomp/ApiClient.php b/src/Discomp/ApiClient.php index 5b3e75f..7045f43 100644 --- a/src/Discomp/ApiClient.php +++ b/src/Discomp/ApiClient.php @@ -3,16 +3,20 @@ declare(strict_types=1); /** + * This file is part of the discomp2abraflexi package * + * https://github.com/Spoje-NET/discomp2abraflexi * - * @author Vítězslav Dvořák - * @copyright 2023 Vitex Software + * (c) SpojeNet s.r.o. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ namespace SpojeNet\Discomp; /** - * Description of DiscordWs + * Description of DiscordWs. * * @see https://www.discomp.cz/i6ws/ReadMe.txt * @@ -23,163 +27,167 @@ class ApiClient extends \Ease\Molecule use \Ease\Logger\Logging; /** - * Discomp URI - * @var string + * Discomp URI. */ - public $baseEndpoint = 'https://WWW.discomp.CZ/i6ws/default.asmx'; + public string $baseEndpoint = 'https://WWW.discomp.CZ/i6ws/default.asmx'; /** - * CURL resource handle - * @var resource|\CurlHandle|null + * Throw Exception on error ? */ - private $curl; + public bool $throwException = true; /** - * CURL response timeout - * @var int + * CURL resource handle. + * + * @var null|\CurlHandle|resource */ - private $timeout = 0; + private $curl; /** - * Last CURL response info - * @var array + * CURL response timeout. */ - private $curlInfo = []; + private int $timeout = 0; /** - * Last CURL response error - * @var string + * Last CURL response info. */ - private $lastCurlError; + private array $curlInfo = []; /** - * Throw Exception on error ? - * @var boolean + * Last CURL response error. */ - public $throwException = true; + private string $lastCurlError; /** - * Discomp Username - * @var string + * Discomp Username. */ - private $apiUsername; + private string $apiUsername; /** - * Discomp User password - * @var string + * Discomp User password. */ - private $apiPassword; + private string $apiPassword; /** - * May be huge response - * @var string|boolean + * May be huge response. + * + * @var bool|string */ private $lastCurlResponse; /** - * HTTP Response code of latst request - * @var int + * HTTP Response code of latst request. */ - private $lastResponseCode; + private int $lastResponseCode; /** - * Debug mode - * @var boolean - */ - public $debug = false; - - /** - * Discomp Data obtainer + * Discomp Data obtainer. * * @param string $username - leave empty to use Environment or constant DISCOMP_USERNAME * @param string $password - leave empty to use Environment or constant DISCOMP_PASSWORD */ public function __construct($username = '', $password = '') { - $this->apiUsername = strlen($username) ? $username : \Ease\Shared::cfg('DISCOMP_USERNAME'); - $this->apiPassword = strlen($password) ? $password : \Ease\Shared::cfg('DISCOMP_PASSWORD'); + $this->apiUsername = \strlen($username) ? $username : \Ease\Shared::cfg('DISCOMP_USERNAME'); + $this->apiPassword = \strlen($password) ? $password : \Ease\Shared::cfg('DISCOMP_PASSWORD'); $this->debug = \Ease\Shared::cfg('DISCOMP_API_DEBUG', false); $this->curlInit(); $this->setObjectName(); } /** - * Initialize CURL + * Close Curl Handle before serizaliation. + */ + public function __destruct() + { + $this->disconnect(); + } + + /** + * Initialize CURL. * - * @return mixed|boolean Online Status + * @return bool|mixed Online Status */ public function curlInit() { $this->curl = \curl_init(); // create curl resource - \curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); // return content as a string from curl_exec - \curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); // follow redirects - \curl_setopt($this->curl, CURLOPT_HTTPAUTH, true); // HTTP authentication - \curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, true); - \curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false); - \curl_setopt($this->curl, CURLOPT_VERBOSE, ($this->debug === true)); // For debugging + \curl_setopt($this->curl, \CURLOPT_RETURNTRANSFER, true); // return content as a string from curl_exec + \curl_setopt($this->curl, \CURLOPT_FOLLOWLOCATION, true); // follow redirects + \curl_setopt($this->curl, \CURLOPT_HTTPAUTH, true); // HTTP authentication + \curl_setopt($this->curl, \CURLOPT_SSL_VERIFYPEER, true); + \curl_setopt($this->curl, \CURLOPT_SSL_VERIFYHOST, false); + \curl_setopt($this->curl, \CURLOPT_VERBOSE, $this->debug === true); // For debugging + if ($this->timeout) { - \curl_setopt($this->curl, CURLOPT_HTTPHEADER, [ + \curl_setopt($this->curl, \CURLOPT_HTTPHEADER, [ 'Connection: Keep-Alive', - 'Keep-Alive: ' . $this->timeout + 'Keep-Alive: '.$this->timeout, ]); - \curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeout); + \curl_setopt($this->curl, \CURLOPT_TIMEOUT, $this->timeout); } + if (empty($this->authSessionId)) { \curl_setopt( $this->curl, - CURLOPT_USERPWD, - $this->apiUsername . ':' . $this->apiPassword + \CURLOPT_USERPWD, + $this->apiUsername.':'.$this->apiPassword, ); // set username and password } + \curl_setopt( $this->curl, - CURLOPT_USERAGENT, - 'DiscompTakeout v' . \Ease\Shared::appVersion() . ' https://github.com/Spoje-NET/Discomp2AbraFlexi' + \CURLOPT_USERAGENT, + 'DiscompTakeout v'.\Ease\Shared::appVersion().' https://github.com/Spoje-NET/Discomp2AbraFlexi', ); + return $this->curl; } /** - * Execute HTTP request + * Execute HTTP request. * - * @param string $url URL of request - * @param string $method HTTP Method GET|POST|PUT|OPTIONS|DELETE + * @param string $url URL of request + * @param string $method HTTP Method GET|POST|PUT|OPTIONS|DELETE + * @param mixed $postParams * * @return int HTTP Response CODE */ public function doCurlRequest($url, $method = 'GET', $postParams = []) { - curl_setopt($this->curl, CURLOPT_URL, $url); + curl_setopt($this->curl, \CURLOPT_URL, $url); - curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, strtoupper($method)); + curl_setopt($this->curl, \CURLOPT_CUSTOMREQUEST, strtoupper($method)); $this->lastCurlResponse = curl_exec($this->curl); $this->curlInfo = curl_getinfo($this->curl); $this->curlInfo['when'] = microtime(); $this->lastResponseCode = $this->curlInfo['http_code']; $this->lastCurlError = curl_error($this->curl); - if (strlen($this->lastCurlError)) { + + if (\strlen($this->lastCurlError)) { $msg = sprintf('Curl Error (HTTP %d): %s', $this->lastResponseCode, $this->lastCurlError); $this->addStatusMessage($msg, 'error'); + if ($this->throwException) { throw new \Ease\Exception($msg, $this); } } + return $this->lastResponseCode; } /** - * Mime Type of last server response + * Mime Type of last server response. * * @return string */ public function getResponseMime() { - return array_key_exists('content_type', $this->curlInfo) ? $this->curlInfo['content_type'] : 'text/plain'; + return \array_key_exists('content_type', $this->curlInfo) ? $this->curlInfo['content_type'] : 'text/plain'; } /** - * Curl Error getter + * Curl Error getter. * * @return string */ @@ -189,7 +197,7 @@ public function getErrors() } /** - * Response code of last HTTP operation + * Response code of last HTTP operation. * * @return int */ @@ -199,7 +207,7 @@ public function getLastResponseCode() } /** - * Latest Data obtained + * Latest Data obtained. * * @return string */ @@ -209,37 +217,33 @@ public function getLastCurlResponseBody() } /** - * Convert XML to array + * Convert XML to array. + * + * @param mixed $xmlObject + * @param mixed $out */ public static function xml2array($xmlObject, $out = []) { foreach ((array) $xmlObject as $index => $node) { - $out[$index] = (is_object($node) || is_array($node)) ? self::xml2array($node) : $node; + $out[$index] = (\is_object($node) || \is_array($node)) ? self::xml2array($node) : $node; } + return $out; } /** * Discomp server disconnect. */ - public function disconnect() + public function disconnect(): void { - if (is_resource($this->curl)) { + if (\is_resource($this->curl)) { curl_close($this->curl); } - $this->curl = null; - } - /** - * Close Curl Handle before serizaliation - */ - public function __destruct() - { - $this->disconnect(); + $this->curl = null; } /** - * * @see https://www.discomp.cz/i6ws/ResultTypeInfo.ashx * * @param string $resultType @@ -248,35 +252,34 @@ public function __destruct() */ public function getResult($resultType) { - $this->doCurlRequest($this->baseEndpoint . '/GetResult?resultType=' . $resultType); - if ($this->lastCurlResponse[0] != '<') { + $this->doCurlRequest($this->baseEndpoint.'/GetResult?resultType='.$resultType); + + if ($this->lastCurlResponse[0] !== '<') { throw new \Exception($this->lastCurlResponse); } + return current(self::xml2array(new \SimpleXMLElement(html_entity_decode($this->lastCurlResponse)))); } /** - * - * @param string $resultType - * @param \DateTime $from - * @param \DateTime $to - * * @return array */ public function getResultByFromTo(string $resultType, \DateTime $from, \DateTime $to) { - $this->doCurlRequest($this->baseEndpoint . - '/GetResultByFromTo?resultType=' . $resultType . - '&from=' . $from->format('Y-m-d\T00:00:00') . - '&to=' . $to->format('Y-m-d\T00:00:00')); - if ($this->lastCurlResponse[0] != '<') { - throw new \Exception($this->curlInfo['url'] . "\n" . html_entity_decode($this->lastCurlResponse)); + $this->doCurlRequest($this->baseEndpoint. + '/GetResultByFromTo?resultType='.$resultType. + '&from='.$from->format('Y-m-d\T00:00:00'). + '&to='.$to->format('Y-m-d\T00:00:00')); + + if ($this->lastCurlResponse[0] !== '<') { + throw new \Exception($this->curlInfo['url']."\n".html_entity_decode($this->lastCurlResponse)); } + return current(self::xml2array(new \SimpleXMLElement($this->lastCurlResponse))); } /** - * Everything about product + * Everything about product. * * @param string $stoItemBase * @param string $code @@ -285,8 +288,9 @@ public function getResultByFromTo(string $resultType, \DateTime $from, \DateTime */ public function getResultByCode($stoItemBase, $code) { - $this->doCurlRequest($this->baseEndpoint . '/GetResultByCode?resultType=' . $stoItemBase . '&code=' . $code); - if ($this->lastCurlResponse[0] != '<') { + $this->doCurlRequest($this->baseEndpoint.'/GetResultByCode?resultType='.$stoItemBase.'&code='.$code); + + if ($this->lastCurlResponse[0] !== '<') { throw new \Exception(html_entity_decode($this->lastCurlResponse)); } @@ -313,11 +317,10 @@ public function getResultByCode($stoItemBase, $code) */ - return json_decode(json_encode(is_bool($this->lastCurlResponse) ? [] : new \SimpleXMLElement($this->lastCurlResponse)), true); + return json_decode(json_encode(\is_bool($this->lastCurlResponse) ? [] : new \SimpleXMLElement($this->lastCurlResponse)), true); } /** - * * @param string $code * * @return array @@ -326,16 +329,17 @@ public function getItemByCode($code) { return [ 'StoItemBase' => $this->getResultByCode('StoItemBase', $code), -// 'StoItemEAN' => $this->getResultByCode('StoItemEAN', $code), -// 'StoItemPriceEU' => $this->getResultByCode('StoItemPriceEU', $code), -// 'StoItemPriceOrd' => $this->getResultByCode('StoItemPriceOrd', $code), -// 'StoItemPriceOrdCur' => $this->getResultByCode('StoItemPriceOrdCur', $code) + // 'StoItemEAN' => $this->getResultByCode('StoItemEAN', $code), + // 'StoItemPriceEU' => $this->getResultByCode('StoItemPriceEU', $code), + // 'StoItemPriceOrd' => $this->getResultByCode('StoItemPriceOrd', $code), + // 'StoItemPriceOrdCur' => $this->getResultByCode('StoItemPriceOrdCur', $code) ]; } public function getImage($baseImageUrl) { $this->doCurlRequest($baseImageUrl); + return $this->lastCurlResponse; } } diff --git a/src/Discomp/Importer.php b/src/Discomp/Importer.php index 54153a8..69fd26d 100644 --- a/src/Discomp/Importer.php +++ b/src/Discomp/Importer.php @@ -3,160 +3,90 @@ declare(strict_types=1); /** - * Discomp Data Importer + * This file is part of the discomp2abraflexi package * - * @author Vítězslav Dvořák - * @copyright 2023 Vitex Software + * https://github.com/Spoje-NET/discomp2abraflexi + * + * (c) SpojeNet s.r.o. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ namespace SpojeNet\Discomp; -use DateTime; -use Exception; use AbraFlexi\RO; use AbraFlexi\RW; /** - * Description of Importer + * Description of Importer. * * @author vitex */ class Importer extends \Ease\Sand { use \Ease\Logger\Logging; + public \DateTime $since; + public \DateTime $until; + public ApiClient $discpomper; /** - * - * @var DateTime - */ - public $since; - - /** - * - * @var DateTime - */ - public $until; - - /** - * - * @var ApiClient - */ - public $discpomper; - - /** - * - * @var int - */ - private $new = 0; - - /** - * - * @var int - */ - private $updated = 0; - - /** - * - * @var int - */ - private $skipped = 0; - - /** - * - * @var int - */ - private $errors = 0; - - /** - * Discomp Tree Root - * @var string - */ - static $ROOT = 'STR_CEN'; - - /** - * - * @var array - */ - private $levels = []; - - /** - * - * @var \AbraFlexi\StromCenik + * Discomp Tree Root. */ - private $category; + public static string $ROOT = 'STR_CEN'; + private int $new = 0; + private int $updated = 0; + private int $skipped = 0; + private int $errors = 0; + private array $levels = []; + private ?\AbraFlexi\StromCenik $category; /** - * * @var array CategoryTree cache */ - private $treeCache = []; + private array $treeCache = []; + private ?RW $atributType; + private ?RW $atribut; /** - * - * @var RW + * Supplier code for \AbraFlexi\Adresar. */ - private $atributType; + private ?string $suplier; /** - * - * @var RW + * Pricelist Engine. */ - private $atribut; + private ?\AbraFlexi\Cenik $sokoban; + private ApiClient $discomper; + private ?\AbraFlexi\Dodavatel $pricer; + private int $images = 0; /** - * Supplier code for \AbraFlexi\Adresar - * @var string - */ - private $suplier; - - /** - * Pricelist Engine - * @var \AbraFlexi\Cenik - */ - private $sokoban; - - /** - * - * @var ApiClient - */ - private $discomper; - - /** - * - * @var \AbraFlexi\Dodavatel - */ - private $pricer; - - /** - * - * @var int - */ - private $images = 0; - - /** - * Discomp Items Importer + * Discomp Items Importer. */ public function __construct() { $this->setObjectName(); $this->discomper = new ApiClient(); $this->abraFlexiInit(); + if (\Ease\Shared::cfg('APP_DEBUG', false)) { $this->logBanner(); } + $this->addStatusMessage(_('Supplier Exists'), $this->ensureSupplierExists() ? 'success' : 'error'); $this->addStatusMessage(_('Category Root Exists'), $this->ensureCategoryRootExists() ? 'success' : 'error'); } /** - * Connect to AbraFlexi + * Connect to AbraFlexi. */ - public function abraFlexiInit() + public function abraFlexiInit(): void { $this->sokoban = new \AbraFlexi\Cenik(null, ['ignore404' => true]); $this->sokoban->setObjectName('Pricelist'); $this->suplier = \AbraFlexi\RO::code(\Ease\Shared::cfg('ABRAFLEXI_DISCOMP_CODE', 'DISCOMP')); - $this->pricer = new \AbraFlexi\Dodavatel(['firma' => $this->suplier, 'poznam' => 'Import: ' . \Ease\Shared::AppName() . ' ' . \Ease\Shared::AppVersion() . "\nhttps://github.com/Spoje-NET/discomp2abraflexi"], ['evidence' => 'dodavatel', 'autoload' => false]); + $this->pricer = new \AbraFlexi\Dodavatel(['firma' => $this->suplier, 'poznam' => 'Import: '.\Ease\Shared::AppName().' '.\Ease\Shared::AppVersion()."\nhttps://github.com/Spoje-NET/discomp2abraflexi"], ['evidence' => 'dodavatel', 'autoload' => false]); $this->category = new \AbraFlexi\StromCenik(); $this->atribut = new RW(null, ['evidence' => 'atribut']); $this->atributType = new RW(null, ['evidence' => 'typ-atributu', 'ignore404' => true]); @@ -164,20 +94,20 @@ public function abraFlexiInit() } /** - * Try to free resources + * Try to free resources. */ - public function abraFlexiDisconnect() + public function abraFlexiDisconnect(): void { - unset($this->sokoban); - unset($this->suplier); - unset($this->pricer); - unset($this->category); - unset($this->atribut); - unset($this->atributType); + $this->sokoban = null; + $this->suplier = null; + $this->pricer = null; + $this->category = null; + $this->atribut = null; + $this->atributType = null; } /** - * Ensure the supplier is present in AddressBook + * Ensure the supplier is present in AddressBook. * * @return bool */ @@ -185,10 +115,11 @@ public function ensureSupplierExists() { $suplierOk = true; $checker = new \AbraFlexi\Adresar($this->suplier, ['ignore404' => true]); - if ($checker->lastResponseCode == 404) { - $this->addStatusMessage($this->suplier . ' is missing.', 'warning'); + + if ($checker->lastResponseCode === 404) { + $this->addStatusMessage($this->suplier.' is missing.', 'warning'); $checker->insertToAbraFlexi([ - 'kod' => \AbraFlexi\RO::uncode($this->suplier), + 'kod' => \AbraFlexi\Functions::uncode($this->suplier), 'nazev' => 'Discomp s.r.o.', 'typVztahuK' => 'typVztahu.dodavatel', 'platceDph' => true, @@ -199,109 +130,124 @@ public function ensureSupplierExists() 'mesto' => 'Plzeň - Lobzy', 'www' => 'https://www.discomp.cz/', 'ic' => '25236792', - 'email' => 'info@discomp.cz' + 'email' => 'info@discomp.cz', ]); - $suplierOk = ($checker->lastResponseCode == 201); - $this->addStatusMessage('creating ' . $this->suplier, $suplierOk ? 'success' : 'error'); + $suplierOk = ($checker->lastResponseCode === 201); + $this->addStatusMessage('creating '.$this->suplier, $suplierOk ? 'success' : 'error'); } + return $suplierOk; } /** - * * @return array */ public function getFreshItems() { $this->scopeToInterval(\Ease\Shared::cfg('DISCOMP_SCOPE', 'yesterday')); $freshItems = $this->discomper->getResultByFromTo('StoItemShop_El', $this->since, $this->until); - $this->addStatusMessage('Import Initiated. From: ' . $this->since->format('Y-m-d') . ' To: ' . $this->until->format('Y-m-d') . ' ' . sprintf(_('Active Items found: %d'), count($freshItems))); + $this->addStatusMessage('Import Initiated. From: '.$this->since->format('Y-m-d').' To: '.$this->until->format('Y-m-d').' '.sprintf(_('Active Items found: %d'), \count($freshItems))); + return $freshItems; } - public function freshItems() + public function freshItems(): void { $errors = 0; $freshItems = $this->getFreshItems(); + foreach ($freshItems as $pos => $activeItemData) { $this->abraFlexiDisconnect(); $this->abraFlexiInit(); $discompItemCode = $activeItemData['CODE']; - $this->sokoban->setObjectName('(' . $pos . '/' . count($freshItems) . ') StoreItem:' . $discompItemCode); + $this->sokoban->setObjectName('('.$pos.'/'.\count($freshItems).') StoreItem:'.$discompItemCode); + + if (\is_array($activeItemData['PART_NUMBER'])) { + $this->sokoban->addStatusMessage('WTF? '.json_encode($activeItemData['PART_NUMBER']), 'debug'); - if (is_array($activeItemData['PART_NUMBER'])) { - $this->sokoban->addStatusMessage('WTF? ' . json_encode($activeItemData['PART_NUMBER']), 'debug'); continue; } + $this->sokoban->setDataValue('kod', $activeItemData['PART_NUMBER']); $recordCheck = $this->sokoban->getColumnsFromAbraFlexi(['dodavatel', 'nazev', 'popis', 'pocetPriloh'], ['id' => \AbraFlexi\RO::code($activeItemData['PART_NUMBER'])]); $this->sokoban->setDataValue('dodavatel', $this->suplier); - if ($activeItemData['ITEM_TYPE'] != 'product') { - $this->sokoban->addStatusMessage('NO Product' . json_encode($activeItemData['PART_NUMBER']), 'debug'); + + if ($activeItemData['ITEM_TYPE'] !== 'product') { + $this->sokoban->addStatusMessage('NO Product'.json_encode($activeItemData['PART_NUMBER']), 'debug'); } - $this->sokoban->setDataValue('typZasobyK', \Ease\Shared::cfg('DISCOMP_TYP_ZASOBY', 'typZasoby.material')); //TODO: ??? - $this->sokoban->setDataValue('skladove', true); //TODO: ??? - //$this->sokoban->setDataValue('eanKod', $activeItemData['EAN']); - $this->sokoban->setDataValue('nakupCena', ceil(floatval($activeItemData['PURCHASE_PRICE']))); + $this->sokoban->setDataValue('typZasobyK', \Ease\Shared::cfg('DISCOMP_TYP_ZASOBY', 'typZasoby.material')); // TODO: ??? + $this->sokoban->setDataValue('skladove', true); // TODO: ??? + // $this->sokoban->setDataValue('eanKod', $activeItemData['EAN']); - if (array_key_exists('STANDARD_PRICE', $activeItemData)) { + $this->sokoban->setDataValue('nakupCena', ceil((float) $activeItemData['PURCHASE_PRICE'])); + + if (\array_key_exists('STANDARD_PRICE', $activeItemData)) { $this->sokoban->setDataValue('cenaBezna', $activeItemData['STANDARD_PRICE']); } $this->sokoban->setDataValue('nazev', $activeItemData['NAME']); - if (array_key_exists('WARRANTY', $activeItemData)) { + if (\array_key_exists('WARRANTY', $activeItemData)) { $this->sokoban->setDataValue('zaruka', $activeItemData['WARRANTY']); } + $this->sokoban->setDataValue('mjZarukyK', 'mjZaruky.mesic'); - if (array_key_exists('WEIGHT', $activeItemData)) { + + if (\array_key_exists('WEIGHT', $activeItemData)) { $this->sokoban->setDataValue('hmotMj', $activeItemData['WEIGHT']); } - if (array_key_exists('SHORT_DESCRIPTION', $activeItemData)) { + + if (\array_key_exists('SHORT_DESCRIPTION', $activeItemData)) { $this->sokoban->setDataValue('popis', $activeItemData['SHORT_DESCRIPTION']); } $this->sokoban->setDataValue('mj1', \AbraFlexi\RO::code($activeItemData['UNIT'])); - if (array_key_exists('MANUFACTURER', $activeItemData)) { + if (\array_key_exists('MANUFACTURER', $activeItemData)) { $this->sokoban->setDataValue('vyrobce', $this->findManufacturerCode($activeItemData['MANUFACTURER'])); } if (empty($recordCheck)) { - $this->discomper->addStatusMessage($activeItemData['CODE'] . ': ' . $activeItemData['NAME'] . ' new item', $this->sokoban->insertToAbraFlexi() ? 'success' : 'error'); - if (array_key_exists('IMAGES', $activeItemData) && array_key_exists('IMAGE', $activeItemData['IMAGES'])) { - if (is_array($activeItemData['IMAGES']['IMAGE'])) { + $this->discomper->addStatusMessage($activeItemData['CODE'].': '.$activeItemData['NAME'].' new item', $this->sokoban->insertToAbraFlexi() ? 'success' : 'error'); + + if (\array_key_exists('IMAGES', $activeItemData) && \array_key_exists('IMAGE', $activeItemData['IMAGES'])) { + if (\is_array($activeItemData['IMAGES']['IMAGE'])) { foreach ($activeItemData['IMAGES']['IMAGE'] as $imgPos => $imgUrl) { - $stdImg = \AbraFlexi\Priloha::addAttachment($this->sokoban, $discompItemCode . '_' . $imgPos . '.jpg', $this->discomper->getImage($imgUrl), $this->discomper->getResponseMime()); - $this->sokoban->addStatusMessage(RO::uncode($this->sokoban->getRecordCode()) . ' Img: ' . $imgUrl, $stdImg->lastResponseCode == 201 ? 'success' : 'error'); - $this->images++; + $stdImg = \AbraFlexi\Priloha::addAttachment($this->sokoban, $discompItemCode.'_'.$imgPos.'.jpg', $this->discomper->getImage($imgUrl), $this->discomper->getResponseMime()); + $this->sokoban->addStatusMessage(\AbraFlexi\Functions::uncode($this->sokoban->getRecordCode()).' Img: '.$imgUrl, $stdImg->lastResponseCode === 201 ? 'success' : 'error'); + ++$this->images; } } else { - $stdImg = \AbraFlexi\Priloha::addAttachment($this->sokoban, $discompItemCode . '_' . 0 . '.jpg', $this->discomper->getImage($activeItemData['IMAGES']['IMAGE']), $this->discomper->getResponseMime()); - $this->sokoban->addStatusMessage(RO::uncode($this->sokoban->getRecordCode()) . ' Img: ' . $activeItemData['IMAGES']['IMAGE'], $stdImg->lastResponseCode == 201 ? 'success' : 'error'); - $this->images++; + $stdImg = \AbraFlexi\Priloha::addAttachment($this->sokoban, $discompItemCode.'_'. 0 .'.jpg', $this->discomper->getImage($activeItemData['IMAGES']['IMAGE']), $this->discomper->getResponseMime()); + $this->sokoban->addStatusMessage(\AbraFlexi\Functions::uncode($this->sokoban->getRecordCode()).' Img: '.$activeItemData['IMAGES']['IMAGE'], $stdImg->lastResponseCode === 201 ? 'success' : 'error'); + ++$this->images; } + unset($stdImg); } - if ($this->sokoban->lastResponseCode == 201) { - $this->new++; + + if ($this->sokoban->lastResponseCode === 201) { + ++$this->new; } else { - $errors++; + ++$errors; } } else { - $progressInfo = '(' . $pos . '/' . count($freshItems) . ') ' . $activeItemData['CODE'] . ': ' . $activeItemData['NAME']; - if (array_key_exists('dodavatel', $recordCheck) && ($recordCheck['dodavatel'] == $this->suplier)) { - $this->discomper->addStatusMessage($progressInfo . ' update', $this->sokoban->insertToAbraFlexi() ? 'success' : 'error'); + $progressInfo = '('.$pos.'/'.\count($freshItems).') '.$activeItemData['CODE'].': '.$activeItemData['NAME']; + + if (\array_key_exists('dodavatel', $recordCheck) && ($recordCheck['dodavatel'] === $this->suplier)) { + $this->discomper->addStatusMessage($progressInfo.' update', $this->sokoban->insertToAbraFlexi() ? 'success' : 'error'); } else { - $this->discomper->addStatusMessage($progressInfo . ' already enlisted', 'info'); + $this->discomper->addStatusMessage($progressInfo.' already enlisted', 'info'); } } + $this->removeItemFromTree($this->sokoban); - if (array_key_exists('CATEGORIES', $activeItemData)) { + + if (\array_key_exists('CATEGORIES', $activeItemData)) { foreach ($this->prepareCategories($activeItemData['CATEGORIES']['CATEGORY']) as $category) { $this->category->insertToAbraFlexi(['idZaznamu' => \AbraFlexi\RO::code($activeItemData['PART_NUMBER']), 'uzel' => $this->treeCache[$category]]); } @@ -309,15 +255,15 @@ public function freshItems() $this->addStatusMessage('No category ?!', 'warning'); } - if (array_key_exists('TEXT_PROPERTIES', $activeItemData)) { + if (\array_key_exists('TEXT_PROPERTIES', $activeItemData)) { foreach ($activeItemData['TEXT_PROPERTIES'] as $property) { - if (count($property) == 2 && key($property) == 'NAME') { - if (strlen($property['NAME'])) { + if (\count($property) === 2 && key($property) === 'NAME') { + if (\strlen($property['NAME'])) { $this->syncProperty($property['NAME'], $property['VALUE']); } } else { foreach ($property as $prop) { - if (strlen($prop['NAME'])) { + if (\strlen($prop['NAME'])) { $this->syncProperty($prop['NAME'], $prop['VALUE']); } } @@ -330,60 +276,71 @@ public function freshItems() } /** - * + * @param mixed $name + * @param mixed $value */ - public function syncProperty($name, $value) + public function syncProperty($name, $value): void { $attributeCode = \AbraFlexi\RO::code(mb_substr($name, -20)); + if (empty($this->atributType->loadFromAbraFlexi($attributeCode))) { - $this->atributType->addStatusMessage(RO::uncode($this->sokoban->getRecordCode()) . ': Attribute ' . $name . ' created', $this->atributType->sync(['kod' => \AbraFlexi\RO::uncode($attributeCode), 'nazev' => $name, 'typAtributK' => 'typAtribut.retezec']) ? 'success' : 'error'); + $this->atributType->addStatusMessage(\AbraFlexi\Functions::uncode($this->sokoban->getRecordCode()).': Attribute '.$name.' created', $this->atributType->sync(['kod' => \AbraFlexi\Functions::uncode($attributeCode), 'nazev' => $name, 'typAtributK' => 'typAtribut.retezec']) ? 'success' : 'error'); } + $this->atribut->dataReset(); $this->atribut->setDataValue('hodnota', $value); - if (is_float($value)) { - $this->atribut->setDataValue('valNumeric', floatval($value)); - } elseif (is_integer($value)) { - $this->atribut->setDataValue('valInteger', intval($value)); + + if (\is_float($value)) { + $this->atribut->setDataValue('valNumeric', (float) $value); + } elseif (\is_int($value)) { + $this->atribut->setDataValue('valInteger', (int) $value); } else { $this->atribut->setDataValue('valString', $value); } + $this->atribut->setDataValue('cenik', $this->sokoban); $this->atribut->setDataValue('typAtributu', $this->atributType); - $this->atribut->addStatusMessage(RO::uncode($this->sokoban->getRecordCode()) . ': ' . $name . ': ' . $value, $this->atribut->sync() ? 'success' : 'error'); + + try { + $this->atribut->addStatusMessage(\AbraFlexi\Functions::uncode($this->sokoban->getRecordCode()).': '.$name.': '.$value, $this->atribut->sync() ? 'success' : 'warning'); + } catch (\AbraFlexi\Exception $exc) { + $this->atribut->addStatusMessage(\AbraFlexi\Functions::uncode($this->sokoban->getRecordCode()).': '.$name.': '.$value, 'error'); + } // BAD: {"winstrom":{"@version":"1.0","atribut":{"hodnota":"QCA9531","valString":"QCA9531","cenik":"code:CRS354-48P-4S+2Q+RM","typAtributu":"code:CPU"},"@atomic":false}} } /** - * Initial import to fullfill pricelist + * Initial import to fullfill pricelist. */ - public function allTimeItems() + public function allTimeItems(): void { $errors = 0; $storageItems = []; $activeItems = $this->discomper->getResult('StoItemActive'); - $this->discomper->addStatusMessage(_('AllTime scope: ') . ' ' . sprintf(_('%d Active Items found'), count($activeItems)), 'success'); + $this->discomper->addStatusMessage(_('AllTime scope: ').' '.sprintf(_('%d Active Items found'), \count($activeItems)), 'success'); foreach ($activeItems as $pos => $activeItemData) { $storageItem = $this->discomper->getItemByCode($activeItemData['@attributes']['Code']); $discompItemId = $activeItemData['@attributes']['Id']; $discompItemCode = $activeItemData['@attributes']['Code']; - if (array_key_exists('StoItem', $storageItem['StoItemBase'])) { + + if (\array_key_exists('StoItem', $storageItem['StoItemBase'])) { $stoItem = $storageItem['StoItemBase']['StoItem']['@attributes']; - $baseImageUrl = $storageItem['StoItemBase']['@attributes']['UrlBaseImg'] . $discompItemId; - $thumbnailImageUrl = $storageItem['StoItemBase']['@attributes']['UrlBaseThumbnail'] . $discompItemId; - $largeImageUrl = $storageItem['StoItemBase']['@attributes']['UrlBaseEnlargement'] . $discompItemId; + $baseImageUrl = $storageItem['StoItemBase']['@attributes']['UrlBaseImg'].$discompItemId; + $thumbnailImageUrl = $storageItem['StoItemBase']['@attributes']['UrlBaseThumbnail'].$discompItemId; + $largeImageUrl = $storageItem['StoItemBase']['@attributes']['UrlBaseEnlargement'].$discompItemId; - if (array_key_exists('PartNo', $stoItem)) { + if (\array_key_exists('PartNo', $stoItem)) { $recordCheck = $this->sokoban->getColumnsFromAbraFlexi(['dodavatel', 'nazev', 'popis', 'pocetPriloh'], ['id' => \AbraFlexi\RO::code($stoItem['PartNo'])]); $this->sokoban->dataReset(); - $this->sokoban->setDataValue('typZasobyK', \Ease\Shared::cfg('DISCOMP_TYP_ZASOBY', 'typZasoby.material')); //TODO: ??? - $this->sokoban->setDataValue('typZasobyK', 'typZasoby.material'); //TODO: ??? - $this->sokoban->setDataValue('skladove', true); //TODO: ??? + $this->sokoban->setDataValue('typZasobyK', \Ease\Shared::cfg('DISCOMP_TYP_ZASOBY', 'typZasoby.material')); // TODO: ??? + $this->sokoban->setDataValue('typZasobyK', 'typZasoby.material'); // TODO: ??? + $this->sokoban->setDataValue('skladove', true); // TODO: ??? $this->sokoban->setDataValue('kod', $stoItem['PartNo']); $this->pricer->unsetDataValue('id'); $this->pricer->setDataValue('cenik', \AbraFlexi\RO::code($stoItem['PartNo'])); $this->pricer->setDataValue('nakupCena', $stoItem['PriceOrd']); - if (array_key_exists('QtyFree', $stoItem)) { + if (\array_key_exists('QtyFree', $stoItem)) { $this->pricer->setDataValue('stavMJ', $stoItem['QtyFree']); } else { $this->pricer->setDataValue('stavMJ', 0); @@ -393,57 +350,62 @@ public function allTimeItems() $this->sokoban->setDataValue('ean', $stoItem['Code']); $this->sokoban->setDataValue('nazev', $stoItem['Name']); - if (array_key_exists('WarDur', $stoItem)) { + if (\array_key_exists('WarDur', $stoItem)) { $this->sokoban->setDataValue('zaruka', $stoItem['WarDur']); } + $this->sokoban->setDataValue('mjZarukyK', 'mjZaruky.den'); - if (array_key_exists('Weight', $stoItem)) { + + if (\array_key_exists('Weight', $stoItem)) { $this->sokoban->setDataValue('hmotMj', $stoItem['Weight']); } - if (array_key_exists('NameE', $stoItem)) { + + if (\array_key_exists('NameE', $stoItem)) { $this->sokoban->setDataValue('nazevA', $stoItem['NameE']); } - if (array_key_exists('NoteShort', $stoItem)) { + + if (\array_key_exists('NoteShort', $stoItem)) { $this->sokoban->setDataValue('popis', $stoItem['NoteShort']); } -// if(array_key_exists('Note', $stoItem)){ -// $sokoban->setDataValue('popis',$stoItem['Note']); //TODO: Source contains HTML markup -// } + // if(array_key_exists('Note', $stoItem)){ + // $sokoban->setDataValue('popis',$stoItem['Note']); //TODO: Source contains HTML markup + // } $this->sokoban->setDataValue('dodavatel', $this->suplier); if (empty($recordCheck)) { - $this->discomper->addStatusMessage($pos . '/' . count($activeItems) . ' ' . $stoItem['Code'] . ': ' . $stoItem['Name'] . ' new item', $this->sokoban->insertToAbraFlexi() ? 'success' : 'error'); + $this->discomper->addStatusMessage($pos.'/'.\count($activeItems).' '.$stoItem['Code'].': '.$stoItem['Name'].' new item', $this->sokoban->insertToAbraFlexi() ? 'success' : 'error'); - if (array_key_exists('ImgIs', $stoItem) && $stoItem['ImgIs'] == 1) { - $stdImg = \AbraFlexi\Priloha::addAttachment($this->sokoban, $discompItemCode . '.jpg', $this->discomper->getImage($baseImageUrl), $this->discomper->getResponseMime()); + if (\array_key_exists('ImgIs', $stoItem) && $stoItem['ImgIs'] === 1) { + $stdImg = \AbraFlexi\Priloha::addAttachment($this->sokoban, $discompItemCode.'.jpg', $this->discomper->getImage($baseImageUrl), $this->discomper->getResponseMime()); // $this->sokoban->addStatusMessage($this->sokoban . ' ' . $baseImageUrl, $stdImg->lastResponseCode == 201 ? 'success' : 'error'); } - if (array_key_exists('EnlargementIs', $stoItem) && $stoItem['EnlargementIs'] == 1) { - $largeImg = \AbraFlexi\Priloha::addAttachment($this->sokoban, $discompItemCode . '.jpg', $this->discomper->getImage($largeImageUrl), $this->discomper->getResponseMime()); - // $this->sokoban->addStatusMessage(\AbraFlexi\RO::uncode($this->sokoban) . ' ' . $largeImageUrl, $largeImg->lastResponseCode == 201 ? 'success' : 'error'); + + if (\array_key_exists('EnlargementIs', $stoItem) && $stoItem['EnlargementIs'] === 1) { + $largeImg = \AbraFlexi\Priloha::addAttachment($this->sokoban, $discompItemCode.'.jpg', $this->discomper->getImage($largeImageUrl), $this->discomper->getResponseMime()); + // $this->sokoban->addStatusMessage(\AbraFlexi\Functions::uncode($this->sokoban) . ' ' . $largeImageUrl, $largeImg->lastResponseCode == 201 ? 'success' : 'error'); } - if ($this->sokoban->lastResponseCode == 201) { - $this->new++; + if ($this->sokoban->lastResponseCode === 201) { + ++$this->new; } else { - $errors++; + ++$errors; } } else { - if (array_key_exists('dodavatel', $recordCheck) && ($recordCheck['dodavatel'] == $this->suplier)) { - $this->discomper->addStatusMessage($pos . '/' . count($activeItems) . ' ' . $stoItem['Code'] . ': ' . $stoItem['Name'] . ' update', $this->sokoban->insertToAbraFlexi() ? 'success' : 'error'); + if (\array_key_exists('dodavatel', $recordCheck) && ($recordCheck['dodavatel'] === $this->suplier)) { + $this->discomper->addStatusMessage($pos.'/'.\count($activeItems).' '.$stoItem['Code'].': '.$stoItem['Name'].' update', $this->sokoban->insertToAbraFlexi() ? 'success' : 'error'); } else { - $this->discomper->addStatusMessage($pos . '/' . count($activeItems) . ' ' . $stoItem['Code'] . ': ' . $stoItem['Name'] . ' already iported', 'info'); + $this->discomper->addStatusMessage($pos.'/'.\count($activeItems).' '.$stoItem['Code'].': '.$stoItem['Name'].' already iported', 'info'); } } $this->updatePrice($stoItem); } else { $this->discomper->addStatusMessage(sprintf(_('Item %s %s does not contain part number. Skipping'), $stoItem['Code'], $stoItem['Name']), 'warning'); - $this->skipped++; + ++$this->skipped; } } else { - $this->discomper->addStatusMessage('Unparsable Response: ' . $this->discomper->getLastCurlResponseBody(), 'debug'); + $this->discomper->addStatusMessage('Unparsable Response: '.$this->discomper->getLastCurlResponseBody(), 'debug'); } } @@ -451,24 +413,26 @@ public function allTimeItems() } /** - * + * @param mixed $activeItemData */ - public function updatePrice($activeItemData) + public function updatePrice($activeItemData): void { $this->pricer->connectionReset(); $this->pricer->unsetDataValue('id'); $this->pricer->setDataValue('cenik', $this->sokoban); $this->pricer->setDataValue('kodIndi', $activeItemData['CODE']); $priceFound = $this->pricer->loadFromAbraFlexi(['cenik' => $this->sokoban, 'firma' => $this->suplier]); + if (empty($priceFound)) { $this->pricer->setDataValue('cenik', $this->sokoban); $this->pricer->setDataValue('firma', $this->suplier); } - $this->pricer->setDataValue('nakupCena', $activeItemData['PURCHASE_PRICE']); //TODO: Confirm column + + $this->pricer->setDataValue('nakupCena', $activeItemData['PURCHASE_PRICE']); // TODO: Confirm column $this->pricer->setDataValue('mena', RO::code($activeItemData['CURRENCY'])); $this->pricer->setDataValue('cenik', RO::code($activeItemData['PART_NUMBER'])); - if (array_key_exists('STOCK', $activeItemData) && array_key_exists('AMOUNT', $activeItemData['STOCK']) && floatval($activeItemData['STOCK']['AMOUNT'])) { + if (\array_key_exists('STOCK', $activeItemData) && \array_key_exists('AMOUNT', $activeItemData['STOCK']) && (float) $activeItemData['STOCK']['AMOUNT']) { $this->pricer->setDataValue('stavMJ', $activeItemData['STOCK']['AMOUNT']); } else { $this->pricer->setDataValue('stavMJ', 0); @@ -476,149 +440,158 @@ public function updatePrice($activeItemData) try { $this->pricer->insertToAbraFlexi(); - $this->pricer->addStatusMessage('supplier price update: ' . RO::uncode($this->sokoban->getRecordCode()) . ': ' . $this->pricer->getDataValue('nakupCena') . ' ' . RO::uncode($this->pricer->getDataValue('mena')), $this->pricer->lastResponseCode == 201 ? 'success' : 'error'); + $this->pricer->addStatusMessage('supplier price update: '.\AbraFlexi\Functions::uncode($this->sokoban->getRecordCode()).': '.$this->pricer->getDataValue('nakupCena').' '.\AbraFlexi\Functions::uncode($this->pricer->getDataValue('mena')), $this->pricer->lastResponseCode === 201 ? 'success' : 'error'); } catch (\AbraFlexi\Exception $exc) { echo $exc->getTraceAsString(); - $this->errors++; + ++$this->errors; } } /** - * Prepare processing interval + * Prepare processing interval. * * @param string $scope - * @throws Exception + * + * @throws \Exception */ - public function scopeToInterval($scope) + public function scopeToInterval($scope): void { switch ($scope) { case 'yesterday': - $this->since = new DateTime("yesterday"); - $this->until = new DateTime("today"); + $this->since = new \DateTime('yesterday'); + $this->until = new \DateTime('today'); + break; case 'last_week': - $this->since = new DateTime("monday last week"); - $this->until = new DateTime("sunday last week"); + $this->since = new \DateTime('monday last week'); + $this->until = new \DateTime('sunday last week'); + break; case 'current_month': - $this->since = new DateTime("first day of this month"); - $this->until = new DateTime(); + $this->since = new \DateTime('first day of this month'); + $this->until = new \DateTime(); + break; case 'last_month': - $this->since = new DateTime("first day of last month"); - $this->until = new DateTime("last day of last month"); - break; + $this->since = new \DateTime('first day of last month'); + $this->until = new \DateTime('last day of last month'); - case 'last_two_months': - $this->since = (new DateTime("first day of last month"))->modify('-1 month'); - $this->until = (new DateTime("last day of last month")); break; + case 'last_two_months': + $this->since = (new \DateTime('first day of last month'))->modify('-1 month'); + $this->until = (new \DateTime('last day of last month')); - case 'previous_month': - $this->since = new DateTime("first day of -2 month"); - $this->until = new DateTime("last day of -2 month"); break; + case 'previous_month': + $this->since = new \DateTime('first day of -2 month'); + $this->until = new \DateTime('last day of -2 month'); - case 'two_months_ago': - $this->since = new DateTime("first day of -3 month"); - $this->until = new DateTime("last day of -3 month"); break; + case 'two_months_ago': + $this->since = new \DateTime('first day of -3 month'); + $this->until = new \DateTime('last day of -3 month'); + break; case 'this_year': - $this->since = new DateTime('first day of January ' . date('Y')); - $this->until = new DateTime("last day of December" . date('Y')); + $this->since = new \DateTime('first day of January '.date('Y')); + $this->until = new \DateTime('last day of December'.date('Y')); + break; + case 'January': // 1 + case 'February': // 2 + case 'March': // 3 + case 'April': // 4 + case 'May': // 5 + case 'June': // 6 + case 'July': // 7 + case 'August': // 8 + case 'September':// 9 + case 'October': // 10 + case 'November': // 11 + case 'December': // 12 + $this->since = new \DateTime('first day of '.$scope.' '.date('Y')); + $this->until = new \DateTime('last day of '.$scope.' '.date('Y')); - case 'January': //1 - case 'February': //2 - case 'March': //3 - case 'April': //4 - case 'May': //5 - case 'June': //6 - case 'July': //7 - case 'August': //8 - case 'September'://9 - case 'October': //10 - case 'November': //11 - case 'December': //12 - $this->since = new DateTime('first day of ' . $scope . ' ' . date('Y')); - $this->until = new DateTime('last day of ' . $scope . ' ' . date('Y')); break; default: - throw new Exception('Unknown scope ' . $scope); + throw new \Exception('Unknown scope '.$scope); } + $this->since = $this->since->setTime(0, 0); $this->until = $this->until->setTime(0, 0); } /** - * Generate > Path > Of > Categories - * - * @param array $categoriesRaw + * Generate > Path > Of > Categories. */ - public function prepareCategories($categoriesRaw) + public function prepareCategories(array $categoriesRaw): array { $categories = []; + foreach ($categoriesRaw as $tree) { - $categories[] = $this->categoryBranch(explode(' > ', 'Discomp > ' . $tree)); + $categories[] = $this->categoryBranch(explode(' > ', 'Discomp > '.$tree)); } + return $categories; } /** - * Create ale nodes in category tree - * - * @param array $nodes + * Create ale nodes in category tree. * * @return string */ public function categoryBranch(array $nodes) { $parent = ''; + foreach ($nodes as $level => $node) { - $parent = $this->createBranchNode($node, $level, $parent, md5(implode('', array_slice($nodes, 0, $level + 1)))); + $parent = $this->createBranchNode($node, $level, $parent, md5(implode('', \array_slice($nodes, 0, $level + 1)))); } + return $parent; } /** - * Create Branch Node + * Create Branch Node. * - * @param string $node - * @param int $level - * @param string $parent - * @param srting $kod focred code for branch + * @param srting $kod focred code for branch * * @return string */ public function createBranchNode(string $node, int $level, string $parent, string $kod) { $kod = RO::code(substr($kod, 0, 30)); - if (array_key_exists($level, $this->levels)) { - $this->levels[$level]++; + + if (\array_key_exists($level, $this->levels)) { + ++$this->levels[$level]; } else { $this->levels[$level] = 1; } + $strom = new \AbraFlexi\Strom($kod, ['ignore404' => true]); - if ($strom->lastResponseCode == 404) { + + if ($strom->lastResponseCode === 404) { $strom->setDataValue('id', $kod); $strom->setDataValue('nazev', $node); $strom->setDataValue('strom', RO::code(self::$ROOT)); + if ($parent) { $strom->setDataValue('otec', $parent); } + $strom->setDataValue('poradi', $this->levels[$level]); - //$strom->setDataValue('hladina',$level); + // $strom->setDataValue('hladina',$level); - $strom->addStatusMessage('Create Category ' . $node, $strom->sync() ? 'success' : 'error'); + $strom->addStatusMessage('Create Category '.$node, $strom->sync() ? 'success' : 'error'); } + $this->treeCache[$strom->getRecordCode()] = $strom->getMyKey(); + return $strom->getRecordCode(); } /** - * * @return int */ public function ensureCategoryRootExists() @@ -632,27 +605,27 @@ public function ensureCategoryRootExists() 'tabulka' => 'cz.winstrom.vo.cen.Cenik', ]; $root = new RW(RO::code(self::$ROOT), ['evidence' => 'strom-koren', 'ignore404' => true]); - return $root->lastResponseCode == 200 ? $root->getMyKey() : $root->insertToAbraFlexi($discpmpData); + + return $root->lastResponseCode === 200 ? $root->getMyKey() : $root->insertToAbraFlexi($discpmpData); } /** - * - * @param string $manufacturerName - * * @return \AbraFlexi\Adresar */ public function findManufacturerCode(string $manufacturerName) { $manufacturerCode = RO::code($manufacturerName); $manufacturer = new \AbraFlexi\Adresar($manufacturerCode, ['ignore404' => true]); - if ($manufacturer->lastResponseCode == 404) { - $manufacturer->addStatusMessage(sprintf(_('New Manufacturer %s'), $manufacturerName), $manufacturer->sync(['kod' => RO::uncode($manufacturerName), 'nazev' => $manufacturerName]) ? 'success' : 'error'); + + if ($manufacturer->lastResponseCode === 404) { + $manufacturer->addStatusMessage(sprintf(_('New Manufacturer %s'), $manufacturerName), $manufacturer->sync(['kod' => \AbraFlexi\Functions::uncode($manufacturerName), 'nazev' => $manufacturerName]) ? 'success' : 'error'); } + return $manufacturer; } /** - * Remove Item from Pricelit Category Tree + * Remove Item from Pricelit Category Tree. * * @param \AbraFlexi\Cenik $item */ @@ -660,11 +633,13 @@ public function removeItemFromTree($item) { $done = 0; $current = $this->category->getColumnsFromAbraFlexi(['id'], ['idZaznamu' => $item->getRecordID()]); + foreach ($current as $assigned) { if ($this->category->deleteFromAbraFlexi($assigned['id'])) { - $done++; + ++$done; } } + return $done; } } diff --git a/src/discomp2abraflexi-init.php b/src/discomp2abraflexi-init.php index 067c148..398ff59 100644 --- a/src/discomp2abraflexi-init.php +++ b/src/discomp2abraflexi-init.php @@ -2,32 +2,43 @@ declare(strict_types=1); +/** + * This file is part of the discomp2abraflexi package + * + * https://github.com/Spoje-NET/discomp2abraflexi + * + * (c) SpojeNet s.r.o. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace SpojeNet; /** - * Discomp pricelist importer to AbraFlexi + * Discomp pricelist importer to AbraFlexi. * * @author Vítězslav Dvořák * @copyright 2023 Vitex Software */ +\define('APP_NAME', 'Discomp2AbraFlexi Init'); -define('APP_NAME', 'Discomp2AbraFlexi Init'); require_once '../vendor/autoload.php'; \Ease\Shared::init( [ - 'ABRAFLEXI_URL', - 'ABRAFLEXI_LOGIN', - 'ABRAFLEXI_PASSWORD', - 'ABRAFLEXI_COMPANY', - 'ABRAFLEXI_STORAGE', - 'DISCOMP_USERNAME', - 'DISCOMP_PASSWORD' - ], - '../.env' + 'ABRAFLEXI_URL', + 'ABRAFLEXI_LOGIN', + 'ABRAFLEXI_PASSWORD', + 'ABRAFLEXI_COMPANY', + 'ABRAFLEXI_STORAGE', + 'DISCOMP_USERNAME', + 'DISCOMP_PASSWORD', + ], + '../.env', ); $importer = new Discomp\Importer(); $importer->addStatusMessage(_('Supplier Exists'), $importer->ensureSupplierExists() ? 'success' : 'error'); $importer->addStatusMessage(_('Category Root Exists'), $importer->ensureCategoryRootExists() ? 'success' : 'error'); -//Todo Attach Discomp logo to ROOT +// Todo Attach Discomp logo to ROOT diff --git a/src/discomp2abraflexi.php b/src/discomp2abraflexi.php index b04a5b1..5caeeaa 100644 --- a/src/discomp2abraflexi.php +++ b/src/discomp2abraflexi.php @@ -2,33 +2,44 @@ declare(strict_types=1); +/** + * This file is part of the discomp2abraflexi package + * + * https://github.com/Spoje-NET/discomp2abraflexi + * + * (c) SpojeNet s.r.o. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace SpojeNet; /** - * Discomp pricelist importer to AbraFlexi + * Discomp pricelist importer to AbraFlexi. * * @author Vítězslav Dvořák * @copyright 2023 Vitex Software */ +\define('APP_NAME', 'Discomp2AbraFlexi'); -define('APP_NAME', 'Discomp2AbraFlexi'); require_once '../vendor/autoload.php'; \Ease\Shared::init( [ - 'ABRAFLEXI_URL', - 'ABRAFLEXI_LOGIN', - 'ABRAFLEXI_PASSWORD', - 'ABRAFLEXI_COMPANY', - 'ABRAFLEXI_STORAGE', - 'DISCOMP_USERNAME', - 'DISCOMP_PASSWORD' - ], - '../.env' + 'ABRAFLEXI_URL', + 'ABRAFLEXI_LOGIN', + 'ABRAFLEXI_PASSWORD', + 'ABRAFLEXI_COMPANY', + 'ABRAFLEXI_STORAGE', + 'DISCOMP_USERNAME', + 'DISCOMP_PASSWORD', + ], + '../.env', ); $importer = new Discomp\Importer(); -if (\Ease\Shared::cfg('DISCOMP_SCOPE') == 'all') { +if (\Ease\Shared::cfg('DISCOMP_SCOPE') === 'all') { $importer->allTimeItems(); } else { $importer->freshItems();