This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
namespace App\Command;
|
||||
|
||||
use App\Helper\HiltesImport;
|
||||
use App\Repository\StockRepository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
@@ -19,6 +21,14 @@ use Symfony\Component\Finder\Finder;
|
||||
)]
|
||||
class HiltesImportCommand extends Command
|
||||
{
|
||||
private $stockRepository;
|
||||
private $logger;
|
||||
public function __construct(StockRepository $stockRepository, LoggerInterface $logger)
|
||||
{
|
||||
$this->stockRepository = $stockRepository;
|
||||
$this->logger = $logger;
|
||||
parent::__construct();
|
||||
}
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
@@ -38,12 +48,12 @@ class HiltesImportCommand extends Command
|
||||
/**
|
||||
* @var HiltesImport
|
||||
*/
|
||||
$hiltesImport = new HiltesImport();
|
||||
$hiltesImport = new HiltesImport($this->stockRepository,$this->logger);
|
||||
|
||||
$hiltesImport->startImport();
|
||||
|
||||
|
||||
$io->success('You have a new command! Now make it your own! Pass --help to see your options.');
|
||||
$io->success('Done.');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Command;
|
||||
|
||||
use App\Controller\ShopwareController;
|
||||
use App\Entity\Orders;
|
||||
use App\Helper\Shopware;
|
||||
use App\Repository\OrdersRepository;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
@@ -33,6 +34,7 @@ class SwGetOrdersCommand extends Command
|
||||
{
|
||||
private $ordersRepository;
|
||||
private $logger;
|
||||
private $sw;
|
||||
private $orderData;
|
||||
|
||||
|
||||
@@ -40,6 +42,7 @@ class SwGetOrdersCommand extends Command
|
||||
{
|
||||
$this->ordersRepository = $ordersRepository;
|
||||
$this->logger = $logger;
|
||||
$this->sw = new Shopware();
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
@@ -88,6 +91,7 @@ class SwGetOrdersCommand extends Command
|
||||
public function getOrderDetails(): void
|
||||
{
|
||||
//Bestelldetails aus SW holen
|
||||
|
||||
$this->getOrdersDataFromSW();
|
||||
|
||||
foreach ($this->orderData as $order) {
|
||||
@@ -95,47 +99,16 @@ class SwGetOrdersCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Vin\ShopwareSdk\Data\AccessToken|void
|
||||
*/
|
||||
private function shopwareAuth()
|
||||
{
|
||||
|
||||
try {
|
||||
$grantType = new ClientCredentialsGrantType($_ENV['SHOPWARE_API_ID'], $_ENV['SHOPWARE_API_KEY']);
|
||||
$adminClient = new AdminAuthenticator($grantType, $_ENV['SHOPWARE_API_URL']);
|
||||
return $adminClient->fetchAccessToken();
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* holt alle fehlende Bestelldetails aus SW
|
||||
*/
|
||||
private function getOrdersDataFromSW(): void
|
||||
{
|
||||
|
||||
foreach ($this->orderData as $value) {
|
||||
// Bei Shopware API anmelden
|
||||
$context = new Context($_ENV['SHOPWARE_API_URL'], $this->shopwareAuth());
|
||||
|
||||
// Create the repository for the entity
|
||||
$orderRepository = RepositoryFactory::create(OrderDefinition::ENTITY_NAME);
|
||||
|
||||
// Create the criteria
|
||||
$criteria = new Criteria();
|
||||
$criteria->addFilter(new EqualsFilter('id', $value->getOrderId()));
|
||||
|
||||
//Beziehungen zu Produkten holen
|
||||
$criteria->addAssociation('lineItems');
|
||||
|
||||
try {
|
||||
$orders = $orderRepository->search($criteria, $context);
|
||||
|
||||
$value->setData((array)$orders->getEntities());
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
}
|
||||
$value->setData((array)$this->sw->getOrders($value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
69
src/Command/SwPushStockCommand.php
Normal file
69
src/Command/SwPushStockCommand.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Repository\StockRepository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'sw:push-stock',
|
||||
description: 'Übermittelt den Bestand an Shopware',
|
||||
)]
|
||||
class SwPushStockCommand extends Command
|
||||
{
|
||||
|
||||
private $stockRepository;
|
||||
private $logger;
|
||||
|
||||
public function __construct(StockRepository $stockRepository, LoggerInterface $logger)
|
||||
{
|
||||
$this->stockRepository = $stockRepository;
|
||||
$this->logger = $logger;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
// $arg1 = $input->getArgument('arg1');
|
||||
|
||||
// if ($arg1) {
|
||||
// $io->note(sprintf('You passed an argument: %s', $arg1));
|
||||
// }
|
||||
//
|
||||
// if ($input->getOption('option1')) {
|
||||
// // ...
|
||||
// }
|
||||
|
||||
$stock = $this->getStock();
|
||||
|
||||
if($stock){
|
||||
|
||||
}
|
||||
|
||||
dump($stock);
|
||||
|
||||
$io->success('Done.');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
public function getStock(){
|
||||
return $this->stockRepository->findAll();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
76
src/Entity/Products.php
Normal file
76
src/Entity/Products.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\ProductsRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: ProductsRepository::class)]
|
||||
class Products
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: Types::GUID, nullable: true)]
|
||||
private ?string $shopware_id = null;
|
||||
|
||||
#[ORM\OneToMany(mappedBy: 'prod_id', targetEntity: Stock::class)]
|
||||
private Collection $stocks;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->stocks = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getShopwareId(): ?string
|
||||
{
|
||||
return $this->shopware_id;
|
||||
}
|
||||
|
||||
public function setShopwareId(?string $shopware_id): self
|
||||
{
|
||||
$this->shopware_id = $shopware_id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Stock>
|
||||
*/
|
||||
public function getStocks(): Collection
|
||||
{
|
||||
return $this->stocks;
|
||||
}
|
||||
|
||||
public function addStock(Stock $stock): self
|
||||
{
|
||||
if (!$this->stocks->contains($stock)) {
|
||||
$this->stocks->add($stock);
|
||||
$stock->setProdId($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeStock(Stock $stock): self
|
||||
{
|
||||
if ($this->stocks->removeElement($stock)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($stock->getProdId() === $this) {
|
||||
$stock->setProdId(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ class Stock
|
||||
private $id;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255)]
|
||||
private $product_id;
|
||||
private $gtin;
|
||||
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private $stock;
|
||||
@@ -25,19 +25,22 @@ class Stock
|
||||
#[ORM\ManyToOne(targetEntity: Warehouse::class, inversedBy: 'warehouse_id')]
|
||||
private $warehouse_id;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'stocks')]
|
||||
private ?Products $prod_id = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getProductId(): ?string
|
||||
public function getGtin(): ?string
|
||||
{
|
||||
return $this->product_id;
|
||||
return $this->gtin;
|
||||
}
|
||||
|
||||
public function setProductId(string $product_id): self
|
||||
public function setGtin(string $gtin): self
|
||||
{
|
||||
$this->product_id = $product_id;
|
||||
$this->gtin = $gtin;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -77,4 +80,16 @@ class Stock
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProdId(): ?Products
|
||||
{
|
||||
return $this->prod_id;
|
||||
}
|
||||
|
||||
public function setProdId(?Products $prod_id): self
|
||||
{
|
||||
$this->prod_id = $prod_id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,24 @@
|
||||
namespace App\Helper;
|
||||
|
||||
|
||||
use App\Entity\Stock;
|
||||
use App\Repository\StockRepository;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
class HiltesImport
|
||||
{
|
||||
private $stockRepository;
|
||||
private $logger;
|
||||
protected $currentDirPath;
|
||||
protected $arrData = array();
|
||||
|
||||
public function __construct()
|
||||
public function __construct(StockRepository $stockRepository, LoggerInterface $logger)
|
||||
{
|
||||
$this->stockRepository = $stockRepository;
|
||||
$this->logger = $logger;
|
||||
|
||||
$this->currentDirPath = getcwd();
|
||||
}
|
||||
|
||||
@@ -76,25 +85,23 @@ class HiltesImport
|
||||
$file = new \SplFileObject($srcFile);
|
||||
# dump(memory_get_usage()-$t);
|
||||
|
||||
dump($file->getRealPath());
|
||||
|
||||
$c = 0;
|
||||
while (!$file->eof()) {
|
||||
$c++;
|
||||
// Header überspringen
|
||||
if($c == 1){ continue; }
|
||||
|
||||
#*** Convertiert die Zeile in UTF8
|
||||
$str = iconv('ISO-8859-1','UTF-8',$file->fgets());
|
||||
//$str = iconv('ISO-8859-1','UTF-8',$file->fgets());
|
||||
|
||||
#*** Zerlegt die Zeile **********
|
||||
$arr = $this->splitLine($str);
|
||||
$arr = $this->splitLine($file->fgets());
|
||||
$this->switchSaveData($arr);
|
||||
#
|
||||
#dump('-----------------------');
|
||||
#dump($str);
|
||||
#dump($arr);
|
||||
$c++;
|
||||
# if($c>=50){
|
||||
# dump(memory_get_usage()-$t);
|
||||
# die();
|
||||
# }
|
||||
}
|
||||
# dump(memory_get_usage()-$t);
|
||||
# die();
|
||||
|
||||
dump($c . ' Datensätze importiert');
|
||||
}
|
||||
protected function splitLine($str){
|
||||
return str_getcsv($str,';','"');
|
||||
@@ -111,51 +118,54 @@ class HiltesImport
|
||||
#*** Leerzeichen löschen bei den einzelnen Einträgen **********
|
||||
$this->trimArray($arr);
|
||||
#***
|
||||
$arr[0] = strtolower($arr[0]);
|
||||
switch ($arr[0]){
|
||||
case 'datei': # Datei
|
||||
$this->saveInfoDatei($arr);
|
||||
break;
|
||||
case 'filiale': # Filiale
|
||||
#$this->saveInfoFiliale($arr);
|
||||
break;
|
||||
case 'land': # Länder
|
||||
$this->saveInfoLand($arr);
|
||||
break;
|
||||
case 'hwg': # Hauptwarengruppe
|
||||
#$this->saveInfoHauptWarenGruppe($arr);
|
||||
break;
|
||||
case 'wg': # Warengruppe
|
||||
#$this->saveInfoWarenGruppe($arr);
|
||||
break;
|
||||
case 'anrede': # Anrede
|
||||
#$this->saveInfoAnrede($arr);
|
||||
break;
|
||||
case 'lieferant': # Lieferant
|
||||
#$this->saveInfoLieferant($arr);
|
||||
break;
|
||||
case 'farb': # Farbcodierung
|
||||
#$this->saveInfoFarbCodierung($arr);
|
||||
break;
|
||||
case 'nlart': # NachlassArt
|
||||
#$this->saveInfoNachlassArt($arr);
|
||||
break;
|
||||
case 'kollektion': # Kollektion
|
||||
#$this->saveInfoKollektion($arr);
|
||||
break;
|
||||
case 'bestand': # Bestand
|
||||
#$this->saveInfoBestand($arr);
|
||||
break;
|
||||
case 'merkmale': # Made In XXXX = Land
|
||||
#$this->saveInfoMerkmale($arr);
|
||||
break;
|
||||
case 'material': # MAterial
|
||||
#$this->saveInfoMaterial($arr);
|
||||
break;
|
||||
default: #
|
||||
dump('!!!!! KEIN DEFINIERTER ANFANG "'.$arr[0].'" !!!!!!!!!');
|
||||
break;
|
||||
}
|
||||
// $arr[0] = strtolower($arr[0]);
|
||||
// switch ($arr[0]){
|
||||
// case 'datei': # Datei
|
||||
// $this->saveInfoDatei($arr);
|
||||
// break;
|
||||
// case 'filiale': # Filiale
|
||||
// #$this->saveInfoFiliale($arr);
|
||||
// break;
|
||||
// case 'land': # Länder
|
||||
// $this->saveInfoLand($arr);
|
||||
// break;
|
||||
// case 'hwg': # Hauptwarengruppe
|
||||
// #$this->saveInfoHauptWarenGruppe($arr);
|
||||
// break;
|
||||
// case 'wg': # Warengruppe
|
||||
// #$this->saveInfoWarenGruppe($arr);
|
||||
// break;
|
||||
// case 'anrede': # Anrede
|
||||
// #$this->saveInfoAnrede($arr);
|
||||
// break;
|
||||
// case 'lieferant': # Lieferant
|
||||
// #$this->saveInfoLieferant($arr);
|
||||
// break;
|
||||
// case 'farb': # Farbcodierung
|
||||
// #$this->saveInfoFarbCodierung($arr);
|
||||
// break;
|
||||
// case 'nlart': # NachlassArt
|
||||
// #$this->saveInfoNachlassArt($arr);
|
||||
// break;
|
||||
// case 'kollektion': # Kollektion
|
||||
// #$this->saveInfoKollektion($arr);
|
||||
// break;
|
||||
// case 'bestand': # Bestand
|
||||
// #$this->saveInfoBestand($arr);
|
||||
// break;
|
||||
// case 'merkmale': # Made In XXXX = Land
|
||||
// #$this->saveInfoMerkmale($arr);
|
||||
// break;
|
||||
// case 'material': # MAterial
|
||||
// #$this->saveInfoMaterial($arr);
|
||||
// break;
|
||||
// default: #
|
||||
// dump('!!!!! KEIN DEFINIERTER ANFANG "'.$arr[0].'" !!!!!!!!!');
|
||||
// break;
|
||||
// }
|
||||
|
||||
$this->saveData($arr);
|
||||
|
||||
}
|
||||
}
|
||||
protected function trimArray(Array &$arr){
|
||||
@@ -166,10 +176,29 @@ class HiltesImport
|
||||
protected function saveInfoDatei(Array $arr){
|
||||
|
||||
}
|
||||
protected function saveInfoLand(Array $arr){
|
||||
protected function saveData(Array $arr){
|
||||
#dump($arr);
|
||||
$stock = new Stock();
|
||||
|
||||
#menge;
|
||||
$stock->setStock((int)$arr[2]);
|
||||
|
||||
#filiale;
|
||||
//$stock->setWarehouseId((int)$arr[0]);
|
||||
|
||||
#gtin;
|
||||
$stock->setGtin($arr[1]);
|
||||
|
||||
|
||||
//ump($stock);
|
||||
|
||||
try{
|
||||
$this->stockRepository->upsert($stock);
|
||||
}catch (\Exception $e){
|
||||
dump($e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
dd($arr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
76
src/Helper/Shopware.php
Normal file
76
src/Helper/Shopware.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helper;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Vin\ShopwareSdk\Client\AdminAuthenticator;
|
||||
use Vin\ShopwareSdk\Client\GrantType\ClientCredentialsGrantType;
|
||||
use Vin\ShopwareSdk\Data\Context;
|
||||
use Vin\ShopwareSdk\Data\Criteria;
|
||||
use Vin\ShopwareSdk\Data\Entity\Order\OrderDefinition;
|
||||
use Vin\ShopwareSdk\Data\Filter\EqualsFilter;
|
||||
use Vin\ShopwareSdk\Factory\RepositoryFactory;
|
||||
|
||||
class Shopware
|
||||
{
|
||||
private $logger;
|
||||
public function __construct(LoggerInterface $logger)
|
||||
{
|
||||
|
||||
$this->logger = $logger;
|
||||
|
||||
//parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Anmeldung bei der Shopwar API
|
||||
* @return \Vin\ShopwareSdk\Data\AccessToken|void
|
||||
*/
|
||||
public function shopwareAuth()
|
||||
{
|
||||
|
||||
try {
|
||||
$grantType = new ClientCredentialsGrantType($_ENV['SHOPWARE_API_ID'], $_ENV['SHOPWARE_API_KEY']);
|
||||
$adminClient = new AdminAuthenticator($grantType, $_ENV['SHOPWARE_API_URL']);
|
||||
return $adminClient->fetchAccessToken();
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $orderId
|
||||
* @return OrderDefinition
|
||||
*/
|
||||
public function getOrders(string $orderId):OrderDefinition{
|
||||
$context = new Context($_ENV['SHOPWARE_API_URL'], $this->shopwareAuth());
|
||||
|
||||
// Create the repository for the entity
|
||||
$orderRepository = RepositoryFactory::create(OrderDefinition::ENTITY_NAME);
|
||||
|
||||
// Create the criteria
|
||||
$criteria = new Criteria();
|
||||
$criteria->addFilter(new EqualsFilter('id', $orderId));
|
||||
|
||||
//Beziehungen zu Produkten holen
|
||||
$criteria->addAssociation('lineItems');
|
||||
|
||||
try {
|
||||
$orders = $orderRepository->search($criteria, $context);
|
||||
return $orders->getEntities();
|
||||
//$value->setData((array)$orders->getEntities());
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function setProduct(){
|
||||
$context = new Context($_ENV['SHOPWARE_API_URL'], $this->shopwareAuth());
|
||||
|
||||
$productRepository = RepositoryFactory::create(ProductDefinition::ENTITY_NAME);
|
||||
|
||||
$productRepository->update();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,44 @@ class StockRepository extends ServiceEntityRepository
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Stock $entity
|
||||
* @param int $id
|
||||
* @return void
|
||||
*/
|
||||
public function update(Stock $entity, string $id): void
|
||||
{
|
||||
|
||||
$stock = $this->getEntityManager()->getRepository(Stock::class)->find($id);
|
||||
|
||||
if (!$stock) {
|
||||
throw $this->createNotFoundException(
|
||||
'No product found for id '.$id
|
||||
);
|
||||
}
|
||||
|
||||
$stock->setStock($entity->getStock());
|
||||
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Stock $entity
|
||||
* @return void
|
||||
*/
|
||||
public function upsert(Stock $entity): void
|
||||
{
|
||||
$stock = $this->findByGtin($entity->getGtin());
|
||||
|
||||
if ($stock) {
|
||||
// $stock->setStock($entity->getStock());
|
||||
// $this->getEntityManager()->flush();
|
||||
$this->update($entity,$stock[0]->getId());
|
||||
}else{
|
||||
$this->add($entity,true);
|
||||
}
|
||||
}
|
||||
|
||||
public function remove(Stock $entity, bool $flush = false): void
|
||||
{
|
||||
$this->getEntityManager()->remove($entity);
|
||||
@@ -39,20 +77,23 @@ class StockRepository extends ServiceEntityRepository
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return Stock[] Returns an array of Stock objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('s')
|
||||
// ->andWhere('s.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('s.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
/**
|
||||
* @return Stock[] Returns an array of Stock objects
|
||||
*/
|
||||
public function findByGtin($value): array
|
||||
{
|
||||
return $this->createQueryBuilder('s')
|
||||
->andWhere('s.gtin = :val')
|
||||
->setParameter('val', $value)
|
||||
->orderBy('s.id', 'ASC')
|
||||
->setMaxResults(1)
|
||||
->getQuery()
|
||||
->getResult()
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// public function findOneBySomeField($value): ?Stock
|
||||
// {
|
||||
|
||||
Reference in New Issue
Block a user