Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Datanorm\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Components\Database\Exception\QueryFailureException;
|
||||
use Xentral\Modules\Datanorm\Exception\ArticleNotFoundException;
|
||||
use Xentral\Modules\Datanorm\Exception\InvalidArgumentException;
|
||||
|
||||
|
||||
final class ArticleService
|
||||
{
|
||||
|
||||
/** @var Database */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $articleArray
|
||||
*
|
||||
* @throws ArticleNotFoundException
|
||||
* @throws QueryFailureException
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function InsertUpdateArticle(array $articleArray): ?int
|
||||
{
|
||||
if (empty($articleArray['nummer'])) {
|
||||
throw new ArticleNotFoundException('No article number found.');
|
||||
}
|
||||
|
||||
$articleId = $this->findArticleIdByNumber($articleArray['nummer']);
|
||||
|
||||
if (empty($articleId)) {
|
||||
$articleId = $this->insertArrayIntoTable($articleArray, 'artikel');
|
||||
} else {
|
||||
$this->updateArrayIntoTable($articleArray, 'artikel', $articleId);
|
||||
}
|
||||
|
||||
return $articleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param string $table
|
||||
*
|
||||
* @throws QueryFailureException
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function insertArrayIntoTable(array $data, string $table): ?int
|
||||
{
|
||||
if (empty($data)) {
|
||||
throw new InvalidArgumentException('No data to insert into ' . $table . ' given');
|
||||
}
|
||||
|
||||
$insert = $this->db->insert();
|
||||
$insert
|
||||
->cols($data)
|
||||
->into($table);
|
||||
$this->db->perform($insert->getStatement(), $insert->getBindValues());
|
||||
|
||||
return $this->db->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param string $table
|
||||
* @param int $id
|
||||
*
|
||||
* @throws QueryFailureException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function updateArrayIntoTable(array $data, string $table, int $id): void
|
||||
{
|
||||
if (empty($data)) {
|
||||
throw new InvalidArgumentException('No data to update in ' . $table . ' given');
|
||||
}
|
||||
|
||||
if (empty($id)) {
|
||||
throw new InvalidArgumentException('No id for update in ' . $table . ' given');
|
||||
}
|
||||
|
||||
$update = $this->db->update()
|
||||
->table($table)
|
||||
->cols($data)
|
||||
->where('id=?', $id);
|
||||
|
||||
$this->db->perform($update->getStatement(), $update->getBindValues());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $number
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function findArticleIdByNumber(string $number): ?int
|
||||
{
|
||||
$select = $this->db->select()
|
||||
->cols(['id'])
|
||||
->from('artikel')
|
||||
->where('nummer=?', $number)
|
||||
->limit(1);
|
||||
|
||||
$result = $this->db->fetchCol(
|
||||
$select->getStatement(),
|
||||
$select->getBindValues()
|
||||
);
|
||||
|
||||
if (!empty($result)) {
|
||||
return $result[0];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Datanorm\Service;
|
||||
|
||||
use Xentral\Modules\Datanorm\Data\DatanormATypeData;
|
||||
use Xentral\Modules\Datanorm\Data\DatanormBTypeData;
|
||||
|
||||
final class DatanormConverter
|
||||
{
|
||||
/**
|
||||
* @param DatanormATypeData $aType
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function transformATypeToArticleArray(DatanormATypeData $aType): array
|
||||
{
|
||||
$article = [];
|
||||
$article['nummer'] = $aType->getArticleNumber();
|
||||
$article['name_de'] = $aType->getShortDescription1();
|
||||
$article['anabregs_text'] = $aType->getShortDescription2();
|
||||
$article['ean'] = $aType->getEan();
|
||||
$article['herstellernummer'] = $aType->getProducerNumber();
|
||||
$article['einheit'] = $aType->getPackingUnit();
|
||||
|
||||
if ($aType->getArticleType() === '1') {
|
||||
$article['lagerartikel'] = 1;
|
||||
}
|
||||
|
||||
if ($aType->getWorkflowState() === 'L') {
|
||||
$article['intern_gesperrt'] = 1;
|
||||
$article['intern_gesperrtgrund'] = 'DATANORM';
|
||||
}
|
||||
|
||||
$article['umsatzsteuer'] = 'normal';
|
||||
if ($aType->getMwstType() === 3) {
|
||||
$article['umsatzsteuer'] = 'ermaessigt';
|
||||
}
|
||||
|
||||
return $article;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DatanormBTypeData $bType
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function transformBTypeToArticleArray(DatanormBTypeData $bType): array
|
||||
{
|
||||
$article = [];
|
||||
|
||||
if (!empty($bType->getEan())) {
|
||||
$article['ean'] = $bType->getEan();
|
||||
}
|
||||
|
||||
if ($bType->getProcessingFlag() === 'L') {
|
||||
$article['intern_gesperrt'] = 1;
|
||||
$article['intern_gesperrtgrund'] = 'DATANORM';
|
||||
}
|
||||
|
||||
if (!empty($bType->getAltArticleNumber())) {
|
||||
$article['herstellernummer'] = $bType->getAltArticleNumber();
|
||||
}
|
||||
|
||||
if ($bType->getCopperWeightIndicator() != '0' && $bType->getCopperWeightIndicator() != '') {
|
||||
$article['internerkommentar'] =
|
||||
'Kupfer-Gewichtsmerker: ' . $bType->getCopperWeightIndicator() . PHP_EOL .
|
||||
'Kupfer-Kennzahl: ' . $bType->getCopperWeightIndicator() . PHP_EOL .
|
||||
'Kupfer-Gewicht: ' . $bType->getCopperWeightIndicator();
|
||||
}
|
||||
|
||||
if (!empty($article)) {
|
||||
$article['nummer'] = $bType->getArticleNumber();
|
||||
}
|
||||
|
||||
return $article;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @param string $priceMark
|
||||
* @param string $currency
|
||||
* @param int $amount
|
||||
* @param float $price
|
||||
* @param int $supplierId
|
||||
* @param string $discountFlag1
|
||||
* @param float $discount1
|
||||
* @param string $discountFlag2
|
||||
* @param float $discount2
|
||||
* @param string $discountFlag3
|
||||
* @param float $discount3
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function transformToPriceArray(
|
||||
int $articleId,
|
||||
string $priceMark,
|
||||
string $currency,
|
||||
int $amount,
|
||||
float $price,
|
||||
int $supplierId,
|
||||
string $discountFlag1,
|
||||
float $discount1,
|
||||
string $discountFlag2,
|
||||
float $discount2,
|
||||
string $discountFlag3,
|
||||
float $discount3
|
||||
): array {
|
||||
$sellingPrice = [];
|
||||
$purchasePrices = [];
|
||||
|
||||
if ($priceMark === '2') {
|
||||
$purchasePrices[] = [
|
||||
'article_id' => $articleId,
|
||||
'address_id' => $supplierId,
|
||||
'currency_code' => $currency,
|
||||
'quantity_from' => $amount,
|
||||
'price' => $price,
|
||||
];
|
||||
} else {
|
||||
$sellingPrice = [
|
||||
'currency_code' => $currency,
|
||||
'quantity_from' => $amount,
|
||||
'article_id' => $articleId,
|
||||
'price' => $price,
|
||||
];
|
||||
|
||||
if ($priceMark === '1') {
|
||||
if (!empty($discountFlag1)) {
|
||||
$discountPrice1 = $this->calculateDiscountPrice($price, $discountFlag1, $discount1);
|
||||
if (!empty($discountPrice1)) {
|
||||
$purchasePrices[] = [
|
||||
'article_id' => $articleId,
|
||||
'address_id' => $supplierId,
|
||||
'currency_code' => $currency,
|
||||
'quantity_from' => $amount,
|
||||
'price' => $discountPrice1,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($discountFlag2)) {
|
||||
$discountPrice2 = $this->calculateDiscountPrice($price, $discountFlag2, $discount2);
|
||||
if (!empty($discountPrice2)) {
|
||||
$purchasePrices[] = [
|
||||
'article_id' => $articleId,
|
||||
'address_id' => $supplierId,
|
||||
'currency_code' => $currency,
|
||||
'quantity_from' => $amount,
|
||||
'price' => $discountPrice2,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($discountFlag3)) {
|
||||
$discountPrice3 = $this->calculateDiscountPrice($price, $discountFlag3, $discount3);
|
||||
if (!empty($discountPrice3)) {
|
||||
$purchasePrices[] = [
|
||||
'article_id' => $articleId,
|
||||
'address_id' => $supplierId,
|
||||
'currency_code' => $currency,
|
||||
'quantity_from' => $amount,
|
||||
'price' => $discountPrice3,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'sellingPrice' => $sellingPrice,
|
||||
'purchasePrices' => $purchasePrices,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $price
|
||||
* @param string $discountFlag
|
||||
* @param float $discount
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function calculateDiscountPrice(float $price, string $discountFlag, float $discount)
|
||||
{
|
||||
$discountPrice = 0.0;
|
||||
|
||||
// Discount
|
||||
if ($discountFlag === '1') {
|
||||
$discountPrice = $price - ($price * ($discount / 100));
|
||||
} // Factor
|
||||
elseif ($discountFlag === '2') {
|
||||
$discountPrice = $price * $discount;
|
||||
} // Surcharge
|
||||
elseif ($discountFlag === '3') {
|
||||
$discountPrice = $price + ($price * ($discount / 100));
|
||||
}
|
||||
|
||||
return $discountPrice;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Datanorm\Service;
|
||||
|
||||
use Xentral\Modules\Datanorm\Data\DatanormATypeData;
|
||||
use Xentral\Modules\Datanorm\Data\DatanormDTypeData;
|
||||
use Xentral\Modules\Datanorm\Data\DatanormPTypeData;
|
||||
use Xentral\Modules\Datanorm\Data\DatanormTTypeData;
|
||||
|
||||
final class DatanormEnricher
|
||||
{
|
||||
/** @var DatanormIntermediateGateway $intermediateGateway */
|
||||
private $intermediateGateway;
|
||||
|
||||
/**
|
||||
* @param DatanormIntermediateGateway $intermediateGateway
|
||||
*/
|
||||
public function __construct(DatanormIntermediateGateway $intermediateGateway)
|
||||
{
|
||||
$this->intermediateGateway = $intermediateGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DatanormPTypeData $pType
|
||||
*
|
||||
* @return DatanormPTypeData
|
||||
*/
|
||||
public function enrichPrice(DatanormPTypeData $pType): DatanormPTypeData
|
||||
{
|
||||
$articleNumber = $pType->getArticleNumber1();
|
||||
$data = $this->intermediateGateway->findArticleLineByNumber($articleNumber);
|
||||
$amount = $this->getPriceAmount($data);
|
||||
$pType->setPriceAmount1($amount);
|
||||
$price = $pType->getPrice1();
|
||||
$pType->setPrice1($price / $amount);
|
||||
|
||||
$articleNumber2 = $pType->getArticleNumber2();
|
||||
if (!empty($articleNumber2)) {
|
||||
$data = $this->intermediateGateway->findArticleLineByNumber($articleNumber2);
|
||||
if (isset($data['content'])) {
|
||||
$amount = $this->getPriceAmount($data);
|
||||
$pType->setPriceAmount2($amount);
|
||||
$price = $pType->getPrice2();
|
||||
$pType->setPrice2($price / $amount);
|
||||
}
|
||||
}
|
||||
|
||||
$articleNumber3 = $pType->getArticleNumber3();
|
||||
if (!empty($articleNumber3)) {
|
||||
$data = $this->intermediateGateway->findArticleLineByNumber($articleNumber3);
|
||||
if (isset($data['content'])) {
|
||||
$amount = $this->getPriceAmount($data);
|
||||
$pType->setPriceAmount3($amount);
|
||||
$price = $pType->getPrice3();
|
||||
$pType->setPrice3($price / $amount);
|
||||
}
|
||||
}
|
||||
|
||||
return $pType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getPriceAmount(array $data): int
|
||||
{
|
||||
$aType = new DatanormATypeData();
|
||||
$aType->fillByJson($data['content']);
|
||||
|
||||
return (int)$aType->getPriceAmount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DatanormATypeData $aType
|
||||
*
|
||||
* @return DatanormATypeData
|
||||
*/
|
||||
public function enrichArticle(DatanormATypeData $aType): DatanormATypeData
|
||||
{
|
||||
$longTextBlockNumber = $aType->getLongDecriptionKey();
|
||||
$textFlag = substr($aType->getTextkey(), 0, 1);
|
||||
|
||||
$text = '';
|
||||
$longtText = '';
|
||||
$dimensionText = '';
|
||||
|
||||
if (!empty($longTextBlockNumber)) {
|
||||
$longtextData = $this->intermediateGateway->findTTypeContentByBlocknumber($longTextBlockNumber);
|
||||
if (!empty($longtextData)) {
|
||||
$longtText = $this->createLongText($longtextData);
|
||||
}
|
||||
}
|
||||
|
||||
$dimensionTextData = $this->intermediateGateway->findDTypeContentByArticleNumer($aType->getArticleNumber());
|
||||
if (!empty($dimensionTextData)) {
|
||||
$dimensionText = $this->getDimensionText($dimensionTextData);
|
||||
}
|
||||
|
||||
if ($textFlag === '0') { //KT1 + KT2
|
||||
$text .= $aType->getShortDescription1() . PHP_EOL;
|
||||
$text .= $aType->getShortDescription2();
|
||||
} elseif ($textFlag === '1') { //LT + KT2
|
||||
$text .= $longtText . PHP_EOL;
|
||||
$text .= $aType->getShortDescription2();
|
||||
} elseif ($textFlag === '2') { //KT1 + DT
|
||||
$text .= $aType->getShortDescription1() . PHP_EOL;
|
||||
$text .= $dimensionText;
|
||||
} elseif ($textFlag === '3') { //LT + DT
|
||||
$text .= $longtText . PHP_EOL;
|
||||
$text .= $dimensionText;
|
||||
} elseif ($textFlag === '4') { //KT1 + KT2 + LT
|
||||
$text .= $aType->getShortDescription1() . PHP_EOL;
|
||||
$text .= $aType->getShortDescription2() . PHP_EOL;
|
||||
$text .= $longtText;
|
||||
} elseif ($textFlag === '5') { //KT1 + KT2 + DT
|
||||
$text .= $aType->getShortDescription1() . PHP_EOL;
|
||||
$text .= $aType->getShortDescription2() . PHP_EOL;
|
||||
$text .= $dimensionText;
|
||||
} elseif ($textFlag === '6') { //KT1 + KT2 + LT + DT
|
||||
$text .= $aType->getShortDescription1() . PHP_EOL;
|
||||
$text .= $aType->getShortDescription2() . PHP_EOL;
|
||||
$text .= $longtText . PHP_EOL;
|
||||
$text .= $dimensionText;
|
||||
}
|
||||
|
||||
if (!empty($text)) {
|
||||
$aType->setShortDescription2(trim($text));
|
||||
}
|
||||
|
||||
return $aType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $longTextData
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createLongText(array $longTextData): string
|
||||
{
|
||||
$longtext = '';
|
||||
foreach ($longTextData as $d) {
|
||||
$tType = new DatanormTTypeData();
|
||||
$tType->fillByJson($d['content']);
|
||||
|
||||
if (!empty($tType->getText1())) {
|
||||
$longtext .= $tType->getText1() . PHP_EOL;
|
||||
}
|
||||
|
||||
if (!empty($tType->getText2())) {
|
||||
$longtext .= $tType->getText2() . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return trim($longtext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $dimensionTextData
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getDimensionText(array $dimensionTextData): string
|
||||
{
|
||||
$dimensionText = '';
|
||||
|
||||
foreach ($dimensionTextData as $d) {
|
||||
$dType = new DatanormDTypeData();
|
||||
$dType->fillByJson($d['content']);
|
||||
|
||||
$textIndicator1 = $dType->getTextIndicator1();
|
||||
$textIndicator2 = $dType->getTextIndicator2();
|
||||
|
||||
if (!empty($textIndicator1)) {
|
||||
$txt = $this->createDimensionText(
|
||||
$textIndicator1,
|
||||
$dType->getText1(),
|
||||
$dType->getTextblockNumber1()
|
||||
);
|
||||
if (!empty($txt)) {
|
||||
$dimensionText .= $txt . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($textIndicator2)) {
|
||||
$txt = $this->createDimensionText(
|
||||
$textIndicator2,
|
||||
$dType->getText2(),
|
||||
$dType->getTextblockNumber2()
|
||||
);
|
||||
if (!empty($txt)) {
|
||||
$dimensionText .= $txt . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trim($dimensionText);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $textIndicator
|
||||
* @param string $text
|
||||
* @param string $textBlockNumber
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createDimensionText(string $textIndicator, string $text, string $textBlockNumber): string
|
||||
{
|
||||
$dimensionText = '';
|
||||
|
||||
if ($textIndicator === 'F') {
|
||||
$dimensionText = $text;
|
||||
} else {
|
||||
$longTextData = $this->intermediateGateway->findTTypeContentByBlocknumber(
|
||||
$textBlockNumber
|
||||
);
|
||||
|
||||
if ($textIndicator === 'T') {
|
||||
$dimensionText .= $this->createLongText($longTextData);
|
||||
} elseif ($textIndicator === 'E') {
|
||||
$dimensionText .= $this->createInsertingText($text, $longTextData);
|
||||
}
|
||||
}
|
||||
|
||||
return $dimensionText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fillementText
|
||||
* @param array $longTextData
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createInsertingText(string $fillementText, array $longTextData): string
|
||||
{
|
||||
$tType = new DatanormTTypeData();
|
||||
$tType->fillByJson($longTextData[0]['content']);
|
||||
$pattern = $tType->getText1();
|
||||
|
||||
$patternExp = explode('$$$', $pattern);
|
||||
$fillmentExp = explode('$', $fillementText);
|
||||
|
||||
$text = '';
|
||||
for ($i = 0; $i < count($patternExp); $i++) {
|
||||
$text .= $patternExp[$i] . $fillmentExp[$i];
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Datanorm\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
|
||||
final class DatanormIntermediateGateway
|
||||
{
|
||||
|
||||
/** @var Database */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLines(int $limit): array
|
||||
{
|
||||
$sqlOnlyA =
|
||||
'SELECT d.id, d.fileName, d.type, d.content
|
||||
FROM `datanorm_intermediate` AS `d`
|
||||
WHERE d.type = \'A\'
|
||||
AND d.errorFlag = 0
|
||||
AND d.doneFlag = 0
|
||||
AND d.ready = 1
|
||||
ORDER BY d.id DESC
|
||||
LIMIT ' . $limit;
|
||||
|
||||
$sqlNotV =
|
||||
'SELECT d.id, d.fileName, d.type, d.content
|
||||
FROM `datanorm_intermediate` AS `d`
|
||||
WHERE d.type != \'V\'
|
||||
AND d.errorFlag = 0
|
||||
AND d.doneFlag = 0
|
||||
AND d.ready = 1
|
||||
ORDER BY d.id DESC
|
||||
LIMIT ' . $limit;
|
||||
|
||||
// Articles (type A) MUST be imported before anything else;
|
||||
// 'ORDER BY type' makes the query slower than 2 single querys
|
||||
$rows = $this->db->fetchAll($sqlOnlyA);
|
||||
|
||||
if (empty($rows)) {
|
||||
$rows = $this->db->fetchAll($sqlNotV);
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLinesToEnrich(int $limit): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT d.id, d.fileName, d.type, d.content
|
||||
FROM `datanorm_intermediate` AS `d`
|
||||
WHERE d.enrich = 1
|
||||
AND d.doneFlag = 0
|
||||
ORDER BY d.id DESC
|
||||
LIMIT ' . $limit;
|
||||
|
||||
return $this->db->fetchAll($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getVType(string $fileName): array
|
||||
{
|
||||
$select = $this->db->select()
|
||||
->cols(['id', 'fileName', 'type', 'content', 'supplier_address_id', 'user_address_id'])
|
||||
->from('datanorm_intermediate')
|
||||
->where('fileName = ?', $fileName)
|
||||
->where('type = ?', 'V')
|
||||
->limit(1);
|
||||
|
||||
return $this->db->fetchRow(
|
||||
$select->getStatement(),
|
||||
$select->getBindValues()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $articleNumber
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findArticleLineByNumber(string $articleNumber): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT di.content
|
||||
FROM `datanorm_intermediate` AS `di`
|
||||
WHERE di.type = \'A\'
|
||||
AND di.nummer = :articleNumber
|
||||
ORDER BY di.id DESC
|
||||
LIMIT 1';
|
||||
|
||||
$values = [
|
||||
'articleNumber' => $articleNumber,
|
||||
];
|
||||
|
||||
return $this->db->fetchRow($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $longTextBlockNumber
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findTTypeContentByBlocknumber(string $longTextBlockNumber): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT di.content
|
||||
FROM `datanorm_intermediate` AS `di`
|
||||
WHERE di.type = \'T\'
|
||||
AND di.nummer = :longTextBlockNumber
|
||||
AND di.doneFlag = 0
|
||||
ORDER BY di.id';
|
||||
|
||||
$values = [
|
||||
'longTextBlockNumber' => $longTextBlockNumber,
|
||||
];
|
||||
|
||||
return $this->db->fetchAll($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $articleNumber
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findDTypeContentByArticleNumer(string $articleNumber): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT di.content
|
||||
FROM `datanorm_intermediate` AS `di`
|
||||
WHERE di.type = \'D\'
|
||||
AND di.nummer = :articleNumber
|
||||
AND di.doneFlag = 0
|
||||
ORDER BY di.id';
|
||||
|
||||
$values = [
|
||||
'articleNumber' => $articleNumber,
|
||||
];
|
||||
|
||||
return $this->db->fetchAll($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $vId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function findSupplierNumberByVid(int $vId)
|
||||
{
|
||||
$sql =
|
||||
'SELECT a.lieferantennummer
|
||||
FROM `adresse` AS `a`
|
||||
LEFT JOIN `datanorm_intermediate` AS `di` ON di.supplier_address_id = a.id
|
||||
WHERE di.id = :v_id';
|
||||
|
||||
$values = [
|
||||
'v_id' => $vId,
|
||||
];
|
||||
|
||||
$result = $this->db->fetchRow($sql, $values);
|
||||
|
||||
if (!empty($result)) {
|
||||
return (string)$result['lieferantennummer'];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Datanorm\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
|
||||
final class DatanormIntermediateService
|
||||
{
|
||||
/** @var Database */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $intermediateEntries
|
||||
*/
|
||||
public function writeMultiple(array $intermediateEntries): void
|
||||
{
|
||||
if (!empty($intermediateEntries)) {
|
||||
$sql =
|
||||
'INSERT IGNORE INTO `datanorm_intermediate` (`fileName`, `type`, `content` ,`hash`, `doneFlag`, `nummer`,`enrich`, `user_address_id`)
|
||||
VALUES';
|
||||
$values = [];
|
||||
$sqlParams = [];
|
||||
|
||||
foreach ($intermediateEntries as $index => $entry) {
|
||||
$fileName = $entry['fileName'];
|
||||
$type = $entry['type'];
|
||||
$content = json_encode($entry['obj']);
|
||||
$doneFlag = ($type === 'V' ? 1 : 0);
|
||||
$hash = ($type === 'V' ? $fileName : md5($content));
|
||||
$nummer = $entry['nummer'];
|
||||
$enrich = $entry['enrich'];
|
||||
$userAddressId = $entry['user_address_id'];
|
||||
|
||||
$values['fileName' . $index] = $fileName;
|
||||
$values['type' . $index] = $type;
|
||||
$values['content' . $index] = $content;
|
||||
$values['hash' . $index] = $hash;
|
||||
$values['doneFlag' . $index] = $doneFlag;
|
||||
$values['nummer' . $index] = $nummer;
|
||||
$values['enrich' . $index] = $enrich;
|
||||
$values['user_address_id' . $index] = $userAddressId;
|
||||
|
||||
$sqlParams[] =
|
||||
'(:fileName' . $index .
|
||||
',:type' . $index .
|
||||
',:content' . $index .
|
||||
',:hash' . $index .
|
||||
',:doneFlag' . $index .
|
||||
',:nummer' . $index .
|
||||
',:enrich' . $index .
|
||||
',:user_address_id' . $index . ')';
|
||||
}
|
||||
|
||||
$sql .= implode(',', $sqlParams);
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $intermdiateIds
|
||||
* @param bool $done
|
||||
*/
|
||||
public function setMultipleDone(array $intermdiateIds, bool $done = true): void
|
||||
{
|
||||
if (!empty($intermdiateIds)) {
|
||||
$sql = 'UPDATE `datanorm_intermediate` SET `doneFlag` = :done WHERE `id` IN (';
|
||||
|
||||
$values = [
|
||||
'done' => $done,
|
||||
];
|
||||
|
||||
$idStrs = [];
|
||||
for ($i = 0; $i < count($intermdiateIds); $i++) {
|
||||
$idStrs[] = ':id' . $i;
|
||||
$values['id' . $i] = $intermdiateIds[$i];
|
||||
}
|
||||
$sql .= implode(',', $idStrs);
|
||||
$sql .= ')';
|
||||
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $enrichData
|
||||
*/
|
||||
public function saveEnrichData(array $enrichData): void
|
||||
{
|
||||
foreach ($enrichData as $id => $data) {
|
||||
$sql =
|
||||
'UPDATE `datanorm_intermediate`
|
||||
SET
|
||||
`content` = :content,
|
||||
`hash` = :hash,
|
||||
`enrich` = :enrich
|
||||
WHERE `id` = :id';
|
||||
|
||||
$values = [
|
||||
'content' => $data['content'],
|
||||
'hash' => $data['hash'],
|
||||
'enrich' => $data['enrich'],
|
||||
'id' => $id,
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
}
|
||||
|
||||
public function setTAndDTypeDone(): void
|
||||
{
|
||||
$sql =
|
||||
'UPDATE `datanorm_intermediate`
|
||||
SET
|
||||
`doneFlag` = :done
|
||||
WHERE (`type` = \'T\' OR `type` = \'D\')
|
||||
AND `doneFlag` = 0';
|
||||
|
||||
$values = ['done' => true];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $vId
|
||||
* @param string $supplierNumber
|
||||
*/
|
||||
public function saveSupplierToVType(int $vId, string $supplierNumber)
|
||||
{
|
||||
$sql =
|
||||
'UPDATE `datanorm_intermediate`
|
||||
SET
|
||||
`supplier_address_id` =
|
||||
(
|
||||
SELECT a.id
|
||||
FROM `adresse` AS `a`
|
||||
WHERE a.lieferantennummer = :supplier_number
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE `id` = :v_id';
|
||||
|
||||
$values = ['v_id' => $vId, 'supplier_number' => $supplierNumber];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Datanorm\Service;
|
||||
|
||||
use Generator;
|
||||
use Xentral\Components\Filesystem\Exception\FileNotFoundException;
|
||||
use Xentral\Components\Filesystem\FilesystemInterface;
|
||||
use Xentral\Components\Filesystem\PathInfo;
|
||||
use Xentral\Modules\Datanorm\Data\DatanormTypeDataInterface;
|
||||
use Xentral\Modules\Datanorm\Exception\FileSystemException;
|
||||
use Xentral\Modules\Datanorm\Exception\InvalidLineException;
|
||||
use Xentral\Modules\Datanorm\Exception\NoAddressIdFoundException;
|
||||
use Xentral\Modules\Datanorm\Exception\WrongDiscountFormatException;
|
||||
use Xentral\Modules\Datanorm\Exception\WrongPriceFormatException;
|
||||
use Xentral\Modules\Datanorm\Exception\WrongVersionException;
|
||||
use Xentral\Modules\Datanorm\Handler\DatanormReaderHandlerInterface;
|
||||
|
||||
|
||||
final class DatanormReader
|
||||
{
|
||||
/** @var FilesystemInterface $filesystem */
|
||||
private $filesystem;
|
||||
|
||||
/** @var string $uploadDir */
|
||||
private $uploadDir;
|
||||
|
||||
/** @var DatanormReaderHandlerInterface[] $readerHandlers */
|
||||
private $readerHandlers;
|
||||
|
||||
/** @var int[] $readerVersions */
|
||||
private $readerVersions;
|
||||
|
||||
/** @var DatanormIntermediateService $intermediateService */
|
||||
private $intermediateService;
|
||||
|
||||
/**
|
||||
* @param FilesystemInterface $filesystem
|
||||
* @param DatanormIntermediateService $intermediateService
|
||||
* @param DatanormReaderHandlerInterface[] $readerHandlers
|
||||
* @param string $uploadDir Relative dir to filesystem-class root
|
||||
*/
|
||||
public function __construct(
|
||||
FilesystemInterface $filesystem,
|
||||
DatanormIntermediateService $intermediateService,
|
||||
array $readerHandlers,
|
||||
$uploadDir
|
||||
) {
|
||||
$this->filesystem = $filesystem;
|
||||
$this->uploadDir = $uploadDir;
|
||||
$this->readerHandlers = [];
|
||||
$this->intermediateService = $intermediateService;
|
||||
|
||||
foreach ($readerHandlers as $r) {
|
||||
$this->readerVersions[] = $r->getVersion();
|
||||
$this->readerHandlers[] = $r;
|
||||
}
|
||||
|
||||
if (!$filesystem->has($this->uploadDir)) {
|
||||
$filesystem->createDir($this->uploadDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PathInfo $file
|
||||
* @param int $limit
|
||||
* @param int $lastLineNumber
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
* @throws WrongVersionException
|
||||
* @throws InvalidLineException
|
||||
* @throws FileSystemException
|
||||
* @throws WrongPriceFormatException
|
||||
* @throws WrongDiscountFormatException
|
||||
* @throws NoAddressIdFoundException
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function read(PathInfo $file, int $limit, int $lastLineNumber): int
|
||||
{
|
||||
$iterator = $this->getFileIterator($file->getPath());
|
||||
$counter = 0;
|
||||
$nextLastLineNumber = $lastLineNumber + $limit;
|
||||
$intermediateEntries = [];
|
||||
$version = 0;
|
||||
|
||||
foreach ($iterator as $line) {
|
||||
if ($counter === 0) {
|
||||
$version = $this->getVersionByTypV($line);
|
||||
}
|
||||
|
||||
if ($counter >= $lastLineNumber && $counter < $nextLastLineNumber) {
|
||||
$type = $this->getLineType($line);
|
||||
$obj = $this->parseLine($line, $version);
|
||||
if (!empty($obj)) {
|
||||
$isEnrich = false;
|
||||
if ($type === 'A' || $type === 'P') {
|
||||
$isEnrich = $this->needsEnrichement($type, $obj, $version);
|
||||
} elseif ($type === 'E' && $version === 4) {
|
||||
$type = 'T';
|
||||
}
|
||||
|
||||
$articleNumber = '';
|
||||
if (method_exists($obj, 'getArticleNumber')) {
|
||||
$articleNumber = $obj->getArticleNumber();
|
||||
} elseif (method_exists($obj, 'getTextnumber')) {
|
||||
$articleNumber = $obj->getTextnumber();
|
||||
}
|
||||
|
||||
$intermediateEntries[] = [
|
||||
'fileName' => $file->getFilename(),
|
||||
'type' => $type,
|
||||
'obj' => $obj,
|
||||
'nummer' => $articleNumber,
|
||||
'enrich' => $isEnrich,
|
||||
'directory' => $file->getDir(),
|
||||
'user_address_id' => $this->getUserIdFromPath($file->getFilename()),
|
||||
];
|
||||
}
|
||||
}
|
||||
$counter++;
|
||||
}
|
||||
|
||||
if (count($intermediateEntries) > 0) {
|
||||
$this->intermediateService->writeMultiple($intermediateEntries);
|
||||
}
|
||||
|
||||
if ($nextLastLineNumber - $counter >= 0) {
|
||||
$isDeleted = $this->deleteFile($file->getPath());
|
||||
|
||||
if (!$isDeleted) {
|
||||
$scriptOwner = @posix_getpwuid(@fileowner(__FILE__));
|
||||
$scriptGroup = @posix_getgrgid(@filegroup(__FILE__));
|
||||
$phpUsername = get_current_user();
|
||||
|
||||
$msg =
|
||||
'Could not delete file: ' . $file->getPath() .
|
||||
', scriptowner: ' . $scriptOwner[0] .
|
||||
', scriptGroup: ' . $scriptGroup[0] .
|
||||
', phpUsername: ' . $phpUsername;
|
||||
|
||||
throw new FileSystemException($msg);
|
||||
}
|
||||
$nextLastLineNumber = -1;
|
||||
}
|
||||
|
||||
return $nextLastLineNumber;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getUserIdFromPath(string $fileName): int
|
||||
{
|
||||
$pos = strstr($fileName, '_', true);
|
||||
if (strstr($fileName, '_') === false) {
|
||||
throw new NoAddressIdFoundException('No user-id found in filename: ' . $fileName);
|
||||
} else {
|
||||
return (int)$pos;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $line
|
||||
* @param int $version
|
||||
*
|
||||
* @throws WrongVersionException
|
||||
* @throws WrongPriceFormatException
|
||||
* @throws WrongDiscountFormatException
|
||||
*
|
||||
* @return null|DatanormTypeDataInterface
|
||||
*/
|
||||
private function parseLine(string $line, int $version): ?DatanormTypeDataInterface
|
||||
{
|
||||
$readerHandler = $this->getReaderHandler($version);
|
||||
|
||||
$line = iconv('CP850', 'UTF-8', $line);
|
||||
|
||||
$obj = null;
|
||||
$type = $this->getLineType($line);
|
||||
switch ($type) {
|
||||
case 'A':
|
||||
$obj = $readerHandler->transformToTypeA($line);
|
||||
break;
|
||||
case'P':
|
||||
$obj = $readerHandler->transformToTypeP($line);
|
||||
break;
|
||||
case'V':
|
||||
$obj = $readerHandler->transformToTypeV($line);
|
||||
break;
|
||||
case'B':
|
||||
$obj = $readerHandler->transformToTypeB($line);
|
||||
break;
|
||||
case'E':
|
||||
if ($version === 4) {
|
||||
$obj = $readerHandler->transformToTypeT($line);
|
||||
}
|
||||
break;
|
||||
case'T':
|
||||
$obj = $readerHandler->transformToTypeT($line);
|
||||
break;
|
||||
case'D':
|
||||
$obj = $readerHandler->transformToTypeD($line);
|
||||
break;
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $version
|
||||
*
|
||||
* @throws WrongVersionException
|
||||
*
|
||||
* @return DatanormReaderHandlerInterface
|
||||
*/
|
||||
private function getReaderHandler(int $version): DatanormReaderHandlerInterface
|
||||
{
|
||||
$readerHandler = null;
|
||||
foreach ($this->readerHandlers as $r) {
|
||||
if ($r->getVersion() === $version) {
|
||||
$readerHandler = $r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($readerHandler)) {
|
||||
throw new WrongVersionException(
|
||||
'The DATANORM-Version is not supported. Only ' .
|
||||
implode(', ', $this->readerVersions) . ' are allowed. Requested version was: ' . $version
|
||||
);
|
||||
}
|
||||
|
||||
return $readerHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filePath Relative path to filesystem-class root
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
*
|
||||
* @return Generator
|
||||
*/
|
||||
private function getFileIterator(string $filePath): Generator
|
||||
{
|
||||
$stream = $this->filesystem->readStream($filePath);
|
||||
|
||||
while ($line = fgets($stream)) {
|
||||
yield $line;
|
||||
}
|
||||
|
||||
if (is_resource($stream)) {
|
||||
fclose($stream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $line
|
||||
*
|
||||
* @throws InvalidLineException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getLineType(string $line): string
|
||||
{
|
||||
$lineType = substr(trim($line), 0, 1);
|
||||
|
||||
if ($lineType === false || empty($lineType)) {
|
||||
throw new InvalidLineException('Unknown linetype in this line: ' . $line);
|
||||
}
|
||||
|
||||
return $lineType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $line
|
||||
*
|
||||
* @throws WrongVersionException
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getVersionByTypV(string $line): int
|
||||
{
|
||||
$v5indicator = false;
|
||||
$split = explode(';', $line);
|
||||
if (isset($split[1])) {
|
||||
$v5indicator = $split[1] === '050';
|
||||
}
|
||||
|
||||
$v4indicator = false;
|
||||
if (strlen($line) > 123) {
|
||||
$v4indicator = trim(substr($line, 123, 2)) === '04';
|
||||
}
|
||||
|
||||
|
||||
if ($v5indicator) {
|
||||
return 5;
|
||||
} elseif ($v4indicator) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
throw new WrongVersionException('DATANORM-Version not found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteFile(string $path): bool
|
||||
{
|
||||
return $this->filesystem->delete($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|PathInfo[]
|
||||
*/
|
||||
public function listUploadedDatanormFiles(): array
|
||||
{
|
||||
return $this->filesystem->listFiles($this->uploadDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param DatanormTypeDataInterface $object
|
||||
* @param int $version
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function needsEnrichement(string $type, DatanormTypeDataInterface $object, int $version): bool
|
||||
{
|
||||
if ($version === 4 && $type === 'P') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($type === 'A' && method_exists($object, 'getTextkey')) {
|
||||
$textFlag = '0';
|
||||
|
||||
if (!empty($object->getTextkey())) {
|
||||
$textFlag = substr($object->getTextkey(), 0, 1);
|
||||
}
|
||||
|
||||
if ($textFlag != '0') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user