Passed
Push — master ( 64e7d7...5c5569 )
by Aimeos
04:35
created

StandardTest::testSearchTotal()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 0
dl 0
loc 16
rs 9.9
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2011
6
 * @copyright Aimeos (aimeos.org), 2015-2024
7
 */
8
9
10
namespace Aimeos\MShop\Order\Manager;
11
12
13
class StandardTest extends \PHPUnit\Framework\TestCase
14
{
15
	private $context;
16
	private $object;
17
	private $editor = '';
18
19
20
	protected function setUp() : void
21
	{
22
		$this->context = \TestHelper::context();
23
		$this->editor = $this->context->editor();
24
		$this->object = new \Aimeos\MShop\Order\Manager\Standard( $this->context );
25
	}
26
27
28
	protected function tearDown() : void
29
	{
30
		unset( $this->object );
31
	}
32
33
34
	public function testAggregate()
35
	{
36
		$search = $this->object->filter()->add( ['order.editor' => 'core'] );
37
		$result = $this->object->aggregate( $search, 'order.channel' );
38
39
		$this->assertEquals( 2, count( $result ) );
40
		$this->assertArrayHasKey( 'web', $result );
41
		$this->assertEquals( 3, $result->get( 'web' ) );
42
	}
43
44
45
	public function testAggregateMultiple()
46
	{
47
		$cols = ['order.channel', 'order.statuspayment'];
48
		$search = $this->object->filter()->add( ['order.editor' => 'core'] )->order( $cols );
49
		$result = $this->object->aggregate( $search, $cols );
50
51
		$this->assertEquals( ['phone' => [6 => 1], 'web' => [5 => 1, 6 => 2]], $result->toArray() );
52
	}
53
54
55
	public function testAggregateAvg()
56
	{
57
		$search = $this->object->filter()->add( ['order.editor' => 'core'] );
58
		$result = $this->object->aggregate( $search, 'order.cmonth', 'order.price', 'avg' );
59
60
		$this->assertEquals( 1, count( $result ) );
61
		$this->assertEquals( '784.75', round( $result->first(), 2 ) );
62
	}
63
64
65
	public function testAggregateAvgMultiple()
66
	{
67
		$cols = ['order.cmonth', 'order.statuspayment'];
68
		$search = $this->object->filter()->add( ['order.editor' => 'core'] )->order( $cols );
69
		$result = $this->object->aggregate( $search, $cols, 'order.price', 'avg' );
70
71
		$this->assertEquals( 1, count( $result ) );
72
		$this->assertArrayHasKey( 5, $result->first() );
73
		$this->assertArrayHasKey( 6, $result->first() );
74
		$this->assertEquals( '13.50', round( $result->first()[5], 2 ) );
75
		$this->assertEquals( '1041.83', round( $result->first()[6], 2 ) );
76
	}
77
78
79
	public function testAggregateSum()
80
	{
81
		$search = $this->object->filter()->add( ['order.editor' => 'core'] );
82
		$result = $this->object->aggregate( $search, 'order.cmonth', 'order.price', 'sum' );
83
84
		$this->assertEquals( 1, count( $result ) );
85
		$this->assertEquals( '3139.00', $result->first() );
86
	}
87
88
89
	public function testAggregateSumMultiple()
90
	{
91
		$cols = ['order.cmonth', 'order.statuspayment'];
92
		$search = $this->object->filter()->add( ['order.editor' => 'core'] )->order( $cols );
93
		$result = $this->object->aggregate( $search, $cols, 'order.price', 'sum' );
94
95
		$this->assertEquals( 1, count( $result ) );
96
		$this->assertArrayHasKey( 5, $result->first() );
97
		$this->assertArrayHasKey( 6, $result->first() );
98
		$this->assertEquals( '13.50', round( $result->first()[5], 2 ) );
99
		$this->assertEquals( '3125.5', round( $result->first()[6], 2 ) );
100
	}
101
102
103
	public function testAggregateTimes()
104
	{
105
		$search = $this->object->filter()->add( ['order.editor' => 'core'] );
106
		$search->setSortations( array( $search->sort( '-', 'order.cdate' ) ) );
107
		$result = $this->object->aggregate( $search, 'order.cmonth' )->toArray();
108
109
		$this->assertEquals( 1, count( $result ) );
110
		$this->assertEquals( 4, reset( $result ) );
111
	}
112
113
114
	public function testAggregateAddress()
115
	{
116
		$search = $this->object->filter()->add( ['order.editor' => 'core'] );
117
		$result = $this->object->aggregate( $search, 'order.address.countryid' )->toArray();
118
119
		$this->assertEquals( 1, count( $result ) );
120
		$this->assertArrayHasKey( 'DE', $result );
121
		$this->assertEquals( 4, reset( $result ) );
122
	}
123
124
125
	public function testAggregateAddressMultiple()
126
	{
127
		$cols = ['order.address.countryid', 'order.statuspayment'];
128
		$search = $this->object->filter()->add( ['order.editor' => 'core'] )->order( $cols );
129
		$result = $this->object->aggregate( $search, $cols )->toArray();
130
131
		$this->assertEquals( ['DE' => [5 => 1, 6 => 3]], $result );
132
	}
133
134
135
	public function testAggregateMonth()
136
	{
137
		$search = $this->object->filter()->add( ['order.editor' => 'core'] );
138
		$result = $this->object->aggregate( $search, 'order.channel' )->toArray();
139
140
		$this->assertEquals( 2, count( $result ) );
141
		$this->assertArrayHasKey( 'web', $result );
142
		$this->assertEquals( 3, $result['web'] );
143
	}
144
145
146
	public function testClear()
147
	{
148
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->clear( [-1] ) );
149
	}
