1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,97 @@ |
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\Input\InputOption; |
|
20 |
+use Symfony\Component\Console\Output\OutputInterface; |
|
21 |
+use Symfony\Component\Console\Style\SymfonyStyle; |
|
22 |
+use vonRotenberg\WmfgoCevisioBundle\Cron\ShopwareExportOrdersJob; |
|
23 |
+use vonRotenberg\WmfgoCevisioBundle\Cron\ShopwareImportProductsJob; |
|
24 |
+ |
|
25 |
+class ShopwareExportOrdersCommand extends Command |
|
26 |
+{ |
|
27 |
+ protected static $defaultName = 'shopware:export-orders'; |
|
28 |
+ |
|
29 |
+ /** |
|
30 |
+ * @var ContaoFramework |
|
31 |
+ */ |
|
32 |
+ private $framework; |
|
33 |
+ |
|
34 |
+ private $start; |
|
35 |
+ private $stop; |
|
36 |
+ |
|
37 |
+ public function __construct(ContaoFramework $framework) |
|
38 |
+ { |
|
39 |
+ $this->framework = $framework; |
|
40 |
+ |
|
41 |
+ parent::__construct(); |
|
42 |
+ } |
|
43 |
+ |
|
44 |
+ protected function configure(): void |
|
45 |
+ { |
|
46 |
+ $this |
|
47 |
+ ->setName(self::$defaultName) |
|
48 |
+ ->addOption('start', 'b', InputOption::VALUE_REQUIRED, 'Custom start date') |
|
49 |
+ ->addOption('stop', 'x', InputOption::VALUE_REQUIRED, 'Custom stop date') |
|
50 |
+ ->setDescription('Export orders from Shopware instance') |
|
51 |
+ ; |
|
52 |
+ } |
|
53 |
+ |
|
54 |
+ protected function interact(InputInterface $input, OutputInterface $output): void |
|
55 |
+ { |
|
56 |
+ if ((null !== $input->getOption('start') && null === $input->getOption('stop')) |
|
57 |
+ || (null === $input->getOption('start') && null !== $input->getOption('stop'))) |
|
58 |
+ { |
|
59 |
+ throw new \RuntimeException('You need to provide start and stop date.'); |
|
60 |
+ } |
|
61 |
+ |
|
62 |
+ if (null !== $input->getOption('start')) { |
|
63 |
+ try { |
|
64 |
+ new \DateTime($input->getOption('start')); |
|
65 |
+ $this->start = $input->getOption('start'); |
|
66 |
+ } catch(\Exception $e) |
|
67 |
+ { |
|
68 |
+ throw new \InvalidArgumentException('Start date is invalid. Please provide an ISO date.'); |
|
69 |
+ } |
|
70 |
+ } |
|
71 |
+ |
|
72 |
+ if (null !== $input->getOption('stop')) { |
|
73 |
+ try { |
|
74 |
+ new \DateTime($input->getOption('stop')); |
|
75 |
+ $this->stop = $input->getOption('stop'); |
|
76 |
+ } catch(\Exception $e) |
|
77 |
+ { |
|
78 |
+ throw new \InvalidArgumentException('Stop date is invalid. Please provide an ISO date.'); |
|
79 |
+ } |
|
80 |
+ } |
|
81 |
+ } |
|
82 |
+ |
|
83 |
+ protected function execute(InputInterface $input, OutputInterface $output): int |
|
84 |
+ { |
|
85 |
+ $this->framework->initialize(); |
|
86 |
+ |
|
87 |
+ $io = new SymfonyStyle($input, $output); |
|
88 |
+ $io->title('Orders export from Shopware'); |
|
89 |
+ |
|
90 |
+ /** @var ShopwareExportOrdersJob $export */ |
|
91 |
+ $export = System::getContainer()->get(ShopwareExportOrdersJob::class); |
|
92 |
+ |
|
93 |
+ $export->export('cli', $this->start,$this->stop, $io); |
|
94 |
+ |
|
95 |
+ return 0; |
|
96 |
+ } |
|
97 |
+} |
0 | 98 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,228 @@ |
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\Encoder\XmlEncoder; |
|
26 |
+use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; |
|
27 |
+use Symfony\Component\Serializer\Serializer; |
|
28 |
+use Symfony\Component\Serializer\SerializerInterface; |
|
29 |
+use vonRotenberg\ShopwareApiBundle\API\Shopware; |
|
30 |
+use vonRotenberg\ShopwareApiBundle\Helper\ShopwareMappings; |
|
31 |
+use vonRotenberg\WmfgoCevisioBundle\Model\Import\ProductModel; |
|
32 |
+ |
|
33 |
+class ShopwareExportOrdersJob extends AbstractController |
|
34 |
+{ |
|
35 |
+ /** @var LoggerInterface */ |
|
36 |
+ private $logger; |
|
37 |
+ |
|
38 |
+ /** @var SerializerInterface */ |
|
39 |
+ private $serializer; |
|
40 |
+ |
|
41 |
+ /** @var Shopware */ |
|
42 |
+ private $shopware; |
|
43 |
+ |
|
44 |
+ /** @var ShopwareMappings */ |
|
45 |
+ private $mappings; |
|
46 |
+ |
|
47 |
+ private $xmlContext = []; |
|
48 |
+ |
|
49 |
+ /** @var Finder */ |
|
50 |
+ private $finder; |
|
51 |
+ |
|
52 |
+ /** @var Connection */ |
|
53 |
+ private $db; |
|
54 |
+ |
|
55 |
+ /** |
|
56 |
+ * Remote |
|
57 |
+ * @var Connection |
|
58 |
+ */ |
|
59 |
+ private $rdb; |
|
60 |
+ |
|
61 |
+ public function __construct(Finder $finder, Shopware $shopware, ShopwareMappings $mappings, Connection $db, LoggerInterface $logger) |
|
62 |
+ { |
|
63 |
+ $this->finder = $finder; |
|
64 |
+ $this->db = $db; |
|
65 |
+ $this->logger = $logger; |
|
66 |
+ $this->shopware = $shopware; |
|
67 |
+ $this->mappings = $mappings; |
|
68 |
+ |
|
69 |
+ $encoder = [new XmlEncoder()]; |
|
70 |
+ $normalizer = [new ObjectNormalizer()]; |
|
71 |
+ $this->serializer = new Serializer($normalizer,$encoder); |
|
72 |
+ |
|
73 |
+ $this->xmlContext = [ |
|
74 |
+ 'xml_root_node_name' => 'Order', |
|
75 |
+ 'xml_encoding' => 'UTF-8', |
|
76 |
+ 'xml_format_output' => true, |
|
77 |
+ ]; |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ public function export(string $scope, ?string $start=null, ?string $stop=null, ?SymfonyStyle &$io = null): void |
|
81 |
+ { |
|
82 |
+ $intCounter = 0; |
|
83 |
+ $isCli = false; |
|
84 |
+ if (strtolower($scope) == 'cli' && $io !== null) { |
|
85 |
+ $isCli = true; |
|
86 |
+ } |
|
87 |
+ $translator = System::getContainer()->get('translator'); |
|
88 |
+ $translator->setLocale('de'); |
|
89 |
+// date_default_timezone_set('Europe/Berlin'); |
|
90 |
+ $projectDir = System::getContainer()->getParameter('kernel.project_dir'); |
|
91 |
+ $srcDir = $projectDir.'/export/orders'; |
|
92 |
+ if (!file_exists($srcDir)) { |
|
93 |
+ mkdir($srcDir, 0777,true); |
|
94 |
+ } |
|
95 |
+ |
|
96 |
+ $Today = new Date(); |
|
97 |
+ |
|
98 |
+ if (($start || $stop) && ($start === null || $stop === null)) |
|
99 |
+ { |
|
100 |
+ return; |
|
101 |
+ } |
|
102 |
+ |
|
103 |
+ // Set working period |
|
104 |
+ if ($start && $stop) { |
|
105 |
+ $StartDate = new Date($start,'Y-m-d'); |
|
106 |
+ $StopDate = new Date($stop,'Y-m-d'); |
|
107 |
+ $intStart = $StartDate->dayBegin; |
|
108 |
+ $intEnd = $StopDate->dayEnd; |
|
109 |
+ } else { |
|
110 |
+ $WorkingDate = new Date($Today->dayBegin); |
|
111 |
+ $intStart = strtotime(date('Y-m-d',$WorkingDate->dayBegin) . ' -1 day'); |
|
112 |
+ $intEnd = $WorkingDate->dayBegin; |
|
113 |
+ } |
|
114 |
+ |
|
115 |
+ if ($isCli) { |
|
116 |
+ $io->definitionList('Using export timeframe:',['Start'=>Date::parse(Date::getNumericDateFormat(),$intStart)],['End'=>Date::parse(Date::getNumericDateFormat(),$intEnd)]); |
|
117 |
+ } |
|
118 |
+ |
|
119 |
+ $arrFilter = [ |
|
120 |
+ [ |
|
121 |
+ 'type'=> 'range', |
|
122 |
+ 'field'=> 'createdAt', |
|
123 |
+ 'parameters'=> [ |
|
124 |
+ 'gte'=> date(\DateTime::ATOM,$intStart), |
|
125 |
+ 'lte'=> date(\DateTime::ATOM,$intEnd), |
|
126 |
+ ], |
|
127 |
+ ], |
|
128 |
+ ]; |
|
129 |
+ |
|
130 |
+ $Response = $this->shopware->findOrdersByFilter($arrFilter); |
|
131 |
+ |
|
132 |
+ if ($Response->getStatusCode() !== 200 || !json_validate($Response->getContent())) { |
|
133 |
+ if ($isCli) $io->error('Could not export orders'); |
|
134 |
+ dump($Response->getContent(false)); |
|
135 |
+ } |
|
136 |
+ |
|
137 |
+ $Content = json_decode($Response->getContent(), true); |
|
138 |
+ |
|
139 |
+ foreach ($Content['data'] as $order) |
|
140 |
+ { |
|
141 |
+ $arrOrderExport = []; |
|
142 |
+// dump($order);die; |
|
143 |
+// dump($order); |
|
144 |
+ |
|
145 |
+ $Delivery = count($order['deliveries']) ? array_shift($order['deliveries']) : null; |
|
146 |
+ $Transaction = count($order['transactions']) ? array_shift($order['transactions']) : null; |
|
147 |
+ $LineItems = count($order['lineItems']) ? $order['lineItems'] : null; |
|
148 |
+ |
|
149 |
+ $arrOrderExport = [ |
|
150 |
+ '@xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', |
|
151 |
+ '@xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', |
|
152 |
+ 'OrderNumber' => $order['orderNumber'], |
|
153 |
+ 'OrderDate' => date(\DateTime::ATOM,strtotime($order['createdAt'])), |
|
154 |
+ 'TODO' => 'One field missing', |
|
155 |
+ 'PaymentMethod' => isset($Transaction['paymentMethod']['name']) ? $Transaction['paymentMethod']['name'] : null, |
|
156 |
+ 'ShippingKind' => isset($Delivery['shippingMethod']['name']) ? $Delivery['shippingMethod']['name'] : null, |
|
157 |
+ 'BuyerId' => $order['orderCustomer']['email'], |
|
158 |
+ 'BuyerFirstName' => $order['billingAddress']['firstName'], |
|
159 |
+ 'BuyerLastName' => $order['billingAddress']['lastName'], |
|
160 |
+ 'BuyerCompanyName' => $order['billingAddress']['company'], |
|
161 |
+ 'BuyerStreet' => $order['billingAddress']['street'], |
|
162 |
+ 'BuyerPostalCode' => $order['billingAddress']['zipcode'], |
|
163 |
+ 'BuyerCity' => $order['billingAddress']['city'], |
|
164 |
+ 'BuyerCountry' => $order['billingAddress']['country']['name'], |
|
165 |
+ 'BuyerCountryCode' => $order['billingAddress']['country']['iso'], |
|
166 |
+ 'BuyerEmail' => $order['orderCustomer']['email'], |
|
167 |
+ 'BuyerPhone' => $order['billingAddress']['phoneNumber'], |
|
168 |
+ 'BuyerVATID' => $order['billingAddress']['vatId'], |
|
169 |
+ ]; |
|
170 |
+ |
|
171 |
+ if (count($Delivery['shippingOrderAddress'])) |
|
172 |
+ { |
|
173 |
+ $arrOrderExport = array_merge($arrOrderExport,[ |
|
174 |
+ 'ShippingName1' => $Delivery['shippingOrderAddress']['firstName']. ' '.$Delivery['shippingOrderAddress']['lastName'], |
|
175 |
+ 'ShippingStreet' => $Delivery['shippingOrderAddress']['street'], |
|
176 |
+ 'ShippingPostalCode' => $Delivery['shippingOrderAddress']['zipcode'], |
|
177 |
+ 'ShippingCity' => $Delivery['shippingOrderAddress']['city'], |
|
178 |
+ 'ShippingCountry' => $Delivery['shippingOrderAddress']['country']['name'], |
|
179 |
+ 'ShippingCountryCode' => $Delivery['shippingOrderAddress']['country']['iso'], |
|
180 |
+ 'ShippingPhone' => $Delivery['shippingOrderAddress']['phoneNumber'], |
|
181 |
+ ]); |
|
182 |
+ } |
|
183 |
+ |
|
184 |
+ $arrOrderExport = array_merge($arrOrderExport,[ |
|
185 |
+ 'PriceDeclaration' => ucfirst($order['taxStatus']), |
|
186 |
+ 'TotalAmount' => $order['amountTotal'], |
|
187 |
+ 'ShippingCosts' => $order['shippingTotal'], |
|
188 |
+ 'PaidAmount' => in_array($Transaction['paymentMethod']['shortName'],['cash_payment','pre_payment']) ? 0.00 : $order['amountTotal'], |
|
189 |
+ ]); |
|
190 |
+ |
|
191 |
+ if (count($LineItems)) |
|
192 |
+ { |
|
193 |
+ $arrPositions = []; |
|
194 |
+ foreach ($LineItems as $item) |
|
195 |
+ { |
|
196 |
+ if ($item['type'] == 'promotion') |
|
197 |
+ { |
|
198 |
+ $arrPositions['Position'][] = [ |
|
199 |
+ 'PositionNumber' => $item['position'], |
|
200 |
+ 'ProductNumber' => 'Rabatt-'.$item['payload']['promotionId'], |
|
201 |
+ 'ProductName' => 'Rabatt als Artikel ('.$item['label']. ' - ' .($item['priceDefinition']['type'] == 'percentage' ? $item['priceDefinition']['percentage']*-1 . '%' : $item['priceDefinition']['price']*-1 . ' EUR') . ')', |
|
202 |
+ 'Quantity' => $item['quantity'], |
|
203 |
+ 'Unit' => 'Stk', |
|
204 |
+ 'UnitPrice' => $item['unitPrice'], |
|
205 |
+ 'TaxRate' => $item['price']['calculatedTaxes'][0]['taxRate'], |
|
206 |
+ ]; |
|
207 |
+ } else { |
|
208 |
+ $arrPositions['Position'][] = [ |
|
209 |
+ 'PositionNumber' => $item['position'], |
|
210 |
+ 'ProductNumber' => isset($item['product']) ? $item['product']['productNumber'] : null, |
|
211 |
+ 'ProductName' => $item['label'], |
|
212 |
+ 'Quantity' => $item['quantity'], |
|
213 |
+ 'Unit' => 'Stk', |
|
214 |
+ 'UnitPrice' => $item['unitPrice'], |
|
215 |
+ 'TaxRate' => $item['price']['calculatedTaxes'][0]['taxRate'], |
|
216 |
+ ]; |
|
217 |
+ } |
|
218 |
+ } |
|
219 |
+ |
|
220 |
+ $arrOrderExport = array_merge($arrOrderExport,['Positions' => $arrPositions]); |
|
221 |
+ } |
|
222 |
+ |
|
223 |
+ \file_put_contents($projectDir.'/export/orders/order__' . $order['orderNumber'] . '.xml', $this->serializer->encode($arrOrderExport,'xml', $this->xmlContext)); |
|
224 |
+ } |
|
225 |
+ |
|
226 |
+ |
|
227 |
+ } |
|
228 |
+} |