magento2: Shipping-information endpoint returns error when DiscountData is specified in the body

Preconditions (*)

  1. Reproduced on 2.4-develop
  2. Replicated on 2.3.5-p1 and 2.4.1

Steps to reproduce (*)

  1. POST request to rest/default/V1/guest-carts/{cartId}/shipping-information Request body from https://magento.redoc.ly/2.4.0-admin/tag/guest-cartscartIdshipping-information
{
  "addressInformation": {
    "shipping_address": {
      "id": 0,
      "region": "string",
      "region_id": 0,
      "region_code": "string",
      "country_id": "string",
      "street": [
        "string"
      ],
      "company": "string",
      "telephone": "string",
      "fax": "string",
      "postcode": "string",
      "city": "string",
      "firstname": "string",
      "lastname": "string",
      "middlename": "string",
      "prefix": "string",
      "suffix": "string",
      "vat_id": "string",
      "customer_id": 0,
      "email": "string",
      "same_as_billing": 0,
      "customer_address_id": 0,
      "save_in_address_book": 0,
      "extension_attributes": {
        "discounts": [
          {
            "discount_data": {
              "amount": 0,
              "base_amount": 0,
              "original_amount": 0,
              "base_original_amount": 0
            },
            "rule_label": "string",
            "rule_id": 0
          }
        ],
        "gift_registry_id": 0,
        "pickup_location_code": "string"
      },
      "custom_attributes": [
        {
          "attribute_code": "string",
          "value": "string"
        }
      ]
    },
    "billing_address": {
      "id": 0,
      "region": "string",
      "region_id": 0,
      "region_code": "string",
      "country_id": "string",
      "street": [
        "string"
      ],
      "company": "string",
      "telephone": "string",
      "fax": "string",
      "postcode": "string",
      "city": "string",
      "firstname": "string",
      "lastname": "string",
      "middlename": "string",
      "prefix": "string",
      "suffix": "string",
      "vat_id": "string",
      "customer_id": 0,
      "email": "string",
      "same_as_billing": 0,
      "customer_address_id": 0,
      "save_in_address_book": 0,
      "extension_attributes": {
        "discounts": [
          {
            "discount_data": {
              "amount": 0,
              "base_amount": 0,
              "original_amount": 0,
              "base_original_amount": 0
            },
            "rule_label": "string",
            "rule_id": 0
          }
        ],
        "gift_registry_id": 0,
        "pickup_location_code": "string"
      },
      "custom_attributes": [
        {
          "attribute_code": "string",
          "value": "string"
        }
      ]
    },
    "shipping_method_code": "string",
    "shipping_carrier_code": "string",
    "extension_attributes": {},
    "custom_attributes": [
      {
        "attribute_code": "string",
        "value": "string"
      }
    ]
  }
}

Expected result (*)

Improved error handling, the API is supposed to warn the client that those fields are read-only and are not suppose to be sent on the POST request.

Actual result (*)