150
151
152
	public function testDelete()
153
	{
154
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->delete( [-1] ) );
155
	}
156
157
158
	public function testGetResourceType()
159
	{
160
		$result = $this->object->getResourceType();
161
162
		$this->assertContains( 'order', $result );
163
		$this->assertContains( 'order/status', $result );
164
		$this->assertContains( 'order/address', $result );
165
		$this->assertContains( 'order/coupon', $result );
166
		$this->assertContains( 'order/product', $result );
167
		$this->assertContains( 'order/product/attribute', $result );
168
		$this->assertContains( 'order/service', $result );
169
		$this->assertContains( 'order/service/attribute', $result );
170
	}
171
172
173
	public function testCreate()
174
	{
175
		$this->assertInstanceOf( \Aimeos\MShop\Order\Item\Iface::class, $this->object->create() );
176
	}
177
178
179
	public function testCreateAddress()
180
	{
181
		$this->assertInstanceOf( \Aimeos\MShop\Order\Item\Address\Iface::class, $this->object->createAddress() );
182
	}
183
184
185
	public function testCreateCoupon()
186
	{
187
		$this->assertInstanceOf( \Aimeos\MShop\Order\Item\Coupon\Iface::class, $this->object->createCoupon() );
188
	}
189
190
191
	public function testCreateProduct()
192
	{
193
		$this->assertInstanceOf( \Aimeos\MShop\Order\Item\Product\Iface::class, $this->object->createProduct() );
194
	}
195
196
197
	public function testCreateProductAttribute()
198
	{
199
		$this->assertInstanceOf( \Aimeos\MShop\Order\Item\Product\Attribute\Iface::class, $this->object->createProductAttribute() );
200
	}
201
202
203
	public function testCreateService()
204
	{
205
		$this->assertInstanceOf( \Aimeos\MShop\Order\Item\Service\Iface::class, $this->object->createService() );
206
	}
207
208
209
	public function testCreateServiceAttribute()
210
	{
211
		$this->assertInstanceOf( \Aimeos\MShop\Order\Item\Service\Attribute\Iface::class, $this->object->createServiceAttribute() );
212
	}
213
214
215
	public function testCreateServiceTransaction()
216
	{
217
		$this->assertInstanceOf( \Aimeos\MShop\Order\Item\Service\Transaction\Iface::class, $this->object->createServiceTransaction() );
218
	}
219
220
221
	public function testCreateStatus()
222
	{
223
		$this->assertInstanceOf( \Aimeos\MShop\Order\Item\Status\Iface::class, $this->object->createStatus() );
224
	}
225
226
227
	public function testGet()
228
	{
229
		$search = $this->object->filter()->slice( 0, 1 )
230
			->add( ['order.price' => '672.00', 'order.editor' => $this->editor] );
231
232
		$item = $this->object->search( $search )->first( new \RuntimeException( 'No order item found' ) );
233
234
		$actual = $this->object->get( $item->getId() );
235
236
		$this->assertEquals( $item, $actual );
237
		$this->assertEquals( '32.00', $item->getPrice()->getCosts() );
238
		$this->assertEquals( '5.00', $item->getPrice()->getRebate() );
239
		$this->assertEquals( '112.4034', $item->getPrice()->getTaxValue() );
240
	}
241
242
243
	public function testSaveUpdateDelete()
244
	{
245
		$search = $this->object->filter()->slice( 0, 1 )
246
			->add( ['order.channel' => 'phone', 'order.editor' => $this->editor] );
247
248
		$item = $this->object->search( $search )->first( new \RuntimeException( 'No order item found' ) );
249
250
		$item->setId( null );
251
		$resultSaved = $this->object->save( $item );
252
		$itemSaved = $this->object->get( $item->getId() );
253
254
		$itemExp = clone $itemSaved;
255
		$itemExp->setChannel( 'web' );
256
		$resultUpd = $this->object->save( $itemExp );
257
		$itemUpd = $this->object->get( $itemExp->getId() );
258
259
		$this->object->delete( $itemSaved->getId() );
260
261
262
		$itemPrice = $item->getPrice();
263
		$itemSavedPrice = $itemSaved->getPrice();
264
265
		$this->assertTrue( $item->getId() !== null );
266
		$this->assertEquals( $item->getId(), $itemSaved->getId() );
267
		$this->assertEquals( $item->getSiteId(), $itemSaved->getSiteId() );
268
		$this->assertEquals( $item->getChannel(), $itemSaved->getChannel() );
269
		$this->assertEquals( $item->getDatePayment(), $itemSaved->getDatePayment() );
270
		$this->assertEquals( $item->getDateDelivery(), $itemSaved->getDateDelivery() );
271
		$this->assertEquals( $item->getStatusPayment(), $itemSaved->getStatusPayment() );
272
		$this->assertEquals( $item->getStatusDelivery(), $itemSaved->getStatusDelivery() );
273
		$this->assertEquals( $item->getInvoiceNumber(), $itemSaved->getInvoiceNumber() );
274
		$this->assertEquals( $item->getRelatedId(), $itemSaved->getRelatedId() );
275
		$this->assertEquals( $item->getCustomerId(), $itemSaved->getCustomerId() );
276
		$this->assertEquals( $item->locale()->getLanguageId(), $itemSaved->locale()->getLanguageId() );
277
		$this->assertEquals( $item->getCustomerReference(), $itemSaved->getCustomerReference() );
278
		$this->assertEquals( $item->getComment(), $itemSaved->getComment() );
279
		$this->assertEquals( $item->getSiteCode(), $itemSaved->getSiteCode() );
280
		$this->assertEquals( $itemPrice->getValue(), $itemSavedPrice->getValue() );
281
		$this->assertEquals( $itemPrice->getCosts(), $itemSavedPrice->getCosts() );
282
		$this->assertEquals( $itemPrice->getRebate(), $itemSavedPrice->getRebate() );
283
		$this->assertEquals( $itemPrice->getTaxValue(), $itemSavedPrice->getTaxValue() );
284
		$this->assertEquals( $itemPrice->getCurrencyId(), $itemSavedPrice->getCurrencyId() );
285
286
		$this->assertEquals( $this->editor, $itemSaved->editor() );
287
		$this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeCreated() );
