magento2: \Magento\Quote\Model\Quote\Payment\ToOrderPayment Failure if payment has additionalData
Preconditions and environment
- Any version of Magento
- Anything else that would help a developer reproduce the bug
Steps to reproduce
- Add additionalInformation to the \Magento\Quote\Api\Data\PaymentInterface object in place order action
- When placing order, Magento copy quote payment to order payment
- \Magento\Quote\Model\Quote\Payment\ToOrderPayment::convert
- \Magento\Framework\DataObject\Copy::getDataFromFieldset
- This method is used:
case $source instanceof DataObject:
$value = $source->getDataUsingMethod($code);
break;
\Magento\Quote\Api\Data\PaymentInterface & \Magento\Sales\Api\Data\OrderPaymentInterface shares the same definition for additional property:
/**
* Get payment additional details
*
* @return string[]|null
*/
public function getAdditionalData();
/**
* Set payment additional details
*
* @param string $additionalData
* @return $this
*/
public function setAdditionalData($additionalData);
Obviously, copying array to string will impact the save action of the order. When the order is saved, the payment relation is processed and throws an error of array to string conversion.
Expected result
Order is placed.
Actual result
An error occurred and the order is not placed.
Additional information
No response
Release note
No response
Triage and priority
- Severity: S0 - Affects critical data or functionality and leaves users without workaround.
- Severity: S1 - Affects critical data or functionality and forces users to employ a workaround.
- Severity: S2 - Affects non-critical data or functionality and forces users to employ a workaround.
- Severity: S3 - Affects non-critical data or functionality and does not force users to employ a workaround.
- Severity: S4 - Affects aesthetics, professional look and feel, “quality” or “usability”.
About this issue
- Original URL
- State: open
- Created a year ago
- Comments: 25 (5 by maintainers)
Hello @thomas-kl1,
We have noticed that this issue has not been updated for a period of long time. Hence we assume that this issue is fixed now, so we are closing it. Please raise a fresh ticket or reopen this ticket if you need more assistance on this.
Regards
Apparently very many things, for example, your plugin is for
Magento\Quote\Model\Quote\Payment
whereas the interface being discussed here isMagento\Quote\Api\Data\PaymentInterface
.Your docblock says this:
However
Magento\Quote\Model\Quote\Payment
implementsMagento\Quote\Api\Data\PaymentInterface
wheresetAdditionalData
has the docblockAs you can see the
string
typehint for$additionalData
is a mismatch with what thearray
typehint you have used (and is used in the implementation).The reason this is a problem is the API - and apparently also the place order action - via
Magento\Framework\DataObject\Copy
- will use the typehint from PaymentInterface when setting additionalData and therefore will pass a string tosetAdditionalData
when the classPayment
expects an array and throw an error.Since the above explanation is not really related to the bug at hand, and more related to basic comprehension of programming in PHP, might I suggest escalating the bug to someone more senior?
Not sure if this is a related issue or part of the same problem, but I did spot an issue with the API here. Note the docblock in
Magento\Quote\Api\Data\PaymentInterface
as quoted above:which suggests setAdditionalData expects a string.
Therefore we can expect $paymentInterface->getData(‘additional_data’) to return a string after calling this function.
getAdditionalData()
function implements conversion of serialised string back to an array hence docblock there statesstring[]
.Given this interface API, a user will set additionalData to JSON as follows:
n.b.
savePaymentInformationAndPlaceOrder
param 2 does expect aPaymentInterface
directly and not some implementation of it.Consider the following stack trace (interceptors cleaned for legibility) - line numbers are from 2.4.6-p1 (perhaps with some quality patches)
In
set
function (param 2 expectsPaymentInterface
):In
convertPaymentData
function:See the second clause is calling array_merge on essentially the result of
$paymentInterface->getData('additional_data')
even though we would expect that to return a string. I think there are a few clean solutions - in order of preference: (a) PaymentInterface takes an array in setAdditionalData and it is down to the resource / repository to serialize it/unserialize it when saving/loading. Then getAdditionalData override could be removed and there is consistency between the result of that function and the result of getData. (b)Magento\Quote\Model\Quote\Payment->importData
is updated to take aPaymentInterface
instead of anarray
as its parameter, and uses the getter functions where appopriate so that it has some confidence in the data types / static analysis picks up bugs like this (right nowmixed[]
is about as good as a static analyser can see). Maybe someone ought togit blame
this code and write a phpcs rule to disallow passing arrays around where data objects could be used instead as well.For any mage users like myself coming up against it the workaround is instead of using the interface method
setAdditionalData
onPaymentInterface
, usesetData
instead:becomes: