Skip to content

Commit 667e5b5

Browse files
[Magento Community Engineering] Community Contributions - 2.4-develop
- merged latest code from mainline branch
2 parents 814639b + 8b1d118 commit 667e5b5

File tree

13 files changed

+565
-57
lines changed

13 files changed

+565
-57
lines changed

app/code/Magento/Catalog/Model/Product/Option/Type/Date.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ public function validateUserValue($values)
7272
$dateValid = true;
7373
if ($this->_dateExists()) {
7474
if ($this->useCalendar()) {
75+
/* Fixed validation if the date was not saved correctly after re-saved the order
76+
for example: "09\/24\/2020,2020-09-24 00:00:00" */
77+
if (is_string($value) && preg_match('/^\d{1,4}.+\d{1,4}.+\d{1,4},+(\w|\W)*$/', $value)) {
78+
$value = [
79+
'date' => preg_replace('/,([^,]+),?$/', '', $value),
80+
];
81+
}
7582
$dateValid = isset($value['date']) && preg_match('/^\d{1,4}.+\d{1,4}.+\d{1,4}$/', $value['date']);
7683
} else {
7784
$dateValid = isset(
@@ -184,8 +191,10 @@ public function prepareForCart()
184191
$date = (new \DateTime())->setTimestamp($timestamp);
185192
$result = $date->format('Y-m-d H:i:s');
186193

194+
$originDate = (isset($value['date']) && $value['date'] != '') ? $value['date'] : null;
195+
187196
// Save date in internal format to avoid locale date bugs
188-
$this->_setInternalInRequest($result);
197+
$this->_setInternalInRequest($result, $originDate);
189198

190199
return $result;
191200
} else {
@@ -352,9 +361,10 @@ public function getYearEnd()
352361
* Save internal value of option in infoBuy_request
353362
*
354363
* @param string $internalValue Datetime value in internal format
364+
* @param string|null $originDate date value in origin format
355365
* @return void
356366
*/
357-
protected function _setInternalInRequest($internalValue)
367+
protected function _setInternalInRequest($internalValue, $originDate = null)
358368
{
359369
$requestOptions = $this->getRequest()->getOptions();
360370
if (!isset($requestOptions[$this->getOption()->getId()])) {
@@ -364,6 +374,9 @@ protected function _setInternalInRequest($internalValue)
364374
$requestOptions[$this->getOption()->getId()] = [];
365375
}
366376
$requestOptions[$this->getOption()->getId()]['date_internal'] = $internalValue;
377+
if ($originDate) {
378+
$requestOptions[$this->getOption()->getId()]['date'] = $originDate;
379+
}
367380
$this->getRequest()->setOptions($requestOptions);
368381
}
369382

app/code/Magento/Catalog/Model/ProductOptionProcessor.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
*/
66
namespace Magento\Catalog\Model;
77

8-
use Magento\Catalog\Api\Data\ProductOptionExtensionFactory;
98
use Magento\Catalog\Api\Data\ProductOptionInterface;
109
use Magento\Catalog\Model\CustomOptions\CustomOption;
1110
use Magento\Catalog\Model\CustomOptions\CustomOptionFactory;
1211
use Magento\Framework\DataObject;
1312
use Magento\Framework\DataObject\Factory as DataObjectFactory;
1413

14+
/**
15+
* Processor for product options
16+
*/
1517
class ProductOptionProcessor implements ProductOptionProcessorInterface
1618
{
1719
/**
@@ -88,7 +90,8 @@ public function convertToProductOption(DataObject $request)
8890
if (!empty($options) && is_array($options)) {
8991
$data = [];
9092
foreach ($options as $optionId => $optionValue) {
91-
if (is_array($optionValue)) {
93+
94+
if (is_array($optionValue) && !$this->isDateWithDateInternal($optionValue)) {
9295
$optionValue = $this->processFileOptionValue($optionValue);
9396
$optionValue = implode(',', $optionValue);
9497
}
@@ -126,6 +129,8 @@ private function processFileOptionValue(array $optionValue)
126129
}
127130

128131
/**
132+
* Get url builder
133+
*
129134
* @return \Magento\Catalog\Model\Product\Option\UrlBuilder
130135
*
131136
* @deprecated 101.0.0
@@ -138,4 +143,15 @@ private function getUrlBuilder()
138143
}
139144
return $this->urlBuilder;
140145
}
146+
147+
/**
148+
* Check if the option has a date_internal and date
149+
*
150+
* @param array $optionValue
151+
* @return bool
152+
*/
153+
private function isDateWithDateInternal(array $optionValue): bool
154+
{
155+
return array_key_exists('date_internal', $optionValue) && array_key_exists('date', $optionValue);
156+
}
141157
}

app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ public function __construct(
421421

422422
$this->_initMessageTemplates();
423423

424-
$this->_initProductsSku()->_initOldCustomOptions();
424+
$this->_initProductsSku();
425425
}
426426

427427
/**
@@ -606,6 +606,9 @@ protected function _initOldCustomOptions()
606606
'option_title.store_id = ?',
607607
$storeId
608608
);
609+
if (!empty($this->_newOptionsOldData)) {
610+
$this->_optionCollection->addProductToFilter(array_keys($this->_newOptionsOldData));
611+
}
609612

610613
$this->_byPagesIterator->iterate($this->_optionCollection, $this->_pageSize, [$addCustomOptions]);
611614
}
@@ -614,6 +617,20 @@ protected function _initOldCustomOptions()
614617
return $this;
615618
}
616619

620+
/**
621+
* Get existing custom options data
622+
*
623+
* @return array
624+
*/
625+
private function getOldCustomOptions(): array
626+
{
627+
if ($this->_oldCustomOptions === null) {
628+
$this->_initOldCustomOptions();
629+
}
630+
631+
return $this->_oldCustomOptions;
632+
}
633+
617634
/**
618635
* Imported entity type code getter
619636
*
@@ -717,9 +734,9 @@ protected function _findOldOptionsWithTheSameTitles()
717734
$errorRows = [];
718735
foreach ($this->_newOptionsOldData as $productId => $options) {
719736
foreach ($options as $outerData) {
720-
if (isset($this->_oldCustomOptions[$productId])) {
737+
if (isset($this->getOldCustomOptions()[$productId])) {
721738
$optionsCount = 0;
722-
foreach ($this->_oldCustomOptions[$productId] as $innerData) {
739+
foreach ($this->getOldCustomOptions()[$productId] as $innerData) {
723740
if (count($outerData['titles']) == count($innerData['titles'])) {
724741
$outerTitles = $outerData['titles'];
725742
$innerTitles = $innerData['titles'];
@@ -753,8 +770,8 @@ protected function _findNewOldOptionsTypeMismatch()
753770
$errorRows = [];
754771
foreach ($this->_newOptionsOldData as $productId => $options) {
755772
foreach ($options as $outerData) {
756-
if (isset($this->_oldCustomOptions[$productId])) {
757-
foreach ($this->_oldCustomOptions[$productId] as $innerData) {
773+
if (isset($this->getOldCustomOptions()[$productId])) {
774+
foreach ($this->getOldCustomOptions()[$productId] as $innerData) {
758775
if (count($outerData['titles']) == count($innerData['titles'])) {
759776
$outerTitles = $outerData['titles'];
760777
$innerTitles = $innerData['titles'];
@@ -784,9 +801,9 @@ protected function _findNewOldOptionsTypeMismatch()
784801
protected function _findExistingOptionId(array $newOptionData, array $newOptionTitles)
785802
{
786803
$productId = $newOptionData['product_id'];
787-
if (isset($this->_oldCustomOptions[$productId])) {
804+
if (isset($this->getOldCustomOptions()[$productId])) {
788805
ksort($newOptionTitles);
789-
$existingOptions = $this->_oldCustomOptions[$productId];
806+
$existingOptions = $this->getOldCustomOptions()[$productId];
790807
foreach ($existingOptions as $optionId => $optionData) {
791808
if ($optionData['type'] == $newOptionData['type']
792809
&& $optionData['titles'][Store::DEFAULT_STORE_ID] == $newOptionTitles[Store::DEFAULT_STORE_ID]

app/code/Magento/Customer/Block/Widget/Dob.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ public function getHtmlExtraParams()
281281
*/
282282
public function getDateFormat()
283283
{
284-
$dateFormat = $this->_localeDate->getDateFormatWithLongYear();
284+
$dateFormat = $this->setTwoDayPlaces($this->_localeDate->getDateFormatWithLongYear());
285285
/** Escape RTL characters which are present in some locales and corrupt formatting */
286286
$escapedDateFormat = preg_replace('/[^MmDdYy\/\.\-]/', '', $dateFormat);
287287

@@ -377,4 +377,19 @@ public function getFirstDay()
377377
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
378378
);
379379
}
380+
381+
/**
382+
* Set 2 places for day value in format string
383+
*
384+
* @param string $format
385+
* @return string
386+
*/
387+
private function setTwoDayPlaces(string $format): string
388+
{
389+
return preg_replace(
390+
'/(?<!d)d(?!d)/',
391+
'dd',
392+
$format
393+
);
394+
}
380395
}

app/code/Magento/Customer/Test/Unit/Block/Widget/DobTest.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class DobTest extends TestCase
5151
const YEAR = '2014';
5252

5353
// Value of date('Y', strtotime(self::DATE))
54-
const DATE_FORMAT = 'M/d/y';
54+
const DATE_FORMAT = 'M/dd/y';
5555

5656
/** Constants used by Dob::setDateInput($code, $html) */
5757
const DAY_HTML =
@@ -356,11 +356,15 @@ public function getDateFormatDataProvider(): array
356356
[
357357
'ar_SA',
358358
preg_replace(
359-
'/[^MmDdYy\/\.\-]/',
360-
'',
361-
(new DateFormatterFactory())
362-
->create('ar_SA', \IntlDateFormatter::SHORT, \IntlDateFormatter::NONE)
363-
->getPattern()
359+
'/(?<!d)d(?!d)/',
360+
'dd',
361+
preg_replace(
362+
'/[^MmDdYy\/\.\-]/',
363+
'',
364+
(new DateFormatterFactory())
365+
->create('ar_SA', \IntlDateFormatter::SHORT, \IntlDateFormatter::NONE)
366+
->getPattern()
367+
)
364368
)
365369
],
366370
[Resolver::DEFAULT_LOCALE, self::DATE_FORMAT],

app/code/Magento/Sales/Model/AdminOrder/Create.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ protected function _initShippingAddressFromOrder(\Magento\Sales\Model\Order $ord
642642
* @param \Magento\Sales\Model\Order\Item $orderItem
643643
* @param int $qty
644644
* @return \Magento\Quote\Model\Quote\Item|string|$this
645+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
645646
*/
646647
public function initFromOrderItem(\Magento\Sales\Model\Order\Item $orderItem, $qty = null)
647648
{
@@ -666,10 +667,17 @@ public function initFromOrderItem(\Magento\Sales\Model\Order\Item $orderItem, $q
666667
$productOptions = $orderItem->getProductOptions();
667668
if ($productOptions !== null && !empty($productOptions['options'])) {
668669
$formattedOptions = [];
670+
$useFrontendCalendar = $this->useFrontendCalendar();
669671
foreach ($productOptions['options'] as $option) {
672+
if (in_array($option['option_type'], ['date', 'date_time']) && $useFrontendCalendar) {
673+
$product->setSkipCheckRequiredOption(false);
674+
break;
675+
}
670676
$formattedOptions[$option['option_id']] = $option['option_value'];
671677
}
672-
$buyRequest->setData('options', $formattedOptions);
678+
if (!empty($formattedOptions)) {
679+
$buyRequest->setData('options', $formattedOptions);
680+
}
673681
}
674682
$item = $this->getQuote()->addProduct($product, $buyRequest);
675683
if (is_string($item)) {
@@ -2115,4 +2123,17 @@ private function isAddressesAreEqual(Order $order)
21152123

21162124
return $shippingData == $billingData;
21172125
}
2126+
2127+
/**
2128+
* Use Calendar on frontend or not
2129+
*
2130+
* @return bool
2131+
*/
2132+
private function useFrontendCalendar(): bool
2133+
{
2134+
return (bool)$this->_scopeConfig->getValue(
2135+
'catalog/custom_options/use_calendar',
2136+
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
2137+
);
2138+
}
21182139
}

app/code/Magento/Sales/etc/db_schema.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@
769769
<column xsi:type="varchar" name="order_increment_id" nullable="false" length="32" comment="Order Increment ID"/>
770770
<column xsi:type="int" name="order_id" unsigned="true" nullable="false" identity="false"
771771
comment="Order ID"/>
772-
<column xsi:type="timestamp" name="order_created_at" on_update="true" nullable="false"
772+
<column xsi:type="timestamp" name="order_created_at" on_update="false" nullable="false"
773773
default="CURRENT_TIMESTAMP" comment="Order Increment ID"/>
774774
<column xsi:type="varchar" name="customer_name" nullable="false" length="128" comment="Customer Name"/>
775775
<column xsi:type="decimal" name="total_qty" scale="4" precision="12" unsigned="false" nullable="true"

app/code/Magento/Tax/Model/Plugin/OrderSave.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,14 @@ public function afterSave(
5050
}
5151

5252
/**
53+
* Save order tax
54+
*
5355
* @param \Magento\Sales\Api\Data\OrderInterface $order
5456
* @return $this
5557
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
5658
* @SuppressWarnings(PHPMD.NPathComplexity)
5759
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
60+
* phpcs:disable Generic.Metrics.NestingLevel.TooHigh
5861
*/
5962
protected function saveOrderTax(\Magento\Sales\Api\Data\OrderInterface $order)
6063
{
@@ -176,7 +179,9 @@ protected function saveOrderTax(\Magento\Sales\Api\Data\OrderInterface $order)
176179
} elseif (isset($quoteItemId['associated_item_id'])) {
177180
//This item is associated with a product item
178181
$item = $order->getItemByQuoteItemId($quoteItemId['associated_item_id']);
179-
$associatedItemId = $item->getId();
182+
if ($item !== null && $item->getId()) {
183+
$associatedItemId = $item->getId();
184+
}
180185
}
181186

182187
$data = [

0 commit comments

Comments
 (0)