{
    "message": "Property \"DiscountData\" does not have accessor method \"setDiscountData\" in class \"Magento\\SalesRule\\Api\\Data\\RuleDiscountInterface\".",
    "trace": "#0 /bitnami/magento/htdocs/vendor/magento/framework/Reflection/NameFinder.php(77): Magento\\Framework\\Reflection\\NameFinder->findAccessorMethodName(Object(Laminas\\Code\\Reflection\\ClassReflection), 'DiscountData', 'setDiscountData', 'setIsDiscountDa...')\n#1 /bitnami/magento/htdocs/vendor/magento/framework/Webapi/ServiceInputProcessor.php(265): Magento\\Framework\\Reflection\\NameFinder->getSetterMethodName(Object(Laminas\\Code\\Reflection\\ClassReflection), 'DiscountData')\n#2 /bitnami/magento/htdocs/vendor/magento/framework/Webapi/ServiceInputProcessor.php(474): Magento\\Framework\\Webapi\\ServiceInputProcessor->_createFromArray('\\\\Magento\\\\SalesR...', Array)\n#3 /bitnami/magento/htdocs/vendor/magento/framework/Webapi/ServiceInputProcessor.php(277): Magento\\Framework\\Webapi\\ServiceInputProcessor->convertValue(Array, '\\\\Magento\\\\SalesR...')\n#4 /bitnami/magento/htdocs/vendor/magento/framework/Webapi/ServiceInputProcessor.php(478): Magento\\Framework\\Webapi\\ServiceInputProcessor->_createFromArray('\\\\Magento\\\\Quote\\\\...', Array)\n#5 /bitnami/magento/htdocs/vendor/magento/framework/Webapi/ServiceInputProcessor.php(277): Magento\\Framework\\Webapi\\ServiceInputProcessor->convertValue(Array, '\\\\Magento\\\\Quote\\\\...')\n#6 /bitnami/magento/htdocs/vendor/magento/framework/Webapi/ServiceInputProcessor.php(478): Magento\\Framework\\Webapi\\ServiceInputProcessor->_createFromArray('\\\\Magento\\\\Quote\\\\...', Array)\n#7 /bitnami/magento/htdocs/vendor/magento/framework/Webapi/ServiceInputProcessor.php(277): Magento\\Framework\\Webapi\\ServiceInputProcessor->convertValue(Array, '\\\\Magento\\\\Quote\\\\...')\n#8 /bitnami/magento/htdocs/vendor/magento/framework/Webapi/ServiceInputProcessor.php(478): Magento\\Framework\\Webapi\\ServiceInputProcessor->_createFromArray('Magento\\\\Checkou...', Array)\n#9 /bitnami/magento/htdocs/vendor/magento/framework/Webapi/ServiceInputProcessor.php(165): Magento\\Framework\\Webapi\\ServiceInputProcessor->convertValue(Array, 'Magento\\\\Checkou...')\n#10 /bitnami/magento/htdocs/vendor/magento/module-webapi/Controller/Rest/InputParamsResolver.php(84): Magento\\Framework\\Webapi\\ServiceInputProcessor->process('Magento\\\\Checkou...', 'saveAddressInfo...', Array)\n#11 /bitnami/magento/htdocs/vendor/magento/framework/Interception/Interceptor.php(58): Magento\\Webapi\\Controller\\Rest\\InputParamsResolver->resolve()\n#12 /bitnami/magento/htdocs/vendor/magento/framework/Interception/Interceptor.php(138): Magento\\Webapi\\Controller\\Rest\\InputParamsResolver\\Interceptor->___callParent('resolve', Array)\n#13 /bitnami/magento/htdocs/vendor/magento/framework/Interception/Interceptor.php(153): Magento\\Webapi\\Controller\\Rest\\InputParamsResolver\\Interceptor->Magento\\Framework\\Interception\\{closure}()\n#14 /bitnami/magento/htdocs/generated/code/Magento/Webapi/Controller/Rest/InputParamsResolver/Interceptor.php(23): Magento\\Webapi\\Controller\\Rest\\InputParamsResolver\\Interceptor->___callPlugins('resolve', Array, Array)\n#15 /bitnami/magento/htdocs/vendor/magento/module-webapi/Controller/Rest/SynchronousRequestProcessor.php(85): Magento\\Webapi\\Controller\\Rest\\InputParamsResolver\\Interceptor->resolve()\n#16 /bitnami/magento/htdocs/vendor/magento/module-webapi/Controller/Rest.php(188): Magento\\Webapi\\Controller\\Rest\\SynchronousRequestProcessor->process(Object(Magento\\Framework\\Webapi\\Rest\\Request\\Proxy))\n#17 /bitnami/magento/htdocs/vendor/magento/framework/Interception/Interceptor.php(58): Magento\\Webapi\\Controller\\Rest->dispatch(Object(Magento\\Framework\\App\\Request\\Http))\n#18 /bitnami/magento/htdocs/vendor/magento/framework/Interception/Interceptor.php(138): Magento\\Webapi\\Controller\\Rest\\Interceptor->___callParent('dispatch', Array)\n#19 /bitnami/magento/htdocs/vendor/magento/framework/Interception/Interceptor.php(153): Magento\\Webapi\\Controller\\Rest\\Interceptor->Magento\\Framework\\Interception\\{closure}(Object(Magento\\Framework\\App\\Request\\Http))\n#20 /bitnami/magento/htdocs/generated/code/Magento/Webapi/Controller/Rest/Interceptor.php(23): Magento\\Webapi\\Controller\\Rest\\Interceptor->___callPlugins('dispatch', Array, Array)\n#21 /bitnami/magento/htdocs/vendor/magento/framework/App/Http.php(116): Magento\\Webapi\\Controller\\Rest\\Interceptor->dispatch(Object(Magento\\Framework\\App\\Request\\Http))\n#22 /bitnami/magento/htdocs/generated/code/Magento/Framework/App/Http/Interceptor.php(23): Magento\\Framework\\App\\Http->launch()\n#23 /bitnami/magento/htdocs/vendor/magento/framework/App/Bootstrap.php(263): Magento\\Framework\\App\\Http\\Interceptor->launch()\n#24 /bitnami/magento/htdocs/index.php(39): Magento\\Framework\\App\\Bootstrap->run(Object(Magento\\Framework\\App\\Http\\Interceptor))\n#25 {main}"
}

See in the exception.log file:

Screenshot from 2020-11-04 16-31-34


Please provide Severity assessment for the Issue as Reporter. This information will help during Confirmation and Issue triage processes.

  • 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: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 18 (3 by maintainers)

Most upvoted comments

@apedicdev I started typing out a really long investigative message for what I’ve discovered about this issue, but might have found the cause and solution. You don’t happen to use Avalara for tax / address validation do you?

Check this out: https://github.com/avadev/Avalara-AvaTax-for-Magento2/releases/tag/2.1.9

image

I’ve been having the same exact error for a client of mine since we upgraded to Magento 2.4.0.

  • As part of the address validation of the Avalara Tax module, it fetches quote address data which gets the “discount” extension attribute populated on it if a customer has applied a coupon code.
  • The extension attributes mistakingly get set with the billing address and sent in the place order request when trying to complete checkout.
  • Magento’s web api processor uses Interfaces to determine which data in a webapi request is valid to set in the Interfaces implementing Model as well as computing the php “setters” to call to set that data on the model. In this case it sees “discount_data”, so it tries to call \Magento\SalesRule\Api\Data\RuleDiscountInterface::setDiscountData() which doesn’t exist.

I think it makes sense that there is no \Magento\SalesRule\Api\Data\RuleDiscountInterface::setDiscountData() method since you wouldn’t want the client/browser to be able to manipulate and send that particular data back to the server to be saved.

The updated version of the Avalara Avatax module includes a change in their address validation javascript that scrubs the address data coming back from the result of saving the shipping step. It stops the “discount_data” from getting set on the billing address that gets sent back to the server when placing order:

image

If you aren’t using avalara, hopefully this at least helps us understand how that data might be getting added to the address data when trying to place orders.

Hi Can you please share the PR link or commit id. We are facing this issue in 2.4.2-P1

@floorz this has been replicated on magento clean installation using payload from documentation https://magento.redoc.ly/2.4.0-admin/tag/guest-cartscartIdshipping-information I guess if the discount_data isn’t needed, then documentation should be fixed accordingly. Viceversa, setters need to be implemented. @engcom-Alfa can you please confirm what is the default behaviour you want?