- ๐ฎ๐ณIndia Akhil Babu Chengannur
Thanks for the patch. Adjustment values are now getting displayed in API response after applying the latest patch from https://www.drupal.org/project/drupal/issues/2915705 โ and then 2916252-66.patch.
But there was a waring after applying 2916252-66.patch.
Deprecated function: Return type of Drupal\commerce_order\Adjustment::getIterator() should either be compatible with IteratorAggregate::getIterator(): Traversable, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in include()
Updating 2916252-66.patch to remove the warning.
Changepublic function getIterator() { return new \ArrayIterator($this->toArray()); }
to
public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->toArray()); }
- ๐จ๐พCyprus alex.bukach
It should be
\Traversable
, not\ArrayIterator
. - ๐ซ๐ทFrance Agence Web CoherActio
The last patch caused side-effects (e.g. price substract() method with adjustment).
I ended up extending Drupal TypedDataNormalizer class to support Ajdustment normalizernamespace Drupal\my_module\Normalizer; use Drupal\commerce_order\Adjustment; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\serialization\Normalizer\TypedDataNormalizer; class MyModuleAdjustmentNormalizer extends TypedDataNormalizer { /** * {@inheritdoc} */ public function normalize($object, $format = NULL, array $context = []): array|string|int|float|bool|\ArrayObject|NULL { $this->addCacheableDependency($context, $object); $value = $object->getValue(); // Support for stringable value objects: avoid numerous custom normalizers. if (is_object($value) && method_exists($value, '__toString')) { $value = (string) $value; } if ($value instanceof Adjustment) { $value = $value->toArray(); } return $value; } }
- ๐ฎ๐ฑIsrael jsacksick
The attached patch works... However I don't think we can commit it as this means Commerce just provides a normalizer for the "Any" data type, which is used by other field types... which is a problem... But attaching the patch anyway..
- ๐ฎ๐ฑIsrael jsacksick
Perhaps we could provide our normalizer, only if the core one introduced in #2915705: TypedData 'Any' can't be normalized to array if it stores an object โ doesn't exist?
- Status changed to Needs review
about 1 year ago 7:29am 29 May 2024 - last update
about 1 year ago 794 pass - ๐ฎ๐ฑIsrael jsacksick
Actually, let's go with this patch... Which provides the "Any" normalizer conditionally in case it is not defined by the serialization module.
- Merge request !265Issue #2916252: Define an normalizer for order adjustments. โ (Open) created by jsacksick
- last update
about 1 year ago 794 pass - First commit to issue fork.
- last update
about 1 year ago CI error - last update
about 1 year ago Unable to generate test groups - last update
about 1 year ago Unable to generate test groups - last update
about 1 year ago Unable to generate test groups - last update
12 months ago 794 pass, 2 fail - ๐ฎ๐ฑIsrael jsacksick
We were missing the test group (added that). But also suddenly not sure about the fix, whenever I don't skip the test methods defined by the base class, there seems to be an issue with the denormalization of the adjustments field... Also... now extending getSupportedTypes() from the normalizer as the previous approach :
/** * {@inheritdoc} */ protected $supportedInterfaceOrClass = Any::class;
is deprecated in D10.2. I'd need to double check when this change was introduced to see if we need ot raise the required core version... Since I'm not sure the issue is actually fixed... Putting this issue on hold for now.
- ๐บ๐ธUnited States mrweiner
@jsacksick re: #80, I can confirm that the patch in #77 fixes the issue for me on D10.3.0.
- ๐ฎ๐ฑIsrael jsacksick
Last time I worked on the tests, they were failing, and can't remember why, so looks like the patch doesn't address all the problems...
- ๐ฎ๐นItaly trickfun
@jsacksick i have this patch too https://www.drupal.org/project/drupal/issues/3300404 ๐ Unserialize(): Passing null to parameter #1 ($data) of type string is deprecated in Drupal\Core\Entity\Sql\SqlContentEntityStorage Needs work
- ๐ฎ๐ฑIsrael jsacksick
@tBKoT: Interesting approach, just wondering if this isn't a breaking change?
Also, we might as well copy what was done in Commerce API. The Commerce API module defines an Adjustment data type as well as an AdjustmentDataDefinition definition class.The data definition class defines all the adjustment properties. This should help getting rid of the "value".
- ๐บ๐ฆUkraine tbkot
@jsacksick I've tried to get rid of the "value" key but it seems that it is not possible without rewriting a lot of staff or removing the denormalization process in the test (it would fail in this case)
The main thing is that JSON:API uses the field property definition as a foundation to generate the structure if we change it as a result all other things related to this field would be broken such as getAdjustments() etc. as those methods use "value" and I guess many other contrib/custom solutions may use this field like that.
Another thing that can help is to define more properties with their own data types to set values for Label, Type, Amount, etc. I do not think it is the best way to resolve this.
One more solution is to disable access to the main "adjustment" field for JSON:API as it is done in the "commerce_api" module and define a new computed field for it to show adjustment without the "value" key.
- ๐ซ๐ทFrance goz
But we should also support denormalizer implementing DenormalizerInterface and adding denormalize method, so we can create order item with adjustment from jsonapi.
/** * {@inheritdoc} */ public function denormalize($data, $type, $format = NULL, array $context = []) { if (isset($context['field_type']) && 'commerce_adjustment' === $context['field_type']) { if (isset($data['amount'], $data['amount']['number'], $data['amount']['currency_code'])) { $data['amount'] = new Price($data['amount']['number'], $data['amount']['currency_code']); } return new Adjustment($data); } return $data; }
- ๐ซ๐ทFrance goz
#89 works with 3.0 but use previous fix based on "Any".
MR add the adjustmentType which should be kept for 3.0 - Merge request !417Issue #2916252 by lawxen, wim leers, mglaman, skyredwang: [PP-1] Order's... โ (Merged) created by goz
- Status changed to Needs work
23 days ago 1:04pm 9 May 2025 - ๐ฎ๐ฑIsrael jsacksick
Do we actually need to declare each individual property like the following? The normalizer is on the value property, isn't that sufficient?
The normalization still works without those... Or is that needed for setting adjustments though the API?$properties['type'] = DataDefinition::create('adjustment_property') ->setLabel(t('Type')) ->setComputed(TRUE); $properties['label'] = DataDefinition::create('adjustment_property') ->setLabel(t('Label')) ->setComputed(TRUE); $properties['amount'] = DataDefinition::create('adjustment_property') ->setLabel(t('Amount')) ->setComputed(TRUE); $properties['source_id'] = DataDefinition::create('adjustment_property') ->setLabel(t('Source ID')) ->setComputed(TRUE); $properties['percentage'] = DataDefinition::create('adjustment_property') ->setLabel(t('Amount')) ->setComputed(TRUE); $properties['included'] = DataDefinition::create('adjustment_property') ->setLabel(t('Included')) ->setComputed(TRUE); $properties['locked'] = DataDefinition::create('adjustment_property') ->setLabel(t('Locked')) ->setComputed(TRUE);
Isn't it
- ๐ฎ๐ฑIsrael jsacksick
Ok removing the extra properties from the AdjustmentItem failed... But removing the AdjustmentPropertyDefinition worked... Wondering why it was added in the first place?
- ๐บ๐ธUnited States rhovland Oregon
So on our site we're writing new adjustments through the API, not just updating existing ones so we need all of those extra properties to be able to set the characteristics of the adjustment.
- ๐ฎ๐ฑIsrael jsacksick
@rhovland: Does the current patch allow for that? (from the MR)? I'm considering merging it as it looks ready.
- ๐บ๐ธUnited States rhovland Oregon
I will update our patch on our test site and make sure the removal of AdjustmentPropertyDefinition didn't mess anything up.
- ๐ซ๐ทFrance goz
With last patch, no error is thrown, i can list adjustments for orders and order items, but i cannot create them.
GET /jsonapi/commerce_order/default?filter[drupal_internal__order_id]=3807'
{ "jsonapi": { "version": "1.0", "meta": { "links": { "self": { "href": "http://jsonapi.org/format/1.0/" } } } }, "data": [ { "type": "commerce_order--default", "id": "ad15f584-05f7-43a8-bd55-ab18a4eaba2c", "links": { ... }, "attributes": { "drupal_internal__order_id": 3807, "order_number": "3807", ... "adjustments": [ { "type": "shipping", "label": "Expรฉdition", "amount": { "number": "4.95", "currency_code": "EUR", "formatted": "4,95 โฌ" }, "percentage": null, "source_id": "1058", "included": false, "locked": false } ], "total_price": { "number": "28.950000", "currency_code": "EUR", "formatted": "28,95 โฌ" }, "total_paid": null, "balance": { "number": "28.950000", "currency_code": "EUR", "formatted": "28,95 โฌ" }, "state": "completed", "locked": false, "created": "2025-03-14T08:13:38+00:00", "changed": "2025-03-14T13:53:41+00:00", "placed": "2025-03-14T13:53:41+00:00", "completed": "2025-03-14T13:53:41+00:00", "customer_comments": null, "cart": false, "checkout_step": "complete", ... }, "relationships": { ... } } ], ... }
But creating new order doesn't :
{ "data": { "type": "commerce_order_item--abonnement_single", "attributes": { "title": "Abonnement individuel - 1 an", "quantity": "1.00", "unit_price": { "number": "15.000000", "currency_code": "EUR", "formatted": "15,00 โฌ" }, "total_price": { "number": "15.000000", "currency_code": "EUR", "formatted": "15,00 โฌ" }, "adjustments": [ { "type": "tax", "label": "TVA", "amount": { "number": "0.31", "currency_code": "EUR" }, "percentage": "0.021", "source_id": "france|0|0", "included": true } ] }, "relationships": { "uid": { "data": { "type": "user--user", "id": "565a095e-d398-4ebb-9030-f877d9301601" } }, "order_id": { "data": { "type": "commerce_order--default", "id": "f1fe4660-dba4-4c90-8c0e-4090310a1e78" } }, "store_id": { "data": { "type": "commerce_store--online", "id": "1adc9d7c-c976-4951-9cd4-38413b150a51" } }, "purchased_entity": { "data": { "type": "commerce_product_variation--abonnement_single", "id": "e12569c7-24a4-4a5c-844f-d67ea1e01a21" } } } } }
Result :
{ "jsonapi": { "version": "1.0", "meta": { "links": { "self": { "href": "http://jsonapi.org/format/1.0/" } } } }, "data": { "type": "commerce_order_item--abonnement_single", "id": "cea7ce7c-84c2-4154-85b6-e65c87bf233c", "links": { ... }, "attributes": { "drupal_internal__order_item_id": 5932, "title": "Abonnement individuel - 1 an", "overridden_title": false, "quantity": "1", "unit_price": { "number": "15.000000", "currency_code": "EUR", "formatted": "15,00 โฌ" }, "overridden_unit_price": false, "total_price": { "number": "15.00", "currency_code": "EUR", "formatted": "15,00 โฌ" }, "adjustments": [], "uses_legacy_adjustments": false, "data": null, "locked": false, "created": "2025-05-16T10:34:03+00:00", "changed": "2025-05-16T10:34:03+00:00" }, .. }
Same thing creating order_item.
- ๐ฎ๐ฑIsrael jsacksick
@goz: What we don't see in your response is whether the order is a draft order? IF it is a draft order then on order save, the adjustment will be cleared by the OrderRefresh service right? So that is probably expected? You'd need to try on a non draft order.
- ๐ซ๐ทFrance goz
My bad, you are right, adjustments are cleared and recalculated. I forgot that. Checked again and everything is fine
- ๐ฎ๐ฑIsrael jsacksick
So RTBC then? Would be great to finally close this... I think this is ready! Would appreciate an RTBC.
-
jsacksick โ
committed e1ca95d8 on 3.x authored by
goz โ
Issue #2916252 by lawxen, tbkot, jsacksick, goz, alexpott, alex.bukach,...
-
jsacksick โ
committed e1ca95d8 on 3.x authored by
goz โ
- ๐บ๐ธUnited States rhovland Oregon
So far we have not been able to use PATCH to replace adjustments. They go poof with no error returned. This is on non-draft orders.
- ๐บ๐ธUnited States rhovland Oregon
If I try to send a patch request to https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e...
With JSON
{ "data":{ "type": "commerce_order--default", "id": "ab42ab1c-b21f-4da2-9e9b-82213e622e59", "attributes": { "adjustments": [ { "type": "shipping", "label": "Shipping", "amount": { "number": "126.940000", "currency_code": "USD" }, "percentage": null, "source_id": "209676", "included": false, "locked": false } ] } } }
I get the response
{ "jsonapi": { "version": "1.0", "meta": { "links": { "self": { "href": "http://jsonapi.org/format/1.0/" } } } }, "data": { "type": "commerce_order--default", "id": "ab42ab1c-b21f-4da2-9e9b-82213e622e59", "links": { "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59" } }, "attributes": { "drupal_internal__order_id": 289391, "order_number": "289391", "version": 15, "mail": "redacted@example.com", "ip_address": "208.56.233.218", "adjustments": [], "total_price": { "number": "226.22", "currency_code": "USD", "formatted": "$226.22" }, "total_paid": { "number": "253.160000", "currency_code": "USD", "formatted": "$253.16" }, "balance": { "number": "-26.94", "currency_code": "USD", "formatted": "-$26.94" }, "state": "shipped", "data": { "paid_event_dispatched": true }, "locked": false, "created": "2024-12-16T21:19:32+00:00", "changed": "2025-05-16T20:19:03+00:00", "placed": "2024-12-16T21:28:24+00:00", "completed": null, "customer_comments": null, "cart": false, "checkout_step": null, "field_customer_comments": null, "field_customer_motorcycles": [], "field_newsletter": false }, "relationships": { "commerce_order_type": { "data": null, "links": { "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/commerce_order_type" } } }, "store_id": { "data": null, "links": { "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/store_id" } } }, "uid": { "data": { "type": "user--user", "id": "e369285a-16a1-4817-baa5-b4848443a28a", "meta": { "drupal_internal__target_id": 29634 } }, "links": { "related": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/uid" }, "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/uid" } } }, "billing_profile": { "data": { "type": "profile--customer", "id": "2cfa79d0-3d74-4c99-bff2-3a26ee115a21", "meta": { "target_revision_id": 363841, "drupal_internal__target_id": 364046 } }, "links": { "related": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/billing_profile" }, "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/billing_profile" } } }, "order_items": { "data": [ { "type": "commerce_order_item--parts", "id": "55aaae86-e1dc-4c22-943e-7503deef65b7", "meta": { "drupal_internal__target_id": 1073893 } } ], "links": { "related": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/order_items" }, "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/order_items" } } }, "checkout_flow": { "data": null, "links": { "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/checkout_flow" } } }, "commerce_giftcards": { "data": [], "links": { "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/commerce_giftcards" } } }, "payment_gateway": { "data": null, "links": { "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/payment_gateway" } } }, "payment_method": { "data": null, "links": { "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/payment_method" } } }, "coupons": { "data": [], "links": { "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/coupons" } } }, "shipments": { "data": [ { "type": "commerce_shipment--default", "id": "86c32de5-5cd6-4542-abaf-23065e0458a1", "meta": { "drupal_internal__target_id": 209706 } } ], "links": { "related": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/shipments" }, "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59/relationships/shipments" } } } } }, "links": { "self": { "href": "https://example.com/jsonapi/commerce_order/default/ab42ab1c-b21f-4da2-9e9b-82213e622e59" } } }
The adjustments are just empty.
- ๐บ๐ธUnited States rhovland Oregon
Ok so after combing through things, we were using #72 ๐ [PP-1] Order's Adjustment can't be normalized and serialized Postponed plus the core Any normalizer patch and it was working.
The issue seems to be the final commit never implemented a denormalizer so that PATCH operations can work. The patch we were using had one. Kinda.
diff --git a/modules/order/src/Plugin/Field/FieldType/AdjustmentItem.php b/modules/order/src/Plugin/Field/FieldType/AdjustmentItem.php index 81ae6c90..cbc96972 100644 --- a/modules/order/src/Plugin/Field/FieldType/AdjustmentItem.php +++ b/modules/order/src/Plugin/Field/FieldType/AdjustmentItem.php @@ -3,6 +3,7 @@ namespace Drupal\commerce_order\Plugin\Field\FieldType; use Drupal\commerce_order\Adjustment; +use Drupal\commerce_price\Price; use Drupal\Core\Field\FieldItemBase; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\TypedData\DataDefinition; @@ -48,6 +49,11 @@ class AdjustmentItem extends FieldItemBase { // The property definition causes the adjustment to be in 'value' key. $values = reset($values); } + // Used for denormalization. + if (is_array($values)) { + $values['amount'] = new Price($values['amount']['number'], $values['amount']['currency_code']); + $values = new Adjustment($values); + } if (!$values instanceof Adjustment) { $values = NULL; }
So as committed this lets you read adjustments via API but not write them.
- ๐บ๐ธUnited States rhovland Oregon
@goz You got this to successfully write order adjustments? Do you have commerce_api installed?
Automatically closed - issue fixed for 2 weeks with no activity.