... | ... |
@@ -23,6 +23,8 @@ |
23 | 23 |
"symfony/config": "^5.4 || ^6.4", |
24 | 24 |
"symfony/dependency-injection": "^5.4 || ^6.4", |
25 | 25 |
"symfony/http-kernel": "^5.4 || ^6.4", |
26 |
+ "symfony/serializer": "^5.4 || ^6.4", |
|
27 |
+ "symfony/property-access": "^5.4 || ^6.4", |
|
26 | 28 |
"vonrotenberg/shopware-api-bundle": "dev-master" |
27 | 29 |
}, |
28 | 30 |
"require-dev": { |
... | ... |
@@ -69,6 +71,10 @@ |
69 | 71 |
"unit-tests": "@php vendor/bin/phpunit --colors=always" |
70 | 72 |
}, |
71 | 73 |
"repositories": { |
74 |
+ "shopware-repo": { |
|
75 |
+ "type": "path", |
|
76 |
+ "url": "C:\\Work\\PhpstormProjects\\vonRotenberg\\contao-shopware-api-bundle" |
|
77 |
+ }, |
|
72 | 78 |
"vonrotenberg": { |
73 | 79 |
"type": "composer", |
74 | 80 |
"url": "https://satis.esales-media.de" |
... | ... |
@@ -7,3 +7,9 @@ services: |
7 | 7 |
vonRotenberg\WmfgoCevisioBundle\: |
8 | 8 |
resource: ../src |
9 | 9 |
exclude: ../src/{VonrotenbergWmfgoCevisioBundle.php,ContaoManager,Entity,Migrations,Model,Resources,Tests,Widget} |
10 |
+ |
|
11 |
+ Symfony\Component\Finder\Finder: |
|
12 |
+ shared: false |
|
13 |
+ |
|
14 |
+ vonRotenberg\WmfgoCevisioBundle\Cron\ShopwareImportProductsJob: |
|
15 |
+ public: true |
10 | 16 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,61 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+declare(strict_types=1); |
|
4 |
+ |
|
5 |
+/* |
|
6 |
+ * This file is part of vonRotenberg WMFGO Cevisio Bundle. |
|
7 |
+ * |
|
8 |
+ * (c) vonRotenberg |
|
9 |
+ * |
|
10 |
+ * @license proprietary |
|
11 |
+ */ |
|
12 |
+ |
|
13 |
+namespace vonRotenberg\WmfgoCevisioBundle\Command; |
|
14 |
+ |
|
15 |
+use Contao\CoreBundle\Framework\ContaoFramework; |
|
16 |
+use Contao\System; |
|
17 |
+use Symfony\Component\Console\Command\Command; |
|
18 |
+use Symfony\Component\Console\Input\InputInterface; |
|
19 |
+use Symfony\Component\Console\Output\OutputInterface; |
|
20 |
+use Symfony\Component\Console\Style\SymfonyStyle; |
|
21 |
+use vonRotenberg\WmfgoCevisioBundle\Cron\ShopwareImportProductsJob; |
|
22 |
+ |
|
23 |
+class ShopwareImportProductsCommand extends Command |
|
24 |
+{ |
|
25 |
+ protected static $defaultName = 'shopware:import-products'; |
|
26 |
+ |
|
27 |
+ /** |
|
28 |
+ * @var ContaoFramework |
|
29 |
+ */ |
|
30 |
+ private $framework; |
|
31 |
+ |
|
32 |
+ public function __construct(ContaoFramework $framework) |
|
33 |
+ { |
|
34 |
+ $this->framework = $framework; |
|
35 |
+ |
|
36 |
+ parent::__construct(); |
|
37 |
+ } |
|
38 |
+ |
|
39 |
+ protected function configure(): void |
|
40 |
+ { |
|
41 |
+ $this |
|
42 |
+ ->setName(self::$defaultName) |
|
43 |
+ ->setDescription('Import products in Shopware instance') |
|
44 |
+ ; |
|
45 |
+ } |
|
46 |
+ |
|
47 |
+ protected function execute(InputInterface $input, OutputInterface $output): int |
|
48 |
+ { |
|
49 |
+ $this->framework->initialize(); |
|
50 |
+ |
|
51 |
+ $io = new SymfonyStyle($input, $output); |
|
52 |
+ $io->title('Product import to Shopware'); |
|
53 |
+ |
|
54 |
+ /** @var ShopwareImportProductsJob $import */ |
|
55 |
+ $import = System::getContainer()->get(ShopwareImportProductsJob::class); |
|
56 |
+ |
|
57 |
+ $import->import('cli', $io); |
|
58 |
+ |
|
59 |
+ return 0; |
|
60 |
+ } |
|
61 |
+} |
0 | 62 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,135 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+declare(strict_types=1); |
|
4 |
+ |
|
5 |
+/* |
|
6 |
+ * This file is part of vonRotenberg WMFGO Cevisio Bundle. |
|
7 |
+ * |
|
8 |
+ * (c) vonRotenberg |
|
9 |
+ * |
|
10 |
+ * @license proprietary |
|
11 |
+ */ |
|
12 |
+ |
|
13 |
+namespace vonRotenberg\WmfgoCevisioBundle\Cron; |
|
14 |
+ |
|
15 |
+use Contao\CoreBundle\Controller\AbstractController; |
|
16 |
+use Contao\Date; |
|
17 |
+use Contao\System; |
|
18 |
+use Doctrine\DBAL\Connection; |
|
19 |
+use Psr\Log\LoggerInterface; |
|
20 |
+use Symfony\Component\Console\Helper\ProgressBar; |
|
21 |
+use Symfony\Component\Console\Output\ConsoleOutput; |
|
22 |
+use Symfony\Component\Console\Style\SymfonyStyle; |
|
23 |
+use Symfony\Component\Finder\Finder; |
|
24 |
+use Symfony\Component\Serializer\Encoder\CsvEncoder; |
|
25 |
+use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; |
|
26 |
+use Symfony\Component\Serializer\Serializer; |
|
27 |
+use Symfony\Component\Serializer\SerializerInterface; |
|
28 |
+use vonRotenberg\ShopwareApiBundle\API\Shopware; |
|
29 |
+use vonRotenberg\WmfgoCevisioBundle\Model\Import\ProductModel; |
|
30 |
+ |
|
31 |
+class ShopwareImportProductsJob extends AbstractController |
|
32 |
+{ |
|
33 |
+ /** @var LoggerInterface */ |
|
34 |
+ private $logger; |
|
35 |
+ |
|
36 |
+ /** @var SerializerInterface */ |
|
37 |
+ private $serializer; |
|
38 |
+ |
|
39 |
+ /** @var SerializerInterface */ |
|
40 |
+ private $shopware; |
|
41 |
+ |
|
42 |
+ private $csvContext = []; |
|
43 |
+ |
|
44 |
+ /** @var Finder */ |
|
45 |
+ private $finder; |
|
46 |
+ |
|
47 |
+ /** @var Connection */ |
|
48 |
+ private $db; |
|
49 |
+ |
|
50 |
+ /** |
|
51 |
+ * Remote |
|
52 |
+ * @var Connection |
|
53 |
+ */ |
|
54 |
+ private $rdb; |
|
55 |
+ |
|
56 |
+ public function __construct(Finder $finder, Shopware $shopware, Connection $db, LoggerInterface $logger) |
|
57 |
+ { |
|
58 |
+ $this->finder = $finder; |
|
59 |
+ $this->db = $db; |
|
60 |
+ $this->logger = $logger; |
|
61 |
+ $this->shopware = $shopware; |
|
62 |
+ |
|
63 |
+ $encoder = [new CsvEncoder()]; |
|
64 |
+ $normalizer = [new ObjectNormalizer()]; |
|
65 |
+ $this->serializer = new Serializer($normalizer,$encoder); |
|
66 |
+ |
|
67 |
+ $this->csvContext = [ |
|
68 |
+ 'csv_delimiter' => ';', |
|
69 |
+ 'csv_enclosure' => '"', |
|
70 |
+ ]; |
|
71 |
+ } |
|
72 |
+ |
|
73 |
+ public function import(string $scope, ?SymfonyStyle &$io = null): void |
|
74 |
+ { |
|
75 |
+ $intCounter = 0; |
|
76 |
+ $isCli = false; |
|
77 |
+ if (strtolower($scope) == 'cli' && $io !== null) { |
|
78 |
+ $isCli = true; |
|
79 |
+ } |
|
80 |
+ $translator = System::getContainer()->get('translator'); |
|
81 |
+ $translator->setLocale('de'); |
|
82 |
+ $projectDir = System::getContainer()->getParameter('kernel.project_dir'); |
|
83 |
+ $srcDir = $projectDir.'/import/products'; |
|
84 |
+ if (!file_exists($srcDir)) { |
|
85 |
+ mkdir($srcDir, 0777,true); |
|
86 |
+ } |
|
87 |
+ |
|
88 |
+ $Today = new Date(); |
|
89 |
+ |
|
90 |
+ $importFiles = $this->finder->files()->in($srcDir)->name('*.csv'); |
|
91 |
+ |
|
92 |
+ if (!$importFiles->count()) |
|
93 |
+ { |
|
94 |
+ return; |
|
95 |
+ } |
|
96 |
+ |
|
97 |
+ foreach ($importFiles as $importFile) { |
|
98 |
+ $data = $this->serializer->decode($importFile->getContents(), 'csv',$this->csvContext); |
|
99 |
+ if ($isCli) $io->progressStart(count($data)); |
|
100 |
+ foreach ($data as $row) { |
|
101 |
+ /** @var ProductModel $Product */ |
|
102 |
+ $Product = $this->serializer->denormalize($row,ProductModel::class); |
|
103 |
+ |
|
104 |
+ $arrData = [ |
|
105 |
+ 'taxId' => '018e65c0485071508949c072f8dc18bd', |
|
106 |
+ 'ean' => $Product->getEan(), |
|
107 |
+ 'price' => [ |
|
108 |
+ [ |
|
109 |
+ 'currencyId' => 'b7d2554b0ce847cd82f3ac9bd1c0dfca', |
|
110 |
+ 'gross' => $Product->getPreis(), |
|
111 |
+ 'net' => $Product->getPreis()/119*100, |
|
112 |
+ 'linked' => true |
|
113 |
+ ] |
|
114 |
+ ], |
|
115 |
+ 'stock' => 9999999, |
|
116 |
+ 'name' => 'vrImport__'.$Product->getName(), |
|
117 |
+ 'customFields' => [ |
|
118 |
+ 'custom_wine_attributes_jahrgang' => $Product->getJahrgang() |
|
119 |
+ ] |
|
120 |
+ ]; |
|
121 |
+ |
|
122 |
+ if (!$this->shopware->addOrUpdateProductBySku($Product->getSku(), $arrData)) |
|
123 |
+ { |
|
124 |
+ if ($isCli) $io->error('Could not update'); |
|
125 |
+ } |
|
126 |
+ |
|
127 |
+ if ($isCli) |
|
128 |
+ { |
|
129 |
+ $io->progressAdvance(); |
|
130 |
+ } |
|
131 |
+ } |
|
132 |
+ if ($isCli) $io->progressFinish(); |
|
133 |
+ } |
|
134 |
+ } |
|
135 |
+} |
0 | 136 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,42 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+declare(strict_types=1); |
|
4 |
+ |
|
5 |
+/* |
|
6 |
+ * This file is part of vonRotenberg Shopware API Bundle. |
|
7 |
+ * |
|
8 |
+ * (c) vonRotenberg |
|
9 |
+ * |
|
10 |
+ * @license proprietary |
|
11 |
+ */ |
|
12 |
+ |
|
13 |
+namespace vonRotenberg\WmfgoCevisioBundle\DependencyInjection; |
|
14 |
+ |
|
15 |
+use Symfony\Component\Config\Definition\Builder\TreeBuilder; |
|
16 |
+use Symfony\Component\Config\Definition\ConfigurationInterface; |
|
17 |
+ |
|
18 |
+class Configuration implements ConfigurationInterface |
|
19 |
+{ |
|
20 |
+ public function getConfigTreeBuilder(): TreeBuilder |
|
21 |
+ { |
|
22 |
+ $treeBuilder = new TreeBuilder('vonrotenberg_wmfgo_cevisio'); |
|
23 |
+ $treeBuilder |
|
24 |
+ ->getRootNode() |
|
25 |
+ ->children() |
|
26 |
+ ->arrayNode('mappings') |
|
27 |
+ ->addDefaultsIfNotSet() |
|
28 |
+ ->children() |
|
29 |
+ ->arrayNode('properties') |
|
30 |
+ ->info('Shopware property mappings') |
|
31 |
+ ->defaultValue('') |
|
32 |
+ ->arrayPrototype() |
|
33 |
+ ->children() |
|
34 |
+ ->end() |
|
35 |
+ ->end() |
|
36 |
+ ->end() |
|
37 |
+ ->end() |
|
38 |
+ ; |
|
39 |
+ |
|
40 |
+ return $treeBuilder; |
|
41 |
+ } |
|
42 |
+} |
... | ... |
@@ -16,11 +16,19 @@ use Symfony\Component\Config\FileLocator; |
16 | 16 |
use Symfony\Component\DependencyInjection\ContainerBuilder; |
17 | 17 |
use Symfony\Component\DependencyInjection\Extension\Extension; |
18 | 18 |
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; |
19 |
+use vonRotenberg\ShopwareApiBundle\DependencyInjection\Configuration; |
|
19 | 20 |
|
20 | 21 |
class VonrotenbergWmfgoCevisioExtension extends Extension |
21 | 22 |
{ |
22 | 23 |
public function load(array $configs, ContainerBuilder $container): void |
23 | 24 |
{ |
25 |
+ $config = $this->processConfiguration(new Configuration(), $configs); |
|
26 |
+ |
|
27 |
+ foreach($config['mappings'] as $key=>$val) |
|
28 |
+ { |
|
29 |
+ $container->setParameter('vonrotenberg_wmfgo_cevisio.mappings.'.$key,$val); |
|
30 |
+ } |
|
31 |
+ |
|
24 | 32 |
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../../config')); |
25 | 33 |
$loader->load('services.yml'); |
26 | 34 |
} |
27 | 35 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,67 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+declare(strict_types=1); |
|
4 |
+ |
|
5 |
+/* |
|
6 |
+ * This file is part of Affentaler customizations for Contao. |
|
7 |
+ * |
|
8 |
+ * (c) Benjamin Roth |
|
9 |
+ * |
|
10 |
+ * @license commercial |
|
11 |
+ */ |
|
12 |
+ |
|
13 |
+namespace vonRotenberg\WmfgoCevisioBundle\Model\Import; |
|
14 |
+ |
|
15 |
+class ProductModel |
|
16 |
+{ |
|
17 |
+ /** |
|
18 |
+ * @var array |
|
19 |
+ */ |
|
20 |
+ private array $arrData; |
|
21 |
+ |
|
22 |
+ public function __get($name) |
|
23 |
+ { |
|
24 |
+ return $this->get($name); |
|
25 |
+ } |
|
26 |
+ |
|
27 |
+ public function __set($name, $value) |
|
28 |
+ { |
|
29 |
+ $this->set($name,$value); |
|
30 |
+ } |
|
31 |
+ |
|
32 |
+ |
|
33 |
+ public function __call($name, $arguments) |
|
34 |
+ { |
|
35 |
+ if (strncmp($name, 'get', 3) === 0) |
|
36 |
+ { |
|
37 |
+ $name = lcfirst(substr($name, 3)); |
|
38 |
+ |
|
39 |
+ return $this->get($name); |
|
40 |
+ } else if (strncmp($name, 'set', 3) === 0) |
|
41 |
+ { |
|
42 |
+ $name = lcfirst(substr($name, 3)); |
|
43 |
+ |
|
44 |
+ $this->set($name,$arguments[0]); |
|
45 |
+ } |
|
46 |
+ } |
|
47 |
+ |
|
48 |
+ public function get(string $name) |
|
49 |
+ { |
|
50 |
+ if (isset($this->arrData[$name])) |
|
51 |
+ { |
|
52 |
+ return $this->arrData[$name]; |
|
53 |
+ } |
|
54 |
+ |
|
55 |
+ return null; |
|
56 |
+ } |
|
57 |
+ |
|
58 |
+ public function set(string $name, $value): void |
|
59 |
+ { |
|
60 |
+ $this->arrData[$name] = $value; |
|
61 |
+ } |
|
62 |
+ |
|
63 |
+ public function getData(): ?array |
|
64 |
+ { |
|
65 |
+ return $this->arrData; |
|
66 |
+ } |
|
67 |
+} |