Problem/Motivation
If you do not set a price of the purchased item from the form in the handler, ie you have not overridden the 'amount', any commerce price resolvers still don't get a chance to set the item price. The particular case where we noticed this was using Commerce Pricelist, which is the source for prices on the site, not the variation itself. This will however be the case for any setup using price resolvers.
The reason for this is at the moment the OrderItem created always overrides the price.
$this->orderItem
->set('purchased_entity', $data['purchasable_entity'])
->set('commerce_webform_order_submission', $webform_submission->id())
->setTitle($data['title'], TRUE)
->setUnitPrice($data['price'], TRUE)
->setQuantity($data['quantity']);
https://git.drupalcode.org/project/commerce_webform_order/-/blob/3.x/src...
The price coming from the price returned by the purchasable entity if there is no override set from the form via the handler
$amount = $data['order_item']['amount'];
if ((empty($amount) || !is_numeric($amount)) && !empty($prepared_data['purchasable_entity'])) {
$data['order_item']['amount'] = $prepared_data['purchasable_entity']->getPrice()->getNumber();
}
if (empty($data['order_item']['currency']) && !empty($prepared_data['purchasable_entity'])) {
$data['order_item']['currency'] = $prepared_data['purchasable_entity']->getPrice()->getCurrencyCode();
}
else {
$currency = $this->loadEntityValue(
$data['order_item']['currency'],
'commerce_currency',
['currencyCode', 'name', 'numericCode']
);
$data['order_item']['currency'] = $currency->getCurrencyCode();
}
$prepared_data['price'] = new Price((string) $data['order_item']['amount'], $data['order_item']['currency']);
https://git.drupalcode.org/project/commerce_webform_order/-/blob/3.x/src...
(Aside this code will rather unceremoniously error if there's an incorrect combination of entity, amount and currency set.)
In a site without any resolvers, not setting the 'amount', will cause the item price to be overridden with the price of the item. Add a resolver it won't kick in because the price is overridden.
Proposed resolution
Don't set the price if it is not overridden by a value from the form.
$this->orderItem
->set('purchased_entity', $data['purchasable_entity'])
->set('commerce_webform_order_submission', $webform_submission->id())
->setTitle($data['title'], TRUE)
->setQuantity($data['quantity']);
if (isset($data['price'])) {
$this->orderItem->setUnitPrice($data['price'], TRUE);
}
Where the code in https://git.drupalcode.org/project/commerce_webform_order/-/blob/3.x/src... has been refactored such that $data['price'] has not been set unless either, or both, of the 'amount' and 'currency' have been configured to be overridden.
This means:
- if there is an 'amount' or 'currency' has been set, the price gets overridden, just as it is now;
- if 'amount' and 'currency' have not been set, and there are no resolvers, the price from the item is used, just as it now, but done by commerce itself;
- but if 'amount' and 'currency' have not been set, and there are resolvers, the price as negotiated by them is used by commerce.
Remaining tasks
Refactor code as described, make a MR.
Possibly make more elegant handling of the case where there isn't a purchasable entity on the way?
Review.
Issue fork commerce_webform_order-3564158
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
ekes commentedComment #4
ekes commentedComment #5
ekes commentedComment #6
rattusrattus commentedI've tested this issue fork and the calculated price was as expected when not overriding the price and using Commerce Pricelist. Thanks
Comment #8
facine commentedThanks for the work on this issue. Everything looks fine, I’ve just merged it.
Thank you!