288
		$this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeModified() );
289
290
		$itemExpPrice = $itemExp->getPrice();
291
		$itemUpdPrice = $itemUpd->getPrice();
292
293
		$this->assertEquals( $itemExp->getId(), $itemUpd->getId() );
294
		$this->assertEquals( $itemExp->getSiteId(), $itemUpd->getSiteId() );
295
		$this->assertEquals( $itemExp->getChannel(), $itemUpd->getChannel() );
296
		$this->assertEquals( $itemExp->getDatePayment(), $itemUpd->getDatePayment() );
297
		$this->assertEquals( $itemExp->getDateDelivery(), $itemUpd->getDateDelivery() );
298
		$this->assertEquals( $itemExp->getStatusPayment(), $itemUpd->getStatusPayment() );
299
		$this->assertEquals( $itemExp->getStatusDelivery(), $itemUpd->getStatusDelivery() );
300
		$this->assertEquals( $itemExp->getInvoiceNumber(), $itemUpd->getInvoiceNumber() );
301
		$this->assertEquals( $itemExp->getRelatedId(), $itemUpd->getRelatedId() );
302
		$this->assertEquals( $itemExp->getCustomerId(), $itemUpd->getCustomerId() );
303
		$this->assertEquals( $itemExp->locale()->getLanguageId(), $itemUpd->locale()->getLanguageId() );
304
		$this->assertEquals( $itemExp->getCustomerReference(), $itemUpd->getCustomerReference() );
305
		$this->assertEquals( $itemExp->getComment(), $itemUpd->getComment() );
306
		$this->assertEquals( $itemExp->getSiteCode(), $itemUpd->getSiteCode() );
307
		$this->assertEquals( $itemExpPrice->getValue(), $itemUpdPrice->getValue() );
308
		$this->assertEquals( $itemExpPrice->getCosts(), $itemUpdPrice->getCosts() );
309
		$this->assertEquals( $itemExpPrice->getRebate(), $itemUpdPrice->getRebate() );
310
		$this->assertEquals( $itemExpPrice->getTaxValue(), $itemUpdPrice->getTaxValue() );
311
		$this->assertEquals( $itemExpPrice->getCurrencyId(), $itemUpdPrice->getCurrencyId() );
312
313
		$this->assertEquals( $this->editor, $itemUpd->editor() );
314
		$this->assertEquals( $itemExp->getTimeCreated(), $itemUpd->getTimeCreated() );
315
		$this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemUpd->getTimeModified() );
316
317
		$this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultSaved );
318
		$this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultUpd );
319
320
		$this->expectException( \Aimeos\MShop\Exception::class );
321
		$this->object->get( $itemSaved->getId() );
322
	}
323
324
325
	public function testSaveStatusUpdatePayment()
326
	{
327
		$statusManager = \Aimeos\MShop::create( $this->context, 'order/status' );
328
329
		$search = $this->object->filter();
330
		$conditions = array(
331
			$search->compare( '==', 'order.channel', 'phone' ),
332
			$search->compare( '==', 'order.editor', $this->editor )
333
		);
334
		$search->setConditions( $search->and( $conditions ) );
335
		$results = $this->object->search( $search )->toArray();
336
337
		if( ( $item = reset( $results ) ) === false ) {
338
			throw new \RuntimeException( 'No order item found.' );
339
		}
340
341
		$item->setId( null );
342
		$this->object->save( $item );
343
344
345
		$search = $statusManager->filter();
346
		$search->setConditions( $search->compare( '==', 'order.status.parentid', $item->getId() ) );
347
		$results = $statusManager->search( $search )->toArray();
348
349
		$this->object->delete( $item->getId() );
350
351
		$this->assertEquals( 0, count( $results ) );
352
353
354
		$item->setId( null );
355
		$item->setStatusPayment( \Aimeos\MShop\Order\Item\Base::PAY_CANCELED );
356
		$this->object->save( $item );
357
358
		$search = $statusManager->filter();
359
		$search->setConditions( $search->compare( '==', 'order.status.parentid', $item->getId() ) );
360
		$results = $statusManager->search( $search )->toArray();
361
362
		$this->object->delete( $item->getId() );
363
364
		if( ( $statusItem = reset( $results ) ) === false ) {
365
			throw new \RuntimeException( 'No status item found' );
366
		}
367
368
		$this->assertEquals( 1, count( $results ) );
369
		$this->assertEquals( \Aimeos\MShop\Order\Item\Status\Base::STATUS_PAYMENT, $statusItem->getType() );
370
		$this->assertEquals( \Aimeos\MShop\Order\Item\Base::PAY_CANCELED, $statusItem->getValue() );
371
	}
372
373
374
	public function testSaveStatusUpdateDelivery()
375
	{
376
		$statusManager = \Aimeos\MShop::create( $this->context, 'order/status' );
377
378
		$search = $this->object->filter();
379
		$conditions = array(
380
			$search->compare( '==', 'order.channel', 'phone' ),
381
			$search->compare( '==', 'order.editor', $this->editor )
382
		);
383
		$search->setConditions( $search->and( $conditions ) );
384
		$results = $this->object->search( $search )->toArray();
385
386
		if( ( $item = reset( $results ) ) === false ) {
387
			throw new \RuntimeException( 'No order item found.' );
388
		}
389
390
		$item->setId( null );
391
		$this->object->save( $item );
392
393
394
		$search = $statusManager->filter();
395
		$search->setConditions( $search->compare( '==', 'order.status.parentid', $item->getId() ) );
396
		$results = $statusManager->search( $search )->toArray();
397
398
		$this->object->delete( $item->getId() );
399
400
		$this->assertEquals( 0, count( $results ) );
401
402
403
		$item->setId( null );
404
		$item->setStatusDelivery( \Aimeos\MShop\Order\Item\Base::STAT_LOST );
405
		$this->object->save( $item );
406
407
		$search = $statusManager->filter();
408
		$search->setConditions( $search->compare( '==', 'order.status.parentid', $item->getId() ) );
409
		$results = $statusManager->search( $search )->toArray();
410
411
		$this->object->delete( $item->getId() );
412
413
		if( ( $statusItem = reset( $results ) ) === false ) {
414
			throw new \RuntimeException( 'No status item found' );
415
		}
416
417
		$this->assertEquals( 1, count( $results ) );
418
		$this->assertEquals( \Aimeos\MShop\Order\Item\Status\Base::STATUS_DELIVERY, $statusItem->getType() );
419
		$this->assertEquals( \Aimeos\MShop\Order\Item\Base::STAT_LOST, $statusItem->getValue() );
420
	}
421
422
423
	public function testFilter()
424
	{
425
		$this->assertInstanceOf( \Aimeos\Base\Criteria\Iface::class, $this->object->filter() );
426
	}
427
428
429
	public function testFilterDefault()
430
	{
431
		$search = $this->object->filter( true );
432
433
		$this->assertInstanceOf( \Aimeos\Base\Criteria\Iface::class, $search );
434
		$this->assertInstanceOf( \Aimeos\Base\Criteria\Expression\Combine\Iface::class, $search->getConditions() );
435
436
		$list = $search->getConditions()->getExpressions();
437
		$this->assertArrayHasKey( 0, $list );
438
		$this->assertInstanceOf( \Aimeos\Base\Criteria\Expression\Combine\Iface::class, $list[0] );
439
	}
440
441
442
	public function testFilterSite()
443
	{
444
		$result = $this->object->filter( false, true );
445
		$this->assertInstanceOf( \Aimeos\Base\Criteria\Expression\Combine\Iface::class, $result->getConditions() );
446
	}
447
448
449
	public function testSearch()
