Skip to content

Commit 1fb7bc6

Browse files
mglamanbojanz
mglaman
authored andcommitted
Issue #2881791 by mglaman, agoradesign: Computed field value for DateTime field causes start time validation error
1 parent f720b77 commit 1fb7bc6

File tree

4 files changed

+194
-69
lines changed

4 files changed

+194
-69
lines changed

modules/payment/src/Plugin/Commerce/PaymentGateway/Manual.php

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace Drupal\commerce_payment\Plugin\Commerce\PaymentGateway;
44

55
use Drupal\commerce_payment\Entity\PaymentInterface;
6-
use Drupal\commerce_payment\Exception\InvalidRequestException;
76
use Drupal\commerce_price\Price;
87
use Drupal\Core\Form\FormStateInterface;
98

modules/promotion/src/Entity/Promotion.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ public function setUsageLimit($usage_limit) {
260260
* {@inheritdoc}
261261
*/
262262
public function getStartDate() {
263-
return $this->get('start_date')->date;
263+
// Can't use the ->date property because it resets the timezone to UTC.
264+
return new DrupalDateTime($this->get('start_date')->value);
264265
}
265266

266267
/**
@@ -275,7 +276,9 @@ public function setStartDate(DrupalDateTime $start_date) {
275276
* {@inheritdoc}
276277
*/
277278
public function getEndDate() {
278-
return $this->get('end_date')->date;
279+
if (!$this->get('end_date')->isEmpty()) {
280+
return new DrupalDateTime($this->get('end_date')->value);
281+
}
279282
}
280283

281284
/**

modules/promotion/tests/src/Kernel/Entity/PromotionTest.php

-66
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@
22

33
namespace Drupal\Tests\commerce_promotion\Kernel\Entity;
44

5-
use Drupal\commerce_order\Entity\Order;
6-
use Drupal\commerce_order\Entity\OrderItem;
75
use Drupal\commerce_order\Entity\OrderItemType;
86
use Drupal\commerce_order\Entity\OrderType;
9-
use Drupal\commerce_price\Price;
107
use Drupal\commerce_promotion\Entity\Coupon;
118
use Drupal\commerce_promotion\Entity\Promotion;
12-
use Drupal\Component\Datetime\TimeInterface;
139
use Drupal\Core\Datetime\DrupalDateTime;
1410
use Drupal\Tests\commerce\Kernel\CommerceKernelTestBase;
1511

@@ -153,66 +149,4 @@ public function testPromotion() {
153149
$this->assertEquals(TRUE, $promotion->isEnabled());
154150
}
155151

156-
/**
157-
* @covers ::available
158-
*/
159-
public function testAvailability() {
160-
$this->installSchema('commerce_promotion', ['commerce_promotion_usage']);
161-
$order_item = OrderItem::create([
162-
'type' => 'test',
163-
'quantity' => 1,
164-
'unit_price' => new Price('12.00', 'USD'),
165-
]);
166-
$order_item->save();
167-
$order = Order::create([
168-
'type' => 'default',
169-
'state' => 'draft',
170-
'mail' => '[email protected]',
171-
'ip_address' => '127.0.0.1',
172-
'order_number' => '6',
173-
'store_id' => $this->store,
174-
'uid' => $this->createUser(),
175-
'order_items' => [$order_item],
176-
]);
177-
$order->setRefreshState(Order::REFRESH_SKIP);
178-
$order->save();
179-
180-
$promotion = Promotion::create([
181-
'order_types' => ['default'],
182-
'stores' => [$this->store->id()],
183-
'usage_limit' => 1,
184-
'start_date' => '2017-01-01',
185-
'status' => TRUE,
186-
]);
187-
$promotion->save();
188-
$this->assertTrue($promotion->available($order));
189-
190-
$promotion->setEnabled(FALSE);
191-
$this->assertFalse($promotion->available($order));
192-
$promotion->setEnabled(TRUE);
193-
194-
$promotion->setOrderTypeIds(['test']);
195-
$this->assertFalse($promotion->available($order));
196-
$promotion->setOrderTypeIds(['default']);
197-
198-
$promotion->setStoreIds(['90']);
199-
$this->assertFalse($promotion->available($order));
200-
$promotion->setStoreIds([$this->store->id()]);
201-
202-
$fake_time = $this->prophesize(TimeInterface::class);
203-
$fake_time->getRequestTime()->willReturn(mktime(0, 0, 0, '01', '15', '2016'));
204-
$this->container->set('datetime.time', $fake_time->reveal());
205-
$this->assertFalse($promotion->available($order));
206-
207-
$fake_time = $this->prophesize(TimeInterface::class);
208-
$fake_time->getRequestTime()->willReturn(mktime(0, 0, 0, '01', '15', '2017'));
209-
$this->container->set('datetime.time', $fake_time->reveal());
210-
$promotion->setEndDate(new DrupalDateTime('2017-01-14'));
211-
$this->assertFalse($promotion->available($order));
212-
$promotion->setEndDate(NULL);
213-
214-
\Drupal::service('commerce_promotion.usage')->addUsage($order, $promotion);
215-
$this->assertFalse($promotion->available($order));
216-
}
217-
218152
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?php
2+
3+
namespace Drupal\Tests\commerce_promotion\Kernel;
4+
5+
use Drupal\commerce_order\Entity\Order;
6+
use Drupal\commerce_order\Entity\OrderItem;
7+
use Drupal\commerce_order\Entity\OrderItemType;
8+
use Drupal\commerce_price\Price;
9+
use Drupal\commerce_promotion\Entity\Promotion;
10+
use Drupal\Core\Datetime\DrupalDateTime;
11+
use Drupal\Tests\commerce\Kernel\CommerceKernelTestBase;
12+
13+
/**
14+
* Tests the promotion availability logic.
15+
*
16+
* @group commerce
17+
*/
18+
class PromotionAvailabilityTest extends CommerceKernelTestBase {
19+
20+
/**
21+
* Modules to enable.
22+
*
23+
* @var array
24+
*/
25+
public static $modules = [
26+
'entity_reference_revisions',
27+
'profile',
28+
'state_machine',
29+
'commerce_order',
30+
'commerce_product',
31+
'commerce_promotion',
32+
];
33+
34+
/**
35+
* The test order.
36+
*
37+
* @var \Drupal\commerce_order\Entity\OrderInterface
38+
*/
39+
protected $order;
40+
41+
/**
42+
* {@inheritdoc}
43+
*/
44+
protected function setUp() {
45+
parent::setUp();
46+
47+
$this->installEntitySchema('profile');
48+
$this->installEntitySchema('commerce_order');
49+
$this->installEntitySchema('commerce_order_item');
50+
$this->installEntitySchema('commerce_promotion');
51+
$this->installEntitySchema('commerce_promotion_coupon');
52+
$this->installSchema('commerce_promotion', ['commerce_promotion_usage']);
53+
$this->installConfig([
54+
'profile',
55+
'commerce_order',
56+
'commerce_promotion',
57+
]);
58+
59+
OrderItemType::create([
60+
'id' => 'test',
61+
'label' => 'Test',
62+
'orderType' => 'default',
63+
])->save();
64+
65+
$order_item = OrderItem::create([
66+
'type' => 'test',
67+
'quantity' => 1,
68+
'unit_price' => new Price('12.00', 'USD'),
69+
]);
70+
$order_item->save();
71+
$order = Order::create([
72+
'type' => 'default',
73+
'state' => 'draft',
74+
'mail' => '[email protected]',
75+
'ip_address' => '127.0.0.1',
76+
'order_number' => '6',
77+
'store_id' => $this->store,
78+
'uid' => $this->createUser(),
79+
'order_items' => [$order_item],
80+
]);
81+
$order->setRefreshState(Order::REFRESH_SKIP);
82+
$order->save();
83+
$this->order = $this->reloadEntity($order);
84+
}
85+
86+
/**
87+
* Test general availability.
88+
*/
89+
public function testAvailability() {
90+
$promotion = Promotion::create([
91+
'order_types' => ['default'],
92+
'stores' => [$this->store->id()],
93+
'usage_limit' => 2,
94+
'status' => TRUE,
95+
]);
96+
$promotion->save();
97+
$this->assertTrue($promotion->available($this->order));
98+
99+
$promotion->setEnabled(FALSE);
100+
$this->assertFalse($promotion->available($this->order));
101+
$promotion->setEnabled(TRUE);
102+
103+
$promotion->setOrderTypeIds(['test']);
104+
$this->assertFalse($promotion->available($this->order));
105+
$promotion->setOrderTypeIds(['default']);
106+
107+
$promotion->setStoreIds(['90']);
108+
$this->assertFalse($promotion->available($this->order));
109+
$promotion->setStoreIds([$this->store->id()]);
110+
}
111+
112+
/**
113+
* Tests the start date logic.
114+
*/
115+
public function testStartDate() {
116+
// Default start date.
117+
$promotion = Promotion::create([
118+
'order_types' => ['default'],
119+
'stores' => [$this->store->id()],
120+
'usage_limit' => 1,
121+
'status' => TRUE,
122+
]);
123+
$promotion->save();
124+
$this->assertTrue($promotion->available($this->order));
125+
126+
// The computed ->date property always converts dates to UTC,
127+
// causing failures around 8PM EST once the UTC date passes midnight.
128+
$now = (new \DateTime())->setTime(20, 00);
129+
$this->container->get('request_stack')->getCurrentRequest()->server->set('REQUEST_TIME', $now->getTimestamp());
130+
$this->assertTrue($promotion->available($this->order));
131+
132+
// Past start date.
133+
$date = new DrupalDateTime('2017-01-01');
134+
$promotion->setStartDate($date);
135+
$this->assertTrue($promotion->available($this->order));
136+
137+
// Future start date.
138+
$date = new DrupalDateTime();
139+
$date->modify('+1 week');
140+
$promotion->setStartDate($date);
141+
$this->assertFalse($promotion->available($this->order));
142+
}
143+
144+
/**
145+
* Tests the end date logic.
146+
*/
147+
public function testEndDate() {
148+
// No end date date.
149+
$promotion = Promotion::create([
150+
'order_types' => ['default'],
151+
'stores' => [$this->store->id()],
152+
'usage_limit' => 1,
153+
'status' => TRUE,
154+
]);
155+
$promotion->save();
156+
$this->assertTrue($promotion->available($this->order));
157+
158+
// Past end date.
159+
$date = new DrupalDateTime('2017-01-01');
160+
$promotion->setEndDate($date);
161+
$this->assertFalse($promotion->available($this->order));
162+
163+
// Future end date.
164+
$date = new DrupalDateTime();
165+
$date->modify('+1 week');
166+
$promotion->setEndDate($date);
167+
$this->assertTrue($promotion->available($this->order));
168+
}
169+
170+
/**
171+
* Tests the usage count logic.
172+
*/
173+
public function testUsageCount() {
174+
$promotion = Promotion::create([
175+
'order_types' => ['default'],
176+
'stores' => [$this->store->id()],
177+
'usage_limit' => 2,
178+
'status' => TRUE,
179+
]);
180+
$promotion->save();
181+
$this->assertTrue($promotion->available($this->order));
182+
183+
\Drupal::service('commerce_promotion.usage')->addUsage($this->order, $promotion);
184+
$this->assertTrue($promotion->available($this->order));
185+
\Drupal::service('commerce_promotion.usage')->addUsage($this->order, $promotion);
186+
$this->assertFalse($promotion->available($this->order));
187+
}
188+
189+
}

0 commit comments

Comments
 (0)