|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace ShopwarePlugins\Connect\Components; |
|
4
|
|
|
|
|
5
|
|
|
use Doctrine\DBAL\DBALException; |
|
6
|
|
|
use Shopware\Components\ContainerAwareEventManager; |
|
7
|
|
|
use Shopware\Connect\SDK; |
|
8
|
|
|
use Shopware\CustomModels\Connect\Attribute; |
|
9
|
|
|
use ShopwarePlugins\Connect\Components\Marketplace\MarketplaceGateway; |
|
10
|
|
|
use ShopwarePlugins\Connect\Components\Validator\ProductAttributesValidator; |
|
11
|
|
|
use Shopware\Components\Model\ModelManager; |
|
12
|
|
|
use Shopware\Models\Article\Article; |
|
13
|
|
|
use Shopware\Models\Article\Detail; |
|
14
|
|
|
use ShopwarePlugins\Connect\Components\ProductStream\ProductStreamsAssignments; |
|
15
|
|
|
use ShopwarePlugins\Connect\Components\ErrorHandler; |
|
16
|
|
|
use ShopwarePlugins\Connect\Struct\ExportList; |
|
17
|
|
|
use ShopwarePlugins\Connect\Struct\SearchCriteria; |
|
18
|
|
|
use Enlight_Event_EventManager; |
|
19
|
|
|
|
|
20
|
|
|
class ConnectExport |
|
21
|
|
|
{ |
|
22
|
|
|
const BATCH_SIZE = 200; |
|
23
|
|
|
|
|
24
|
|
|
/** @var |
|
25
|
|
|
* Helper |
|
26
|
|
|
*/ |
|
27
|
|
|
protected $helper; |
|
28
|
|
|
|
|
29
|
|
|
/** @var |
|
30
|
|
|
* SDK |
|
31
|
|
|
*/ |
|
32
|
|
|
protected $sdk; |
|
33
|
|
|
|
|
34
|
|
|
/** @var |
|
35
|
|
|
* ModelManager |
|
36
|
|
|
*/ |
|
37
|
|
|
protected $manager; |
|
38
|
|
|
|
|
39
|
|
|
/** |
|
40
|
|
|
* @var ProductAttributesValidator |
|
41
|
|
|
*/ |
|
42
|
|
|
protected $productAttributesValidator; |
|
43
|
|
|
|
|
44
|
|
|
/** @var |
|
45
|
|
|
* MarketplaceGateway |
|
46
|
|
|
*/ |
|
47
|
|
|
protected $marketplaceGateway; |
|
48
|
|
|
|
|
49
|
|
|
/** |
|
50
|
|
|
* @var ErrorHandler |
|
51
|
|
|
*/ |
|
52
|
|
|
protected $errorHandler; |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* @var Config |
|
56
|
|
|
*/ |
|
57
|
|
|
protected $configComponent; |
|
58
|
|
|
|
|
59
|
|
|
/** |
|
60
|
|
|
* @var Enlight_Event_EventManager |
|
61
|
|
|
*/ |
|
62
|
|
|
private $eventManager; |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* ConnectExport constructor. |
|
66
|
|
|
* @param Helper $helper |
|
67
|
|
|
* @param SDK $sdk |
|
68
|
|
|
* @param ModelManager $manager |
|
69
|
|
|
* @param ProductAttributesValidator $productAttributesValidator |
|
70
|
|
|
* @param Config $configComponent |
|
71
|
|
|
* @param \ShopwarePlugins\Connect\Components\ErrorHandler $errorHandler |
|
72
|
|
|
* @param Enlight_Event_EventManager $eventManager |
|
73
|
|
|
*/ |
|
74
|
|
|
public function __construct( |
|
75
|
|
|
Helper $helper, |
|
76
|
|
|
SDK $sdk, |
|
77
|
|
|
ModelManager $manager, |
|
78
|
|
|
ProductAttributesValidator $productAttributesValidator, |
|
79
|
|
|
Config $configComponent, |
|
80
|
|
|
ErrorHandler $errorHandler, |
|
81
|
|
|
Enlight_Event_EventManager $eventManager |
|
82
|
|
|
) |
|
83
|
|
|
{ |
|
84
|
|
|
$this->helper = $helper; |
|
85
|
|
|
$this->sdk = $sdk; |
|
86
|
|
|
$this->manager = $manager; |
|
87
|
|
|
$this->productAttributesValidator = $productAttributesValidator; |
|
88
|
|
|
$this->configComponent = $configComponent; |
|
89
|
|
|
$this->errorHandler = $errorHandler; |
|
90
|
|
|
$this->eventManager = $eventManager; |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
/** |
|
94
|
|
|
* Load article entity |
|
95
|
|
|
* |
|
96
|
|
|
* @param $id |
|
97
|
|
|
* @return null|\Shopware\Models\Article\Article |
|
98
|
|
|
*/ |
|
99
|
|
|
public function getArticleModelById($id) |
|
100
|
|
|
{ |
|
101
|
|
|
return $this->manager->getRepository('Shopware\Models\Article\Article')->find($id); |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* Load article detail entity |
|
106
|
|
|
* |
|
107
|
|
|
* @param $id |
|
108
|
|
|
* @return null|\Shopware\Models\Article\Detail |
|
109
|
|
|
*/ |
|
110
|
|
|
public function getArticleDetailById($id) |
|
111
|
|
|
{ |
|
112
|
|
|
return $this->manager->getRepository('Shopware\Models\Article\Detail')->find($id); |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
/** |
|
116
|
|
|
* Helper function to mark a given array of source ids for connect update |
|
117
|
|
|
* |
|
118
|
|
|
* There is a problem with flush when is called from life cycle event in php7, |
|
119
|
|
|
* this flag '$isEvent' is preventing the flush |
|
120
|
|
|
* |
|
121
|
|
|
* @param array $ids |
|
122
|
|
|
* @param ProductStreamsAssignments|null $streamsAssignments |
|
123
|
|
|
* @return array |
|
124
|
|
|
*/ |
|
125
|
|
|
public function export(array $ids, ProductStreamsAssignments $streamsAssignments = null) |
|
126
|
|
|
{ |
|
127
|
|
|
$ids = $this->eventManager->filter( |
|
128
|
|
|
'Connect_Supplier_Get_Products_Filter_Source_IDS', |
|
129
|
|
|
$ids, |
|
130
|
|
|
[ |
|
131
|
|
|
'subject' => $this |
|
132
|
|
|
] |
|
133
|
|
|
); |
|
134
|
|
|
|
|
135
|
|
|
$connectItems = $this->fetchConnectItems($ids); |
|
136
|
|
|
|
|
137
|
|
|
$this->eventManager->notify( |
|
138
|
|
|
'Connect_Supplier_Get_All_Products_Before', |
|
139
|
|
|
[ |
|
140
|
|
|
'subject' => $this, |
|
141
|
|
|
'products' => $connectItems |
|
142
|
|
|
] |
|
143
|
|
|
); |
|
144
|
|
|
|
|
145
|
|
|
$this->manager->beginTransaction(); |
|
146
|
|
|
|
|
147
|
|
|
foreach ($connectItems as &$item) { |
|
148
|
|
|
$model = $this->getArticleDetailById($item['articleDetailId']); |
|
149
|
|
|
if($model === null) { |
|
150
|
|
|
continue; |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
$connectAttribute = $this->helper->getOrCreateConnectAttributeByModel($model); |
|
154
|
|
|
|
|
155
|
|
|
$excludeInactiveProducts = $this->configComponent->getConfig('excludeInactiveProducts'); |
|
156
|
|
|
if ($excludeInactiveProducts && !$model->getActive()) { |
|
157
|
|
|
$this->updateLocalConnectItem( |
|
158
|
|
|
$connectAttribute->getSourceId(), |
|
159
|
|
|
array( |
|
160
|
|
|
'export_status' => Attribute::STATUS_INACTIVE, |
|
161
|
|
|
'exported' => false, |
|
162
|
|
|
'export_message' => Shopware()->Snippets()->getNamespace('backend/connect/view/main')->get( |
|
163
|
|
|
'export/message/error_product_is_not_active', |
|
164
|
|
|
'Produkt ist inaktiv', |
|
165
|
|
|
true |
|
166
|
|
|
), |
|
167
|
|
|
) |
|
168
|
|
|
); |
|
169
|
|
|
$this->manager->refresh($connectAttribute); |
|
170
|
|
|
continue; |
|
171
|
|
|
} |
|
172
|
|
|
|
|
173
|
|
|
if (!$this->helper->isProductExported($connectAttribute)) { |
|
174
|
|
|
$status = Attribute::STATUS_INSERT; |
|
175
|
|
|
} else { |
|
176
|
|
|
$status = Attribute::STATUS_UPDATE; |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
$categories = $this->helper->getConnectCategoryForProduct($item['articleId']); |
|
180
|
|
|
if (is_string($categories)) { |
|
181
|
|
|
$categories = array($categories); |
|
182
|
|
|
} |
|
183
|
|
|
$categories = json_encode($categories); |
|
184
|
|
|
|
|
185
|
|
|
$this->updateLocalConnectItem( |
|
186
|
|
|
$connectAttribute->getSourceId(), |
|
187
|
|
|
array( |
|
188
|
|
|
'export_status' => $status, |
|
189
|
|
|
'export_message' => null, |
|
190
|
|
|
'exported' => true, |
|
191
|
|
|
'category' => $categories, |
|
192
|
|
|
) |
|
193
|
|
|
); |
|
194
|
|
|
|
|
195
|
|
|
try { |
|
196
|
|
|
$this->productAttributesValidator->validate($this->extractProductAttributes($model)); |
|
197
|
|
|
if ($status == Attribute::STATUS_INSERT) { |
|
198
|
|
|
$this->sdk->recordInsert($item['sourceId']); |
|
199
|
|
|
} else { |
|
200
|
|
|
$this->sdk->recordUpdate($item['sourceId']); |
|
201
|
|
|
} |
|
202
|
|
|
|
|
203
|
|
|
if ($this->helper->isMainVariant($item['sourceId']) && |
|
204
|
|
|
$streamsAssignments !== null && |
|
205
|
|
|
$streamsAssignments->getStreamsByArticleId($item['articleId']) !== null |
|
206
|
|
|
) { |
|
207
|
|
|
$this->sdk->recordStreamAssignment( |
|
208
|
|
|
$item['sourceId'], |
|
209
|
|
|
$streamsAssignments->getStreamsByArticleId($item['articleId']), |
|
210
|
|
|
$item['groupId'] |
|
211
|
|
|
); |
|
212
|
|
|
} |
|
213
|
|
|
} catch (\Exception $e) { |
|
214
|
|
|
if ($this->errorHandler->isPriceError($e)) { |
|
215
|
|
|
$this->updateLocalConnectItem( |
|
216
|
|
|
$connectAttribute->getSourceId(), |
|
217
|
|
|
array( |
|
218
|
|
|
'export_status' => Attribute::STATUS_ERROR_PRICE, |
|
219
|
|
|
'export_message' => Shopware()->Snippets()->getNamespace('backend/connect/view/main')->get( |
|
220
|
|
|
'export/message/error_price_status', |
|
221
|
|
|
'There is an empty price field', |
|
222
|
|
|
true |
|
223
|
|
|
), |
|
224
|
|
|
) |
|
225
|
|
|
); |
|
226
|
|
|
} else { |
|
227
|
|
|
$this->updateLocalConnectItem( |
|
228
|
|
|
$connectAttribute->getSourceId(), |
|
229
|
|
|
array( |
|
230
|
|
|
'export_status' => Attribute::STATUS_ERROR, |
|
231
|
|
|
'export_message' => $e->getMessage() . "\n" . $e->getTraceAsString(), |
|
232
|
|
|
) |
|
233
|
|
|
); |
|
234
|
|
|
} |
|
235
|
|
|
|
|
236
|
|
|
$this->errorHandler->handle($e); |
|
237
|
|
|
} |
|
238
|
|
|
$this->manager->refresh($connectAttribute); |
|
239
|
|
|
} |
|
240
|
|
|
|
|
241
|
|
|
try { |
|
242
|
|
|
$this->manager->commit(); |
|
243
|
|
|
} catch (\Exception $e) { |
|
244
|
|
|
$this->manager->rollback(); |
|
245
|
|
|
$this->errorHandler->handle($e); |
|
246
|
|
|
} |
|
247
|
|
|
|
|
248
|
|
|
return $this->errorHandler->getMessages(); |
|
249
|
|
|
} |
|
250
|
|
|
|
|
251
|
|
|
/** |
|
252
|
|
|
* Update connect attribute data |
|
253
|
|
|
* |
|
254
|
|
|
* @param string $sourceId |
|
255
|
|
|
* @param array $params |
|
256
|
|
|
*/ |
|
257
|
|
|
private function updateLocalConnectItem($sourceId, $params = array()) |
|
258
|
|
|
{ |
|
259
|
|
|
if (empty($params)) { |
|
260
|
|
|
return; |
|
261
|
|
|
} |
|
262
|
|
|
$possibleValues = array( |
|
263
|
|
|
Attribute::STATUS_DELETE, |
|
264
|
|
|
Attribute::STATUS_INSERT, |
|
265
|
|
|
Attribute::STATUS_UPDATE, |
|
266
|
|
|
Attribute::STATUS_ERROR, |
|
267
|
|
|
Attribute::STATUS_ERROR_PRICE, |
|
268
|
|
|
Attribute::STATUS_INACTIVE, |
|
269
|
|
|
Attribute::STATUS_SYNCED, |
|
270
|
|
|
null, |
|
271
|
|
|
); |
|
272
|
|
|
|
|
273
|
|
|
if (isset($params['export_status']) && !in_array($params['export_status'], $possibleValues)) { |
|
274
|
|
|
throw new \InvalidArgumentException('Invalid export status'); |
|
275
|
|
|
} |
|
276
|
|
|
|
|
277
|
|
|
if (isset($params['exported']) && !is_bool($params['exported'])) { |
|
278
|
|
|
throw new \InvalidArgumentException('Parameter $exported must be boolean.'); |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
$builder = $this->manager->getConnection()->createQueryBuilder(); |
|
282
|
|
|
$builder->update('s_plugin_connect_items', 'ci'); |
|
283
|
|
|
array_walk($params, function($param, $name) use ($builder) { |
|
284
|
|
|
$builder->set('ci.' . $name, ':' . $name) |
|
285
|
|
|
->setParameter($name, $param); |
|
286
|
|
|
}); |
|
287
|
|
|
|
|
288
|
|
|
$builder->where('source_id = :sourceId') |
|
289
|
|
|
->setParameter('sourceId', $sourceId) |
|
290
|
|
|
->andWhere('shop_id IS NULL') |
|
291
|
|
|
->execute(); |
|
292
|
|
|
} |
|
293
|
|
|
|
|
294
|
|
|
/** |
|
295
|
|
|
* Fetch connect items |
|
296
|
|
|
* Default order is main variant first, after that regular variants. |
|
297
|
|
|
* This is needed, because first received variant with an unknown groupId in Connect |
|
298
|
|
|
* will be selected as main variant. |
|
299
|
|
|
* |
|
300
|
|
|
* @param array $sourceIds |
|
301
|
|
|
* @param boolean $orderByMainVariants |
|
302
|
|
|
* @return array |
|
303
|
|
|
*/ |
|
304
|
|
|
public function fetchConnectItems(array $sourceIds, $orderByMainVariants = true) |
|
305
|
|
|
{ |
|
306
|
|
|
if (count($sourceIds) == 0) { |
|
307
|
|
|
return array(); |
|
308
|
|
|
} |
|
309
|
|
|
|
|
310
|
|
|
$implodedIds = '"' . implode('","', $sourceIds) . '"'; |
|
311
|
|
|
$query = "SELECT bi.article_id as articleId, |
|
312
|
|
|
bi.article_detail_id as articleDetailId, |
|
313
|
|
|
bi.export_status as exportStatus, |
|
314
|
|
|
bi.export_message as exportMessage, |
|
315
|
|
|
bi.source_id as sourceId, |
|
316
|
|
|
a.name as title, |
|
317
|
|
|
IF (a.configurator_set_id IS NOT NULL, a.id, NULL) as groupId, |
|
318
|
|
|
d.ordernumber as number |
|
319
|
|
|
FROM s_plugin_connect_items bi |
|
320
|
|
|
LEFT JOIN s_articles a ON bi.article_id = a.id |
|
321
|
|
|
LEFT JOIN s_articles_details d ON bi.article_detail_id = d.id |
|
322
|
|
|
WHERE bi.source_id IN ($implodedIds)"; |
|
323
|
|
|
|
|
324
|
|
|
if ($orderByMainVariants === false) { |
|
325
|
|
|
$query .= ';'; |
|
326
|
|
|
return Shopware()->Db()->fetchAll($query); |
|
327
|
|
|
} |
|
328
|
|
|
|
|
329
|
|
|
$query .= 'AND d.kind = ?;'; |
|
330
|
|
|
$mainVariants = Shopware()->Db()->fetchAll($query, array(1)); |
|
331
|
|
|
$regularVariants = Shopware()->Db()->fetchAll($query, array(2)); |
|
332
|
|
|
|
|
333
|
|
|
return array_merge($mainVariants, $regularVariants); |
|
334
|
|
|
} |
|
335
|
|
|
|
|
336
|
|
|
/** |
|
337
|
|
|
* Helper function to return export product ids |
|
338
|
|
|
* @return array |
|
339
|
|
|
*/ |
|
340
|
|
|
public function getExportArticlesIds() |
|
341
|
|
|
{ |
|
342
|
|
|
$builder = $this->manager->createQueryBuilder(); |
|
343
|
|
|
$builder->from('Shopware\CustomModels\Connect\Attribute', 'at'); |
|
344
|
|
|
$builder->join('at.article', 'a'); |
|
345
|
|
|
$builder->join('a.mainDetail', 'd'); |
|
346
|
|
|
$builder->leftJoin('d.prices', 'p', 'with', "p.from = 1 AND p.customerGroupKey = 'EK'"); |
|
347
|
|
|
$builder->leftJoin('a.supplier', 's'); |
|
348
|
|
|
$builder->leftJoin('a.tax', 't'); |
|
349
|
|
|
|
|
350
|
|
|
$builder->select(array('a.id')); |
|
351
|
|
|
|
|
352
|
|
|
$builder->where("at.exportStatus = 'update' OR at.exportStatus = 'insert' OR at.exportStatus = 'error'"); |
|
353
|
|
|
$builder->andWhere('at.shopId IS NULL'); |
|
354
|
|
|
|
|
355
|
|
|
$query = $builder->getQuery(); |
|
356
|
|
|
$articles = $query->getArrayResult(); |
|
357
|
|
|
|
|
358
|
|
|
$ids = array(); |
|
359
|
|
|
foreach ($articles as $article) { |
|
360
|
|
|
$ids[] = $article['id']; |
|
361
|
|
|
} |
|
362
|
|
|
|
|
363
|
|
|
return $ids; |
|
364
|
|
|
} |
|
365
|
|
|
|
|
366
|
|
|
/** |
|
367
|
|
|
* Helper function to count how many changes |
|
368
|
|
|
* are waiting to be synchronized |
|
369
|
|
|
* |
|
370
|
|
|
* @return int |
|
371
|
|
|
*/ |
|
372
|
|
|
public function getChangesCount() |
|
373
|
|
|
{ |
|
374
|
|
|
$sql = 'SELECT COUNT(*) FROM `sw_connect_change`'; |
|
375
|
|
|
|
|
376
|
|
|
return (int)Shopware()->Db()->fetchOne($sql); |
|
377
|
|
|
} |
|
378
|
|
|
|
|
379
|
|
|
/** |
|
380
|
|
|
* Mark single connect product detail for delete |
|
381
|
|
|
* |
|
382
|
|
|
* @param \Shopware\Models\Article\Detail $detail |
|
383
|
|
|
*/ |
|
384
|
|
|
public function syncDeleteDetail(Detail $detail) |
|
385
|
|
|
{ |
|
386
|
|
|
$attribute = $this->helper->getConnectAttributeByModel($detail); |
|
387
|
|
|
if (!$this->helper->isProductExported($attribute)) { |
|
388
|
|
|
return; |
|
389
|
|
|
} |
|
390
|
|
|
$this->sdk->recordDelete($attribute->getSourceId()); |
|
391
|
|
|
$attribute->setExportStatus(Attribute::STATUS_DELETE); |
|
392
|
|
|
$attribute->setExported(false); |
|
393
|
|
|
$this->manager->persist($attribute); |
|
394
|
|
|
$this->manager->flush($attribute); |
|
395
|
|
|
} |
|
396
|
|
|
|
|
397
|
|
|
/** |
|
398
|
|
|
* Mark all product variants for delete |
|
399
|
|
|
* |
|
400
|
|
|
* @param Article $article |
|
401
|
|
|
*/ |
|
402
|
|
|
public function setDeleteStatusForVariants(Article $article) |
|
403
|
|
|
{ |
|
404
|
|
|
$builder = $this->manager->createQueryBuilder(); |
|
405
|
|
|
$builder->select(array('at.sourceId')) |
|
406
|
|
|
->from('Shopware\CustomModels\Connect\Attribute', 'at') |
|
407
|
|
|
->where('at.articleId = :articleId') |
|
408
|
|
|
->andWhere('at.exported = 1') |
|
409
|
|
|
->setParameter(':articleId', $article->getId()); |
|
410
|
|
|
$connectItems = $builder->getQuery()->getArrayResult(); |
|
411
|
|
|
|
|
412
|
|
|
foreach($connectItems as $item) { |
|
413
|
|
|
$this->sdk->recordDelete($item['sourceId']); |
|
414
|
|
|
} |
|
415
|
|
|
|
|
416
|
|
|
$builder = $this->manager->createQueryBuilder(); |
|
417
|
|
|
$builder->update('Shopware\CustomModels\Connect\Attribute', 'at') |
|
418
|
|
|
->set('at.exportStatus', $builder->expr()->literal(Attribute::STATUS_DELETE)) |
|
419
|
|
|
->set('at.exported', 0) |
|
420
|
|
|
->where('at.articleId = :articleId') |
|
421
|
|
|
->setParameter(':articleId', $article->getId()); |
|
422
|
|
|
|
|
423
|
|
|
$builder->getQuery()->execute(); |
|
424
|
|
|
} |
|
425
|
|
|
|
|
426
|
|
|
/** |
|
427
|
|
|
* @param array $sourceIds |
|
428
|
|
|
* @param $status |
|
429
|
|
|
*/ |
|
430
|
|
|
public function updateConnectItemsStatus(array $sourceIds, $status) |
|
431
|
|
|
{ |
|
432
|
|
|
if (empty($sourceIds)) { |
|
433
|
|
|
return; |
|
434
|
|
|
} |
|
435
|
|
|
|
|
436
|
|
|
$chunks = array_chunk($sourceIds, self::BATCH_SIZE); |
|
437
|
|
|
|
|
438
|
|
|
foreach ($chunks as $chunk) { |
|
439
|
|
|
$builder = $this->manager->getConnection()->createQueryBuilder(); |
|
440
|
|
|
$builder->update('s_plugin_connect_items', 'ci') |
|
441
|
|
|
->set('ci.export_status', ':status') |
|
442
|
|
|
->where('source_id IN (:sourceIds)') |
|
443
|
|
|
->setParameter('sourceIds', $chunk, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY) |
|
444
|
|
|
->setParameter('status', $status) |
|
445
|
|
|
->execute(); |
|
446
|
|
|
} |
|
447
|
|
|
} |
|
448
|
|
|
|
|
449
|
|
|
/** |
|
450
|
|
|
* @param SearchCriteria $criteria |
|
451
|
|
|
* @return ExportList |
|
452
|
|
|
*/ |
|
453
|
|
|
public function getExportList(SearchCriteria $criteria) |
|
454
|
|
|
{ |
|
455
|
|
|
$customProductsTableExists = false; |
|
456
|
|
|
try { |
|
457
|
|
|
$builder = $this->manager->getConnection()->createQueryBuilder(); |
|
458
|
|
|
$builder->select('id'); |
|
459
|
|
|
$builder->from('s_plugin_custom_products_template'); |
|
460
|
|
|
$builder->setMaxResults(1); |
|
461
|
|
|
$builder->execute()->fetch(); |
|
462
|
|
|
|
|
463
|
|
|
$customProductsTableExists = true; |
|
464
|
|
|
} catch (DBALException $e) { |
|
|
|
|
|
|
465
|
|
|
// ignore it |
|
466
|
|
|
// custom products is not installed |
|
467
|
|
|
} |
|
468
|
|
|
|
|
469
|
|
|
$builder = $this->manager->getConnection()->createQueryBuilder(); |
|
470
|
|
|
$builder->select(array( |
|
471
|
|
|
'a.id', |
|
472
|
|
|
'd.ordernumber as number', |
|
473
|
|
|
'd.inStock as inStock', |
|
474
|
|
|
'a.name as name', |
|
475
|
|
|
's.name as supplier', |
|
476
|
|
|
'a.active as active', |
|
477
|
|
|
't.tax as tax', |
|
478
|
|
|
'p.price * (100 + t.tax) / 100 as price', |
|
479
|
|
|
'i.category', |
|
480
|
|
|
'i.export_status as exportStatus', |
|
481
|
|
|
'i.export_message as exportMessage', |
|
482
|
|
|
'i.cron_update as cronUpdate' |
|
483
|
|
|
)) |
|
484
|
|
|
->from('s_plugin_connect_items', 'i') |
|
485
|
|
|
->innerJoin('i', 's_articles', 'a', 'a.id = i.article_id') |
|
486
|
|
|
->innerJoin('a', 's_articles_details', 'd', 'a.main_detail_id = d.id') |
|
487
|
|
|
->leftJoin('d', 's_articles_prices', 'p', 'd.id = p.articledetailsID') |
|
488
|
|
|
->leftJoin('a', 's_core_tax', 't', 'a.taxID = t.id') |
|
489
|
|
|
->leftJoin('a', 's_articles_supplier', 's', 'a.supplierID = s.id') |
|
490
|
|
|
->groupBy('i.article_id') |
|
491
|
|
|
->where('i.shop_id IS NULL'); |
|
492
|
|
|
|
|
493
|
|
|
if ($customProductsTableExists) { |
|
494
|
|
|
$builder->addSelect("IF(spcptpr.template_id > 0, 1, 0) as customProduct") |
|
495
|
|
|
->leftJoin('a', 's_plugin_custom_products_template_product_relation', 'spcptpr', 'a.id = spcptpr.article_id'); |
|
496
|
|
|
} |
|
497
|
|
|
|
|
498
|
|
|
if ($criteria->search) { |
|
499
|
|
|
$builder->andWhere('d.ordernumber LIKE :search OR a.name LIKE :search OR s.name LIKE :search') |
|
500
|
|
|
->setParameter('search', $criteria->search); |
|
501
|
|
|
} |
|
502
|
|
|
|
|
503
|
|
|
if ($criteria->categoryId) { |
|
504
|
|
|
|
|
505
|
|
|
// Get all children categories |
|
506
|
|
|
$qBuilder = $this->manager->getConnection()->createQueryBuilder(); |
|
507
|
|
|
$qBuilder->select('c.id'); |
|
508
|
|
|
$qBuilder->from('s_categories', 'c'); |
|
509
|
|
|
$qBuilder->where('c.path LIKE :categoryIdSearch'); |
|
510
|
|
|
$qBuilder->orWhere('c.id = :categoryId'); |
|
511
|
|
|
$qBuilder->setParameter(':categoryId', $criteria->categoryId); |
|
512
|
|
|
$qBuilder->setParameter(':categoryIdSearch', "%|$criteria->categoryId|%"); |
|
513
|
|
|
|
|
514
|
|
|
$categoryIds = $qBuilder->execute()->fetchAll(\PDO::FETCH_COLUMN); |
|
515
|
|
|
|
|
516
|
|
|
if (count($categoryIds) === 0) { |
|
517
|
|
|
$categoryIds = array($criteria->categoryId); |
|
518
|
|
|
} |
|
519
|
|
|
|
|
520
|
|
|
$builder->innerJoin('a', 's_articles_categories', 'sac', 'a.id = sac.articleID') |
|
521
|
|
|
->andWhere('sac.categoryID IN (:categoryIds)') |
|
522
|
|
|
->setParameter('categoryIds', $categoryIds, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY); |
|
523
|
|
|
} |
|
524
|
|
|
|
|
525
|
|
|
if ($criteria->supplierId) { |
|
526
|
|
|
$builder->andWhere('a.supplierID = :supplierId') |
|
527
|
|
|
->setParameter('supplierId', $criteria->supplierId); |
|
528
|
|
|
} |
|
529
|
|
|
|
|
530
|
|
|
if ($criteria->exportStatus) { |
|
531
|
|
|
$errorStatuses = [Attribute::STATUS_ERROR, Attribute::STATUS_ERROR_PRICE]; |
|
532
|
|
|
|
|
533
|
|
|
if (in_array($criteria->exportStatus, $errorStatuses)) { |
|
534
|
|
|
$builder->andWhere('i.export_status IN (:status)') |
|
535
|
|
|
->setParameter('status', $errorStatuses, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY); |
|
536
|
|
|
} elseif ($criteria->exportStatus == Attribute::STATUS_INACTIVE) { |
|
537
|
|
|
$builder->andWhere('a.active = :status') |
|
538
|
|
|
->setParameter('status', false); |
|
539
|
|
|
} else { |
|
540
|
|
|
$builder->andWhere('i.export_status LIKE :status') |
|
541
|
|
|
->setParameter('status', $criteria->exportStatus); |
|
542
|
|
|
} |
|
543
|
|
|
} |
|
544
|
|
|
|
|
545
|
|
|
if ($criteria->active) { |
|
546
|
|
|
$builder->andWhere('a.active = :active') |
|
547
|
|
|
->setParameter('active', $criteria->active); |
|
548
|
|
|
} |
|
549
|
|
|
|
|
550
|
|
|
if ($criteria->orderBy) { |
|
551
|
|
|
$builder->orderBy($criteria->orderBy, $criteria->orderByDirection); |
|
552
|
|
|
} |
|
553
|
|
|
|
|
554
|
|
|
$total = $builder->execute()->rowCount(); |
|
555
|
|
|
|
|
556
|
|
|
$builder->setFirstResult($criteria->offset); |
|
557
|
|
|
$builder->setMaxResults($criteria->limit); |
|
558
|
|
|
|
|
559
|
|
|
$data = $builder->execute()->fetchAll(); |
|
560
|
|
|
|
|
561
|
|
|
return new ExportList(array( |
|
562
|
|
|
'articles' => $data, |
|
563
|
|
|
'count' => $total, |
|
564
|
|
|
)); |
|
565
|
|
|
} |
|
566
|
|
|
|
|
567
|
|
|
public function clearConnectItems() |
|
568
|
|
|
{ |
|
569
|
|
|
$this->deleteAllConnectProducts(); |
|
570
|
|
|
$this->resetConnectItemsStatus(); |
|
571
|
|
|
} |
|
572
|
|
|
|
|
573
|
|
|
/** |
|
574
|
|
|
* @param $articleId |
|
575
|
|
|
*/ |
|
576
|
|
|
public function markArticleForCronUpdate($articleId) |
|
577
|
|
|
{ |
|
578
|
|
|
$this->manager->getConnection()->update( |
|
579
|
|
|
's_plugin_connect_items', |
|
580
|
|
|
['cron_update' => 1], |
|
581
|
|
|
['article_id' => (int) $articleId] |
|
582
|
|
|
); |
|
583
|
|
|
} |
|
584
|
|
|
|
|
585
|
|
|
/** |
|
586
|
|
|
* Wrapper method |
|
587
|
|
|
* |
|
588
|
|
|
* @param string $sourceId |
|
589
|
|
|
*/ |
|
590
|
|
|
public function recordDelete($sourceId) |
|
591
|
|
|
{ |
|
592
|
|
|
$this->sdk->recordDelete($sourceId); |
|
593
|
|
|
} |
|
594
|
|
|
|
|
595
|
|
|
/** |
|
596
|
|
|
* Deletes products hash |
|
597
|
|
|
*/ |
|
598
|
|
|
private function deleteAllConnectProducts() |
|
599
|
|
|
{ |
|
600
|
|
|
$builder = $this->manager->getConnection()->createQueryBuilder(); |
|
601
|
|
|
$builder->delete('sw_connect_product'); |
|
602
|
|
|
$builder->execute(); |
|
603
|
|
|
} |
|
604
|
|
|
|
|
605
|
|
|
/** |
|
606
|
|
|
* Resets all item status |
|
607
|
|
|
*/ |
|
608
|
|
|
private function resetConnectItemsStatus() |
|
609
|
|
|
{ |
|
610
|
|
|
$builder = $this->manager->getConnection()->createQueryBuilder(); |
|
611
|
|
|
$builder->update('s_plugin_connect_items', 'ci') |
|
612
|
|
|
->set('export_status', ':exportStatus') |
|
613
|
|
|
->set('revision', ':revision') |
|
614
|
|
|
->set('exported', 0) |
|
615
|
|
|
->setParameter('exportStatus', null) |
|
616
|
|
|
->setParameter('revision', null); |
|
617
|
|
|
|
|
618
|
|
|
$builder->execute(); |
|
619
|
|
|
} |
|
620
|
|
|
|
|
621
|
|
|
private function getMarketplaceGateway() |
|
622
|
|
|
{ |
|
623
|
|
|
//todo@fixme: Implement better way to get MarketplaceGateway |
|
624
|
|
|
if (!$this->marketplaceGateway) { |
|
625
|
|
|
$this->marketplaceGateway = new MarketplaceGateway($this->manager); |
|
626
|
|
|
} |
|
627
|
|
|
|
|
628
|
|
|
return $this->marketplaceGateway; |
|
629
|
|
|
} |
|
630
|
|
|
|
|
631
|
|
|
/** |
|
632
|
|
|
* Extracts all marketplaces attributes from product |
|
633
|
|
|
* |
|
634
|
|
|
* @param Detail $detail |
|
635
|
|
|
* @return array |
|
636
|
|
|
*/ |
|
637
|
|
|
private function extractProductAttributes(Detail $detail) |
|
638
|
|
|
{ |
|
639
|
|
|
$marketplaceAttributes = array(); |
|
640
|
|
|
$marketplaceAttributes['purchaseUnit'] = $detail->getPurchaseUnit(); |
|
641
|
|
|
$marketplaceAttributes['referenceUnit'] = $detail->getReferenceUnit(); |
|
642
|
|
|
|
|
643
|
|
|
// marketplace attributes are available only for SEM shops |
|
644
|
|
|
if ($this->configComponent->getConfig('isDefault', true)) { |
|
645
|
|
|
return $marketplaceAttributes; |
|
646
|
|
|
} |
|
647
|
|
|
|
|
648
|
|
|
foreach ($this->getMarketplaceGateway()->getMappings() as $mapping) { |
|
649
|
|
|
$shopwareAttribute = $mapping['shopwareAttributeKey']; |
|
650
|
|
|
$getter = 'get' . ucfirst($shopwareAttribute); |
|
651
|
|
|
|
|
652
|
|
|
if (method_exists($detail->getAttribute(), $getter)) { |
|
653
|
|
|
$marketplaceAttributes[$shopwareAttribute] = $detail->getAttribute()->{$getter}(); |
|
654
|
|
|
} |
|
655
|
|
|
} |
|
656
|
|
|
|
|
657
|
|
|
return $marketplaceAttributes; |
|
658
|
|
|
} |
|
659
|
|
|
} |
Scrutinizer analyzes your
composer.json/composer.lockfile if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.