450
	{
451
		$siteid = $this->context->locale()->getSiteId();
452
453
		$total = 0;
454
		$search = $this->object->filter();
455
		$funcStatus = $search->make( 'order:status', ['typestatus', 'shipped'] );
456
457
		$expr = [];
458
		$expr[] = $search->compare( '!=', 'order.id', null );
459
		$expr[] = $search->compare( '==', 'order.siteid', $siteid );
460
		$expr[] = $search->compare( '==', 'order.channel', 'web' );
461
		$expr[] = $search->compare( '==', 'order.invoiceno', 'UINV-001' );
462
		$expr[] = $search->compare( '==', 'order.datepayment', '2008-02-15 12:34:56' );
463
		$expr[] = $search->compare( '==', 'order.datedelivery', null );
464
		$expr[] = $search->compare( '==', 'order.statuspayment', \Aimeos\MShop\Order\Item\Base::PAY_RECEIVED );
465
		$expr[] = $search->compare( '==', 'order.statusdelivery', 4 );
466
		$expr[] = $search->compare( '==', 'order.relatedid', '' );
467
		$expr[] = $search->compare( '==', 'order.sitecode', 'unittest' );
468
		$expr[] = $search->compare( '>=', 'order.customerid', '' );
469
		$expr[] = $search->compare( '==', 'order.languageid', 'de' );
470
		$expr[] = $search->compare( '==', 'order.currencyid', 'EUR' );
471
		$expr[] = $search->compare( '==', 'order.price', '53.50' );
472
		$expr[] = $search->compare( '==', 'order.costs', '1.50' );
473
		$expr[] = $search->compare( '==', 'order.rebate', '14.50' );
474
		$expr[] = $search->compare( '~=', 'order.comment', 'This is a comment' );
475
		$expr[] = $search->compare( '>=', 'order.mtime', '1970-01-01 00:00:00' );
476
		$expr[] = $search->compare( '>=', 'order.ctime', '1970-01-01 00:00:00' );
477
		$expr[] = $search->compare( '==', 'order.editor', $this->editor );
478
		$expr[] = $search->compare( '==', $funcStatus, 1 );
479
480
		$expr[] = $search->compare( '!=', 'order.status.id', null );
481
		$expr[] = $search->compare( '==', 'order.status.siteid', $siteid );
482
		$expr[] = $search->compare( '!=', 'order.status.parentid', null );
483
		$expr[] = $search->compare( '>=', 'order.status.type', 'typestatus' );
484
		$expr[] = $search->compare( '==', 'order.status.value', 'shipped' );
485
		$expr[] = $search->compare( '>=', 'order.status.mtime', '1970-01-01 00:00:00' );
486
		$expr[] = $search->compare( '>=', 'order.status.ctime', '1970-01-01 00:00:00' );
487
		$expr[] = $search->compare( '==', 'order.status.editor', $this->editor );
488
489
		$expr[] = $search->compare( '!=', 'order.address.id', null );
490
		$expr[] = $search->compare( '==', 'order.address.siteid', $siteid );
491
		$expr[] = $search->compare( '!=', 'order.address.parentid', null );
492
		$expr[] = $search->compare( '==', 'order.address.type', 'payment' );
493
		$expr[] = $search->compare( '==', 'order.address.company', 'Example company' );
494
		$expr[] = $search->compare( '==', 'order.address.vatid', 'DE999999999' );
495
		$expr[] = $search->compare( '==', 'order.address.salutation', 'mr' );
496
		$expr[] = $search->compare( '==', 'order.address.title', '' );
497
		$expr[] = $search->compare( '==', 'order.address.firstname', 'Our' );
498
		$expr[] = $search->compare( '==', 'order.address.lastname', 'Unittest' );
499
		$expr[] = $search->compare( '==', 'order.address.address1', 'Durchschnitt' );
500
		$expr[] = $search->compare( '==', 'order.address.address2', '1' );
501
		$expr[] = $search->compare( '==', 'order.address.address3', '' );
502
		$expr[] = $search->compare( '==', 'order.address.postal', '20146' );
503
		$expr[] = $search->compare( '==', 'order.address.city', 'Hamburg' );
504
		$expr[] = $search->compare( '==', 'order.address.state', 'Hamburg' );
505
		$expr[] = $search->compare( '==', 'order.address.countryid', 'DE' );
506
		$expr[] = $search->compare( '==', 'order.address.languageid', 'de' );
507
		$expr[] = $search->compare( '==', 'order.address.telephone', '055544332211' );
508
		$expr[] = $search->compare( '==', 'order.address.telefax', '055544332212' );
509
		$expr[] = $search->compare( '==', 'order.address.mobile', '055544332213' );
510
		$expr[] = $search->compare( '==', 'order.address.email', '[email protected]' );
511
		$expr[] = $search->compare( '==', 'order.address.website', 'www.example.net' );
512
		$expr[] = $search->compare( '>=', 'order.address.mtime', '1970-01-01 00:00:00' );
513
		$expr[] = $search->compare( '>=', 'order.address.ctime', '1970-01-01 00:00:00' );
514
		$expr[] = $search->compare( '==', 'order.address.editor', $this->editor );
515
516
		$expr[] = $search->compare( '!=', 'order.coupon.id', null );
517
		$expr[] = $search->compare( '==', 'order.coupon.siteid', $siteid );
518
		$expr[] = $search->compare( '!=', 'order.coupon.parentid', null );
519
		$expr[] = $search->compare( '!=', 'order.coupon.productid', null );
520
		$expr[] = $search->compare( '==', 'order.coupon.code', 'OPQR' );
521
		$expr[] = $search->compare( '>=', 'order.coupon.mtime', '1970-01-01 00:00:00' );
522
		$expr[] = $search->compare( '>=', 'order.coupon.ctime', '1970-01-01 00:00:00' );
523
		$expr[] = $search->compare( '>=', 'order.coupon.editor', '' );
524
525
		$expr[] = $search->compare( '!=', 'order.product.id', null );
526
		$expr[] = $search->compare( '==', 'order.product.siteid', $siteid );
527
		$expr[] = $search->compare( '!=', 'order.product.parentid', null );
528
		$expr[] = $search->compare( '!=', 'order.product.productid', null );
529
		$expr[] = $search->compare( '==', 'order.product.prodcode', 'CNE' );
530
		$expr[] = $search->compare( '==', 'order.product.vendor', 'Test vendor' );
531
		$expr[] = $search->compare( '==', 'order.product.name', 'Cafe Noire Expresso' );
532
		$expr[] = $search->compare( '==', 'order.product.mediaurl', 'somewhere/thump1.jpg' );
533
		$expr[] = $search->compare( '==', 'order.product.quantity', 9 );
534
		$expr[] = $search->compare( '==', 'order.product.price', '4.50' );
535
		$expr[] = $search->compare( '==', 'order.product.costs', '0.00' );
536
		$expr[] = $search->compare( '==', 'order.product.rebate', '0.00' );
537
		$expr[] = $search->compare( '=~', 'order.product.taxrates', '{' );
538
		$expr[] = $search->compare( '==', 'order.product.flags', 0 );
539
		$expr[] = $search->compare( '==', 'order.product.position', 1 );
540
		$expr[] = $search->compare( '==', 'order.product.statuspayment', 5 );
541
		$expr[] = $search->compare( '==', 'order.product.statusdelivery', 1 );
542
		$expr[] = $search->compare( '>=', 'order.product.mtime', '1970-01-01 00:00:00' );
543
		$expr[] = $search->compare( '>=', 'order.product.ctime', '1970-01-01 00:00:00' );
544
		$expr[] = $search->compare( '==', 'order.product.editor', $this->editor );
545
546
		$expr[] = $search->compare( '!=', 'order.product.attribute.id', null );
547
		$expr[] = $search->compare( '==', 'order.product.attribute.siteid', $siteid );
548
		$expr[] = $search->compare( '!=', 'order.product.attribute.parentid', null );
549
		$expr[] = $search->compare( '==', 'order.product.attribute.code', 'width' );
550
		$expr[] = $search->compare( '==', 'order.product.attribute.value', '33' );
551
		$expr[] = $search->compare( '==', 'order.product.attribute.name', '33' );
552
		$expr[] = $search->compare( '==', 'order.product.attribute.quantity', 1 );
553
		$expr[] = $search->compare( '>=', 'order.product.attribute.mtime', '1970-01-01 00:00:00' );
554
		$expr[] = $search->compare( '>=', 'order.product.attribute.ctime', '1970-01-01 00:00:00' );
555
		$expr[] = $search->compare( '==', 'order.product.attribute.editor', $this->editor );
556
557
		$expr[] = $search->compare( '!=', 'order.service.id', null );
558
		$expr[] = $search->compare( '==', 'order.service.siteid', $siteid );
559
		$expr[] = $search->compare( '!=', 'order.service.parentid', null );
560
		$expr[] = $search->compare( '==', 'order.service.type', 'payment' );
561
		$expr[] = $search->compare( '==', 'order.service.code', 'unitpaymentcode' );
562
		$expr[] = $search->compare( '==', 'order.service.name', 'unitpaymentcode' );
563
		$expr[] = $search->compare( '==', 'order.service.price', '0.00' );
564
		$expr[] = $search->compare( '==', 'order.service.costs', '0.00' );
565
		$expr[] = $search->compare( '==', 'order.service.rebate', '0.00' );
566
		$expr[] = $search->compare( '=~', 'order.service.taxrates', '{' );
567
		$expr[] = $search->compare( '>=', 'order.service.mtime', '1970-01-01 00:00:00' );
568
		$expr[] = $search->compare( '>=', 'order.service.ctime', '1970-01-01 00:00:00' );
569
		$expr[] = $search->compare( '==', 'order.service.editor', $this->editor );
570
571
		$expr[] = $search->compare( '!=', 'order.service.attribute.id', null );
572
		$expr[] = $search->compare( '==', 'order.service.attribute.siteid', $siteid );
573
		$expr[] = $search->compare( '!=', 'order.service.attribute.parentid', null );
574
		$expr[] = $search->compare( '==', 'order.service.attribute.code', 'NAME' );
575
		$expr[] = $search->compare( '==', 'order.service.attribute.value', '"CreditCard"' );
576
		$expr[] = $search->compare( '==', 'order.service.attribute.quantity', 1 );
577
		$expr[] = $search->compare( '>=', 'order.service.attribute.mtime', '1970-01-01 00:00:00' );
578
		$expr[] = $search->compare( '>=', 'order.service.attribute.ctime', '1970-01-01 00:00:00' );
579
		$expr[] = $search->compare( '==', 'order.service.attribute.editor', $this->editor );
580
581
582
583
		$search->setConditions( $search->and( $expr ) );
584
		$result = $this->object->search( $search, [], $total )->toArray();
585
586
		$this->assertEquals( 1, count( $result ) );
587
		$this->assertEquals( 1, $total );
588
	}
