d2d.emegrendeles.hu/app/Services/PriceListService.php
2026-03-08 06:46:54 +01:00

742 lines
26 KiB
PHP

<?php
namespace App\Services;
use App\Enums\BasicUnitEnum;
use App\Enums\DbStatusFieldEnum;
use App\Enums\ProductUnitEnum;
use App\Models\Product;
use App\Repositories\PriceListRepository;
use App\Repositories\PriceListRepositoryInterface;
use App\Repositories\ProducerRepository;
use App\Repositories\ProductRepository;
use App\Repositories\SupplierRepository;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
class PriceListService
{
protected PriceListRepository $PriceListRepository;
protected SupplierRepository $supplierRepository;
protected ProducerRepository $producerRepository;
protected ProductRepository $productRepository;
protected MessageBag $error;
public function __construct(PriceListRepositoryInterface $PriceListRepository)
{
$this->PriceListRepository = $PriceListRepository;
$this->error = new MessageBag;
}
/**
* Get's a record by it's ID
*
* @param int
*/
public function get($id): collection
{
return $this->PriceListRepository->get($id);
}
/**
* Get's all records.
*
* @return mixed
*/
public function all()
{
return $this->PriceListRepository->all();
}
/**
* Deletes a record.
*
* @param int
*/
public function delete($id)
{
return $this->PriceListRepository->delete($id);
}
/**
* Updates a post.
*
* @param int
* @param array
*/
public function update($id, array $data)
{
$this->PriceListRepository->update($id, $data);
}
public function getError()
{
return $this->error->toArray();
}
public function getExcelFieldPointer(): array
{
return $this->excelFieldPointer;
}
public const EXPECTED_HEADERS = [
0 => 'Szállítói cikkszám',
1 => 'Fő termékcsoport',
2 => 'Alcsoport 1',
3 => 'Alcsoport 2',
4 => 'Termék megnevezése',
5 => 'Kiszerelés',
6 => 'Súly/Űrtartalom (nettó)',
7 => 'Mértékegység',
8 => 'Gyártó',
9 => 'Legkisebb eladási egység',
10 => 'Egységszorzó',
11 => 'Mennyiségi egység',
12 => 'ÁFA %',
13 => 'Előző számlázási nettó ár/mennyiségi egység',
14 => 'Új számlázási nettó ár/mennyiségi egység',
15 => 'Áráltozás %',
16 => 'Fix Hooreyca ID',
17 => 'Hooreyca mértékegység',
18 => 'Hooreyca mennyiségi szorzó',
19 => 'Vevői megnevezés',
20 => 'Megjegyzés',
21 => 'KREL',
];
private array $excelFieldPointer = [
'supplierProductNumber' => 0,
'productGroupMain' => 1,
'productGroupSub1' => 2,
'productGroupSub2' => 3,
'name' => 4,
'packing' => 5,
'unitValue' => 6,
'productUnit' => 7,
'producerName' => 8,
'sellerUnit' => 9,
'unitMultiplier' => 10,
'amountUnit' => 11,
'vat' => 12,
'price' => 13,
'priceNew' => 14,
'priceChange' => 15,
'hooreycaId' => 16,
'HooreycaUnit' => 17,
'HooreycaMultiplier' => 18,
'buyerProductName' => 19,
'note' => 20,
'krel' => 21,
];
private array $excelFieldAcceptedType = [
'supplierProductNumber' => ['integer', 'string'], // 0
'productGroupMain' => ['string'], // 1
'productGroupSub1' => ['string'], // 2
'productGroupSub2' => ['string'], // 3
'name' => ['string'], // 4
'packing' => ['integer', 'double'], // 5
'unitValue' => ['integer', 'double'], // 6
'productUnit' => ['string', 'enum' => BasicUnitEnum::class], // 7
'producerName' => ['string'], // 8
'sellerUnit' => ['string', 'enum' => ProductUnitEnum::class], // 9
'unitMultiplier' => ['integer', 'double'], // 10
'amountUnit' => ['integer', 'string', 'enum' => ProductUnitEnum::class], // 11
'vat' => ['integer', 'string', 'double'], // 12
'price' => ['integer', 'string', 'double'], // 13
'priceNew' => ['integer', 'string', 'double'], // 14
'priceChange' => ['integer', 'string', 'double'], // 15
'hooreycaId' => ['integer', 'string'], // 16
'HooreycaUnit' => ['string'], // 17
'HooreycaMultiplier' => ['integer', 'double', 'string'], // 18
'buyerProductName' => ['string'], // 19
'note' => ['string'], // 20
'krel' => ['string'], // 21
];
private array $excelFieldConverter = [
'priceNew' => ['numberFormat', ['decimals' => 2]],
'priceChange' => ['percentage'],
'vat' => ['percentage'],
'note' => ['null'],
'krel' => ['booleanCustom'],
'hooreycaId' => ['null'],
'HooreycaUnit' => ['null'],
'HooreycaMultiplier' => ['null'],
];
private function convertBooleanCustom($value, $options)
{
if (strlen(trim($value)) > 0) {
return 1;
} else {
return 0;
}
}
private function convertNull($value, $options)
{
if (! is_null($value)) {
if ($value == 'null') {
$value = null;
} elseif (strlen($value.'') === 0) {
$value = null;
}
}
return $value;
}
private function convertPercentage($value, $options)
{
if (gettype($value) == 'string') {
$value = (float) $value;
}
if (! isset($options['multiplier']) || $options['multiplier'] == true) {
$value = $value * 100;
}
if (! isset($options['precision'])) {
$precision = 0;
}
return $this->convertNumberFormat($value, [
'decimals' => $precision,
]
);
}
private function convertNumberFormat($value, $options)
{
if (gettype($value) == 'string') {
$value = str_replace(',', '.', $value);
$value = str_replace(' ', '', $value);
}
$value = (float) $value;
$decimals = 0;
if (isset($options['decimals'])) {
$decimals = $options['decimals'];
}
$decimal_separator = '.';
if (isset($options['decimal_separator'])) {
$decimal_separator = $options['decimal_separator'];
}
$thousands_separator = '';
if (isset($options['thousands_separator'])) {
$thousands_separator = $options['thousands_separator'];
}
return number_format($value, $decimals, $decimal_separator, $thousands_separator);
}
private function convertRowData($data)
{
foreach ($data as $fieldName => $value) {
if (isset($this->excelFieldConverter[$fieldName])) {
$converterParameter = $this->excelFieldConverter[$fieldName];
$functionName = 'convert'.ucfirst($converterParameter[0]);
$arg = [];
if (isset($converterParameter[1])) {
$arg = $converterParameter[1];
}
$data[$fieldName] = call_user_func([$this, $functionName], $value, $arg);
// $this->['convert'.ucfirst($this->excelFieldConverter[$fieldName])]()
/* dd([
$fieldName,
$functionName,
$arg,
method_exists($this,$functionName),
$value,
$this->convertNumberFormat($value,$arg),
call_user_func(array($this, $functionName), $value,$arg)
]);*/
}
}
return $data;
}
private function checkExcelRowFieldType($data)
{
// dd($this->excelFieldAcceptedType[array_search('12',$this->excelFieldPointer)]);
$retArray = [];
foreach ($data as $key => $value) {
if ($key > max($this->excelFieldPointer)) {
break;
}
$fieldName = array_search($key, $this->excelFieldPointer);
try {
$acceptedType = $this->excelFieldAcceptedType[$fieldName];
} catch (\Exception $e) {
dd([
$data,
$key,
$value,
$this->excelFieldAcceptedType,
$this->excelFieldPointer,
$fieldName,
]);
}
if (! in_array(gettype($value), $acceptedType)) {
$retArray[$fieldName] = 'invalid Type '.var_export($acceptedType, true);
if (gettype($value) == 'object') {
$retArray[$fieldName] .= '['.gettype($value).'/'.get_class($value).']';
} else {
$retArray[$fieldName] .= '['.gettype($value).']';
}
$this->importableDataFile = false;
} else {
if (isset($acceptedType['enum'])) {
// dd($acceptedType['enum']);
if (! in_array($value, $acceptedType['enum']::getValues())) {
// dd([$value,$acceptedType['enum']::getValues()]);
$retArray[$fieldName] = 'Nem megfelelő érték.';
// $retArray[$key].='['.gettype($value).'/'.get_class($value).']';
}
}
}
}
if (count($retArray) > 0) {
return $retArray;
}
return false;
}
private function convertExcelRowToNamedArray($data)
{
$returnArray = [];
foreach ($data as $key => $value) {
if ($fieldName = array_search($key, $this->excelFieldPointer)) {
$returnArray[$fieldName] = $value;
} else {
$returnArray[$key] = $value;
}
}
return $returnArray;
}
private array $productGroupArray = [];
private function initGroupsArray()
{
// ellenorizni kell a csoportokat
$ProductGroup = new \App\Models\ProductGroup;
// $productGroupArray=$ProductGroup->allWithParents(2);
$this->productGroupArray = $ProductGroup->allWithPath(3);
// path szerint idexelni.
}
private function getProductGroupByName($mainGroupName, $subGroupName = null, $subGroup2Name = null)
{
// var_export($this->productGroupArray[4]);
// var_export(func_get_args());
$searchName = '';
if ($subGroup2Name) {
$searchName = $subGroup2Name;
} elseif ($subGroupName) {
$searchName = $subGroupName;
} else {
$searchName = $mainGroupName;
}
foreach ($this->productGroupArray as $key => $groupData) {
if ($groupData['name'] == $searchName) {
return $groupData;
}
}
return false;
}
public function checkProductUnit($name)
{
return \App\Enums\ProductUnitEnum::hasValue($name);
}
private array $rowData = [];
private function addRowFieldError($namedArrayErrors)
{
if (! isset($this->rowData['error']['fields'])) {
$this->rowData['error']['fields'] = $namedArrayErrors;
} else {
foreach ($namedArrayErrors as $key => $value) {
$this->rowData['error']['fields'][$key] = $value;
}
// $this->rowData['error']['fields']=array_merge($this->rowData['error']['fields'],$namedArrayErrors);
}
$this->rowData['status'] = 'error';
return $this->rowData;
}
private bool $importableDataFile = true;
public function importPriceListCheck($supplierId = null, $data = null)
{
if (! intval($supplierId) ||
$supplierId < 1
) {
$this->error->add('supplierId', 'Nem megfelelő beszállító');
return false;
}
$SupplierRepository = new SupplierRepository;
if (! $SupplierData = $SupplierRepository->get($supplierId)) {
$this->error->add('supplierId', 'Ismeretlen beszállító');
return false;
}
if (! $data || count($data) < 1) {
$this->error->add('priceListData', 'Nincsenek sorok');
return false;
}
if (count($data[array_key_first($data)]) > count($this->excelFieldPointer)) {
$this->error->add('priceListData', 'Túl sok oszlop. [max:'.count($this->excelFieldPointer).']');
return false;
}
$this->loadProducers('name');
$this->initGroupsArray();
$this->initProductRepository();
$fromLine = 370; // nincs 2-es alcsoportja 370
$fromLine = 6; // tizedes az arban
$fromLine = 0; // OK sor
// $fromLine=360; //nincs 2-es alcsoportja 370
$linesNum = 50;
$linesNum = 400;
$linesNum = 9999;
$data = array_splice($data, $fromLine, $linesNum);
$excelPointer = $this->excelFieldPointer;
$checkedData = [];
foreach ($data as $key => $itemData) {
$this->rowData = [
'rowNum' => $key + 1,
'status' => 'OK',
'originalData' => null,
'oldStoredData' => null,
'additionalData' => [],
'error' => [],
];
$this->rowData['originalData'] = $this->convertExcelRowToNamedArray($itemData);
$this->rowData['originalData']['supplier_id'] = $SupplierData['id'];
// Excel importnal lehetnek rossz a mezotipusok ezert ellenorizni kell
if ($fieldHasTypeError = $this->checkExcelRowFieldType($itemData)) {
$this->addRowFieldError($fieldHasTypeError);
$checkedData[] = $this->rowData;
continue;
} else {
// ha nem hibas a mezotipus akkoro koverteljuk
$this->rowData['originalData'] = $this->convertRowData($this->rowData['originalData']);
}
// Check product
/**
* PM108 supplierProductNumber required
*/
if (! $itemData[$this->excelFieldPointer['supplierProductNumber']]
|| strlen(preg_replace('/\s+/', '', $itemData[$this->excelFieldPointer['supplierProductNumber']])) < 1
) {
$this->addRowFieldError([$this->excelFieldPointer['supplierProductNumber'] => 'unknown value']);
}
/*$storedData=Product::where('supplier_id',$supplierId)
->where('supplierProductNumber',$itemData[$excelPointer['supplierProductNumber']])->get()->first();
*/
$storedData = $this->productRepository->getBySupplierAndSupplierProductNumber($supplierId, $itemData[$excelPointer['supplierProductNumber']], true);
if (! $storedData) {
// $this->rowData['error']=array_merge($this->rowData['error'],['all'=>'new Item']);
$this->rowData['status'] = 'new';
} else {
$this->rowData['oldStoredData'] = $storedData;
}
// productGroupData
if ($groupData = $this->getProductGroupByName($itemData[$this->excelFieldPointer['productGroupMain']],
$itemData[$this->excelFieldPointer['productGroupSub1']],
$itemData[$this->excelFieldPointer['productGroupSub2']]
)) {
$this->rowData['additionalData']['groupData'] = $groupData;
$this->rowData['originalData']['product_group_id'] = $groupData['id'];
} else {
// nem talaltuk meg a csoporot
$this->addRowFieldError([$this->excelFieldPointer['productGroupSub2'] => 'invalid group']);
// $this->rowData['error']['fields'][$this->excelFieldPointer['productGroupSub2']]='invalid group';
$this->importableDataFile = false;
}
// producerData
if ($producerData = $this->getProducerByName($itemData[$this->excelFieldPointer['producerName']])) {
$this->rowData['additionalData']['producerData'] = $producerData;
$this->rowData['originalData']['producer_id'] = $producerData['id'];
}
// productUnit
if (! $this->checkProductUnit($itemData[$this->excelFieldPointer['productUnit']])) {
$this->addRowFieldError([$this->excelFieldPointer['productUnit'] => 'unknown productUnit']);
// dd($this->rowData);
}
// PM159 check horreycadata
if ($this->rowData['originalData']['hooreycaId'] != null) {
if ($this->rowData['originalData']['HooreycaUnit'] == null) {
$this->addRowFieldError([$this->excelFieldPointer['HooreycaUnit'] => 'unknown value']);
}
if ($this->rowData['originalData']['HooreycaMultiplier'] == null) {
$this->addRowFieldError([$this->excelFieldPointer['HooreycaMultiplier'] => 'unknown value']);
}
}
if (count($this->rowData['error']) < 1) {
/*todo:ha van akkor ellenorizni kella fobb adatinak valtozasa, meg el kell menteni a kulombsegeket a historyba
*/
if ($this->rowData['status'] != 'new') {
$changed = $this->productRepository->checkIsChanged($this->rowData['oldStoredData']['id'], $this->rowData['originalData']);
if (count($changed) > 0) {
// var_dump($changed);
if (isset($changed['error'])) {
$this->rowData['error'] = $changed['error'];
$this->rowData['status'] = 'error';
} else {
$this->rowData['changed'] = $changed;
$this->rowData['status'] = 'changed';
}
}
}
} else {
// indexeljuk a nevekkel a hibalistat
if (isset($this->rowData['error']['fields']) && count($this->rowData['error']['fields']) > 0) {
$this->rowData['error']['fields'] = $this->convertExcelRowToNamedArray($this->rowData['error']['fields']);
}
}
// dd($this->rowData);
// dd($this->rowData['oldStoredData']);
$checkedData[] = $this->rowData;
// return [$retData];
// return [$key,$retData];
}
return [
'importableFile' => $this->importableDataFile,
'rows' => $checkedData,
];
return $data;
}
private ?array $producers = null;
private ?string $producerIndexedBy = null;
private function loadProducers(?string $index = null)
{
$this->initProducerRepository();
if (! $index) {
$this->producerIndexedBy = 'id';
} else {
$this->producerIndexedBy = $index;
}
$this->producers = $this->producerRepository->allByIndex($index);
}
private function getProducerByName($name)
{
$this->initProducerRepository();
if (isset($this->producers[$name])) {
return $this->producers[$name];
}
return false;
}
private function initProducerRepository()
{
if (! isset($this->producerRepository)) {
$this->producerRepository = new ProducerRepository;
}
}
private function addNewProducer($data)
{
$this->initProducerRepository();
$data['canSee'] = 1;
$data['status'] = \App\Enums\DbStatusFieldEnum::active;
if ($id = $this->producerRepository->add($data)) {
return $id;
}
return false;
}
public function updateProductData($id, array $changedData)
{
return $this->productRepository->update($id, $changedData);
}
public function importPriceList($supplierId = null, $availableDate = null, $data = null, $otherField = [])
{
if (false === $priceListData = $this->importPriceListCheck($supplierId, $data)) {
return false;
}
if ($priceListData['importableFile'] == false) {
return false;
}
$newPriceListData = [];
$newPriceListData['supplier_id'] = $supplierId;
$newPriceListData['canSee'] = 1;
$newPriceListData['available'] = $availableDate;
$newPriceListData['status'] = DbStatusFieldEnum::draft;
if (isset($otherField['note'])) {
$newPriceListData['note'] = $otherField['note'];
}
$priceListId = $this->PriceListRepository->add($newPriceListData);
$priceListData['importSuccess'] = false;
$priceListData['id'] = $priceListId;
$affectedProductIds = [];
foreach ($priceListData['rows'] as $key => $rowData) {
if (! isset($rowData['additionalData']['producerData'])) {
// dd($rowData);
if (! $producerData = $this->getProducerByName($rowData['originalData']['producerName'])) {
if ($producerId = $this->addNewProducer(['name' => $rowData['originalData']['producerName']])) {
$this->loadProducers('name');
$producerData = $this->producerRepository->get($producerId);
} else {
// nem lett felveve a producer
}
}
if ($rowData['status'] !== 'new') {
$rowData['status'] = 'changed';
if (! isset($rowData['changed'])) {
$rowData['changed'] = [];
}
$old_producer_id = null;
if (isset($rowData['oldStoredData']['producer_id'])) {
$old_producer_id = $rowData['oldStoredData']['producer_id'];
}
$rowData['changed']['producer_id'] = [
'old' => $old_producer_id,
'new' => $producerData['id'],
];
}
$rowData['additionalData']['producerData'] = $producerData;
}
$fromOriginalData = [
'name',
'packing',
'unitValue',
'productUnit',
'sellerUnit',
'unitMultiplier',
'amountUnit',
'vat',
'supplierProductNumber',
'hooreycaId',
'HooreycaUnit',
'HooreycaMultiplier',
'buyerProductName',
'note',
'krel',
];
$productData = [];
foreach ($fromOriginalData as $pointer) {
if (! array_key_exists($pointer, $rowData['originalData'])) {
// debug(__CLASS__.__LINE__,$pointer,$rowData['originalData'],$rowData);
// dd(__CLASS__.__LINE__,$pointer,$rowData['originalData'],$rowData);
} else {
$productData[$pointer] = $rowData['originalData'][$pointer];
}
}
$productData['supplier_id'] = $supplierId;
$productData['producer_id'] = $rowData['additionalData']['producerData']['id'];
/* if(!array_key_exists('groupData',$rowData['additionalData'])) {
dd(__CLASS__.__LINE__,$rowData);
}*/
$productData['product_group_id'] = $rowData['additionalData']['groupData']['id'];
$productData['type'] = $rowData['additionalData']['groupData']['type'];
// dd($productData,$rowData);
if ($rowData['status'] == 'changed') {
$this->updateProductData($rowData['oldStoredData']['id'], $productData);
}
if ($rowData['status'] == 'new') {
// fel kell venni az uj tetelt
$productData['id'] = $this->addNewProduct($productData);
if ($productData['id'] !== null) {
// ár elmenteése a termékhez
$this->PriceListRepository->attachProduct($productData['id'], $rowData['originalData']['priceNew'], $priceListId);
} else {
// hibat hozzaadni!
}
}// elseif($rowData['status']=='OK'){
else {
$this->PriceListRepository->attachProduct($rowData['oldStoredData']['id'], $rowData['originalData']['priceNew'], $priceListId);
}
if (isset($productData['id'])) {
$affectedProductIds[] = $productData['id'];
} else {
$affectedProductIds[] = $rowData['oldStoredData']['id'];
}
}
$this->PriceListRepository->update($priceListId, ['status' => DbStatusFieldEnum::active]);
$this->updateProductVisibilities($affectedProductIds);
$priceListData['importSuccess'] = true;
return $priceListData;
}
private function updateProductVisibilities($productIds)
{
$this->initProductRepository();
return $this->productRepository->updateVisibilitiesByIds($productIds);
}
private function initProductRepository()
{
if (! isset($this->productRepository)) {
$this->productRepository = new ProductRepository;
}
}
private function addNewProduct($productData): ?int
{
$this->initProductRepository();
$productData['canSee'] = 1;
$productData['status'] = \App\Enums\DbStatusFieldEnum::active;
return $this->productRepository->add($productData);
}
}