589
590
591
	public function testSearchTotal()
592
	{
593
		$total = 0;
594
		$search = $this->object->filter()->slice( 0, 1 );
595
		$conditions = array(
596
			$search->compare( '==', 'order.statuspayment', \Aimeos\MShop\Order\Item\Base::PAY_RECEIVED ),
597
			$search->compare( '==', 'order.editor', $this->editor )
598
		);
599
		$search->setConditions( $search->and( $conditions ) );
600
		$items = $this->object->search( $search, [], $total )->toArray();
601
602
		$this->assertEquals( 1, count( $items ) );
603
		$this->assertEquals( 3, $total );
604
605
		foreach( $items as $itemId => $item ) {
606
			$this->assertEquals( $itemId, $item->getId() );
607
		}
608
	}
609
610
611
	public function testSearchRef()
612
	{
613
		$total = 0;
614
		$search = $this->object->filter()->slice( 0, 1 );
615
		$conditions = array(
616
			$search->compare( '==', 'order.datepayment', '2008-02-15 12:34:56' ),
617
			$search->compare( '==', 'order.editor', $this->editor )
618
		);
619
		$search->setConditions( $search->and( $conditions ) );
620
		$item = $this->object->search( $search, ['order/address', 'order/coupon', 'order/product', 'order/service'], $total )->first();
621
622
		$this->assertEquals( 2, count( $item->getAddresses() ) );
623
		$this->assertEquals( 2, count( $item->getCoupons() ) );
624
		$this->assertEquals( 4, count( $item->getProducts() ) );
625
		$this->assertEquals( 2, count( $item->getServices() ) );
626
	}
627
628
629
	public function testGetSubManager()
630
	{
631
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->getSubManager( 'address' ) );
632
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->getSubManager( 'address', 'Standard' ) );
633
634
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->getSubManager( 'coupon' ) );
635
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->getSubManager( 'coupon', 'Standard' ) );
636
637
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->getSubManager( 'product' ) );
638
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->getSubManager( 'product', 'Standard' ) );
639
640
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->getSubManager( 'service' ) );
641
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->getSubManager( 'service', 'Standard' ) );
642
643
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->getSubManager( 'status' ) );
644
		$this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->getSubManager( 'status', 'Standard' ) );
645
646
		$this->expectException( \LogicException::class );
647
		$this->object->getSubManager( 'unknown' );
648
	}
649
650
651
	public function testGetSubManagerInvalidName()
652
	{
653
		$this->expectException( \LogicException::class );
654
		$this->object->getSubManager( 'status', 'unknown' );
655
	}
656
657
658
	public function testSave()
659
	{
660
		$item = $this->getOrderItem();
661
		$ref = ['order/address', 'order/coupon', 'order/product', 'order/service'];
662
663
		$basket = $this->getBasket( $item->getId(), $ref, true );
664
		$this->object->save( $basket );
665
666
		$newBasketId = $basket->getId();
667
668
		$basket = $this->getBasket( $newBasketId, $ref );
669
		$this->object->delete( $newBasketId );
670
671
672
		$this->assertEquals( $item->getCustomerId(), $basket->getCustomerId() );
673
		$this->assertEquals( $basket->locale()->getSiteId(), $basket->getSiteId() );
674
675
		$this->assertEquals( 1.50, $basket->getPrice()->getCosts() );
676
677
		$pos = 1;
678
		$products = $basket->getProducts();
679
		$this->assertEquals( 4, count( $products ) );
680
681
		foreach( $products as $product )
682
		{
683
			if( $product->getProductCode() != 'U:MD' ) {
684
				$this->assertGreaterThanOrEqual( 2, count( $product->getAttributeItems() ) );
685
			}
686
			$this->assertEquals( $pos++, $product->getPosition() );
687
		}
688
689
		$this->assertEquals( 2, count( $basket->getAddresses() ) );
690
691
		$services = $basket->getServices();
692
		$this->assertEquals( 2, count( $services ) );
693
694
		$attributes = [];
695
		foreach( $services as $list )
696
		{
697
			foreach( $list as $service ) {
698
				$attributes[$service->getCode()] = $service->getAttributeItems();
699
			}
700
		}
701
702
		$this->assertEquals( 9, count( $attributes['unitpaymentcode'] ) );
703
		$this->assertEquals( 0, count( $attributes['unitdeliverycode'] ) );
704
705
		$this->expectException( \Aimeos\MShop\Exception::class );
706
		$this->object->get( $newBasketId );
707
	}
708
709
710
	public function testSaveExisting()
711
	{
712
		$item = $this->getOrderItem();
713
		$ref = ['order/address', 'order/coupon', 'order/product', 'order/service'];
714
715
		$basket = $this->getBasket( $item->getId(), $ref, true );
716
		$this->object->save( $basket );
717
		$newBasketId = $basket->getId();
718
		$this->object->save( $basket );
719
		$newBasket = $this->getBasket( $newBasketId, $ref );
720
721
		$this->object->delete( $newBasketId );
722
723
		foreach( $basket->getAddresses() as $type => $list )
724
		{
725
			$this->assertTrue( map( $list )->getId()->equals( map( $newBasket->getAddress( $type ) )->getId() ) );
726
		}
727
728
		$this->assertTrue( $basket->getProducts()->getId()->equals( $newBasket->getProducts()->getId() ) );
729
730
		foreach( $basket->getServices() as $type => $list )
731
		{
732
			$this->assertTrue( map( $list )->getId()->equals( map( $newBasket->getService( $type ) )->getId() ) );
733
		}
734
	}
735
736
737
	public function testSaveBundles()
738
	{
739
		$search = $this->object->filter()->add( ['order.sitecode' => 'unittest', 'order.price' => 2400.00] );
740
		$item = $this->object->search( $search )->first( new \RuntimeException( 'No order found' ) );
741
742
		$ref = ['order/address', 'order/coupon', 'order/product', 'order/service'];
743
		$basket = $this->getBasket( $item->getId(), $ref, true );
744
		$this->object->save( $basket );
745
746
		$newBasketId = $basket->getId();
747
748
		$basket = $this->getBasket( $newBasketId, $ref );
749
		$this->object->delete( $newBasketId );
750
751
		$this->assertEquals( $item->getCustomerId(), $basket->getCustomerId() );
752
		$this->assertEquals( $basket->locale()->getSiteId(), $basket->getSiteId() );
753
754
		$pos = 1;
755
		$products = $basket->getProducts();
756
757
		$this->assertEquals( 2, count( $products ) );
758
		foreach( $products as $product )
759
		{
760
			$this->assertEquals( 2, count( $product->getProducts() ) );
761
			$this->assertEquals( $pos, $product->getPosition() );
762
			$pos += 3; // two sub-products in between
763
		}
764
765
		$this->expectException( \Aimeos\MShop\Exception::class );
766
		$this->object->get( $newBasketId );
767
	}
768
769
770
	public function testSaveAddress()
771
	{
772
		$item = $this->getOrderItem();
773
774
		$basket = $this->getBasket( $item->getId(), ['order/address'], true );
775
		$this->object->save( $basket );
776
777
		$newBasketId = $basket->getId();
778
779
		$ref = ['order/address', 'order/coupon', 'order/product', 'order/service'];
780
		$basket = $this->getBasket( $newBasketId, $ref );
781
		$this->object->delete( $newBasketId );
782
783
		$this->assertGreaterThan( 0, count( $basket->getAddresses() ) );
784
		$this->assertEquals( [], $basket->getProducts()->toArray() );
785
		$this->assertEquals( [], $basket->getCoupons()->toArray() );
786
		$this->assertEquals( [], $basket->getServices()->toArray() );
787
	}
788
789
790
	public function testSaveProduct()
791
	{
792
		$item = $this->getOrderItem();
793
794
		$basket = $this->getBasket( $item->getId(), ['order/product'], true );
795
		$this->object->save( $basket );
796
797
		$newBasketId = $basket->getId();
798
799
		$ref = ['order/address', 'order/coupon', 'order/product', 'order/service'];
800
		$basket = $this->getBasket( $newBasketId, $ref );
801
		$this->object->delete( $newBasketId );
802
803
		$this->assertGreaterThan( 0, count( $basket->getProducts() ) );
804
		$this->assertEquals( [], $basket->getAddresses()->toArray() );
805
		$this->assertEquals( [], $basket->getCoupons()->toArray() );
806
		$this->assertEquals( [], $basket->getServices()->toArray() );
807
	}
808
809
810
	public function testSaveService()
811
	{
812
		$item = $this->getOrderItem();
813
814
		$basket = $this->getBasket( $item->getId(), ['order/service'], true );
815
		$this->object->save( $basket );
816
817
		$newBasketId = $basket->getId();
818
819
		$ref = ['order/address', 'order/coupon', 'order/product', 'order/service'];
820
		$basket = $this->getBasket( $newBasketId, $ref );
821
		$this->object->delete( $newBasketId );
822
823
		$this->assertGreaterThan( 0, count( $basket->getServices() ) );
824
		$this->assertEquals( [], $basket->getProducts()->toArray() );
825
		$this->assertEquals( [], $basket->getAddresses()->toArray() );
826
		$this->assertEquals( [], $basket->getCoupons()->toArray() );
827
	}
828
829
830
	public function testLoadSaveCoupons()
831
	{
832
		$ref = ['order/address', 'order/product', 'order/service'];
833
834
		$search = $this->object->filter()->add( ['order.price' => '53.50'] );
835
		$item = $this->object->search( $search )->first( new \RuntimeException( 'No order found' ) );
836
837
		$basket = $this->getBasket( $item->getId(), $ref, true );
838
839
		$this->assertEquals( '53.50', $basket->getPrice()->getValue() );
840
		$this->assertEquals( '1.50', $basket->getPrice()->getCosts() );
841
		$this->assertEquals( '14.50', $basket->getPrice()->getRebate() );
842
		$this->assertEquals( 0, count( $basket->getCoupons() ) );
843
844
		$basket->addCoupon( 'CDEF' );
845
		$basket->addCoupon( '90AB' );
846
847
		$this->assertEquals( '47.05', $basket->getPrice()->getValue() );
848
		$this->assertEquals( '1.50', $basket->getPrice()->getCosts() );
849
		$this->assertEquals( '20.95', $basket->getPrice()->getRebate() );
850
		$this->assertEquals( 2, count( $basket->getCoupons() ) );
851
852
		$this->object->save( $basket );
853
854
		$ref = ['order/address', 'order/coupon', 'order/product', 'order/service'];
855
856
		$newBasket = $this->object->get( $basket->getId(), $ref );
857
		$this->object->delete( $newBasket->getId() );
858
859
		$this->assertEquals( '47.05', $newBasket->getPrice()->getValue() );
860
		$this->assertEquals( '1.50', $newBasket->getPrice()->getCosts() );
861
		$this->assertEquals( '20.95', $newBasket->getPrice()->getRebate() );
862
		$this->assertEquals( 2, count( $newBasket->getCoupons() ) );
863
	}
864
865
866
	public function testSaveStatus()
867
	{
868
		$item = $this->getOrderItem();
869
870
		$basket = $this->getBasket( $item->getId(), ['order/status'], true );
871
		$this->object->save( $basket );
872
873
		$newBasketId = $basket->getId();
874
875
		$basket = $this->getBasket( $newBasketId, ['order/status'] );
876
		$this->object->delete( $newBasketId );
877
878
		$this->assertGreaterThan( 0, count( $basket->getStatusItems() ) );
879
	}
880
881
882
	/**
883
	 * Returns the basket object
884
	 *
885
	 * @param string|null $id Unique order ID
886
	 * @param array $ref List of items that should be fetched too
887
	 * @param bool $fresh TRUE to return items without IDs
888
	 * @return \Aimeos\MShop\Order\Item\Iface Order base item
889
	 * @throws \Exception If no found
890
	 */
891
	protected function getBasket( ?string $id, array $ref = [], bool $fresh = false )
892
	{
893
		if( $id === null ) {
894
			throw new \Exception( 'ID can not be NULL' );
895
		}
896
897
		$basket = $this->object->get( $id, $ref );
898
899
		if( $fresh )
900
		{
901
			$basket->setId( null );
902
903
			$basket->getAddresses()->flat( 1 )->setParentId( null )->setId( null );
904
			$basket->getServices()->flat( 1 )->setParentId( null )->setId( null );
905
906
			$basket->getProducts()->merge( $basket->getProducts()->getProducts()->flat( 1 ) )
907
				->setParentId( null )->setPosition( null )->setId( null );
908
909
			$basket->getStatusItems()->setParentId( null )->setId( null );
910
		}
911
912
		return $basket;
913
	}
914
915
916
	/**
917
	 * Returns an order base item
918
	 *
919
	 * @return \Aimeos\MShop\Order\Item\Iface Order base item
920
	 * @throws \Exception If no found
921
	 */
922
	protected function getOrderItem()
923
	{
924
		$search = $this->object->filter()->add( [
925
			'order.sitecode' => 'unittest',
926
			'order.price' => 53.50,
927
			'order.rebate' => 14.50,
928
			'order.editor' => $this->editor
929
		] );
930
931
		return $this->object->search( $search )->first( new \RuntimeException( 'No order found' ) );
932
	}
933
}
934