jlevers / selling-partner-api

A PHP client library for Amazon's Selling Partner API
BSD 3-Clause "New" or "Revised" License
404 stars 198 forks source link

Issue with productFees - case mismatch in GetMyFeesEstimateRequest #680

Closed nikgilbe closed 4 months ago

nikgilbe commented 7 months ago

Problem description:

When attempting getMyFeesEstimateForSKU, the GetMyFeesEstimateRequest object properties appear to want an initial capital, but are showing as lower case when displayed, resulting in a '400' error. I edited a number of the files in 'vendor/jlevers/selling-partner-api/src/Seller/ProductFeesV0' to force initial capitals and managed to get a successful response, reverted back to the original and the error reappeared.

Error:

Exception: Bad Request (400) Response: {
  "errors": [
    {
      "code": "InvalidInput",
      "message": "This is an invalid input",
      "details": "Missing objects [FeesEstimateRequest] in body parameters."
    }
  ]
}

Code

$connector = SellingPartnerApi::make(
    clientId: $sp_conn['client_id'],
    clientSecret: $sp_conn['secret'],
    refreshToken: $sp_conn['refresh_token'],
    endpoint: Endpoint::EU,
)->seller();

$feesApi = $connector->productFees();
$marketplace = 'A1F83G8C2ARO7P';
$identifier = "abc" . date("mdis");
$seller_sku = "ABC123";
$sku_price = 529.94;

$listingPrice = new feeDto\MoneyType('GBP', $sku_price);
$fee_price = new feeDto\PriceToEstimateFees($listingPrice);
$fee_request = new feeDto\FeesEstimateRequest($marketplace, $fee_price, $identifier, false);
$request = new feeDto\GetMyFeesEstimateRequest($fee_request);

try {
    $result = $feesApi->getMyFeesEstimateForSKU($seller_sku, $request);
    $json = $result->json();
    $finalFee = $json['payload']['FeesEstimateResult']['FeesEstimate']['TotalFeesEstimate']['Amount'];
    doLog("SKU [$seller_sku] Price [$sku_price] Final Fee [$finalFee]", "cli");
} catch (Exception $e) {
    print_r($request);
    echo "Exception: ",  $e->getMessage(), PHP_EOL;
}

Contents of $request when failed

SellingPartnerApi\Seller\ProductFeesV0\Dto\GetMyFeesEstimateRequest Object
(
    [feesEstimateRequest] => SellingPartnerApi\Seller\ProductFeesV0\Dto\FeesEstimateRequest Object
        (
            [marketplaceId] => A1F83G8C2ARO7P
            [priceToEstimateFees] => SellingPartnerApi\Seller\ProductFeesV0\Dto\PriceToEstimateFees Object
                (
                    [listingPrice] => SellingPartnerApi\Seller\ProductFeesV0\Dto\MoneyType Object
                        (
                            [currencyCode] => GBP
                            [amount] => 529.94
                        )

                    [shipping] =>
                    [points] =>
                )

            [identifier] => abc04100330
            [isAmazonFulfilled] =>
            [optionalFulfillmentProgram] =>
        )

)

Successful output using modified DTOs

SellingPartnerApi\Seller\ProductFeesV0\Dto\GetMyFeesEstimateRequest Object
(
    [FeesEstimateRequest] => SellingPartnerApi\Seller\ProductFeesV0\Dto\FeesEstimateRequest Object
        (
            [MarketplaceId] => A1F83G8C2ARO7P
            [PriceToEstimateFees] => SellingPartnerApi\Seller\ProductFeesV0\Dto\PriceToEstimateFees Object
                (
                    [ListingPrice] => SellingPartnerApi\Seller\ProductFeesV0\Dto\MoneyType Object
                        (
                            [CurrencyCode] => GBP
                            [Amount] => 529.94
                        )

                    [shipping] =>
                    [points] =>
                )

            [Identifier] => dkw04102701
            [isAmazonFulfilled] =>
            [optionalFulfillmentProgram] =>
        )

)
[2024-04-10 08:12:52] SKU [ABC123] Price [529.94] Final Fee [81.58]
BlackHallNick commented 7 months ago

I have also encountered this issue, what files specifically need to be modified to force it to work?

nikgilbe commented 7 months ago

I must admit I was hacking around a bit, but these are the modified files:

selling-partner-api/src/Seller/ProductFeesV0/Dto

FeesEstimateByIdRequest.php
FeesEstimateRequest.php
GetMyFeesEstimateRequest.php
MoneyType.php
PriceToEstimateFees.php
BlackHallNick commented 7 months ago

I've capiltalized every feasible property in these files and I can't force a working response. I'm not sure even exactly where the case mismatch is.

nikgilbe commented 7 months ago

This is the untouched version of FeesEstimateRequest.php

<?php

namespace SellingPartnerApi\Seller\ProductFeesV0\Dto;

use Crescat\SaloonSdkGenerator\BaseDto;

final class FeesEstimateRequest extends BaseDto
{
    protected static array $attributeMap = [
        'marketplaceId' => 'MarketplaceId',
        'priceToEstimateFees' => 'PriceToEstimateFees',
        'identifier' => 'Identifier',
        'isAmazonFulfilled' => 'IsAmazonFulfilled',
        'optionalFulfillmentProgram' => 'OptionalFulfillmentProgram',
    ];

    /**
     * @param  string  $marketplaceId  A marketplace identifier.
     * @param  PriceToEstimateFees  $priceToEstimateFees  Price information for an item, used to estimate fees.
     * @param  string  $identifier  A unique identifier provided by the caller to track this request.
     * @param  ?bool  $isAmazonFulfilled  When true, the offer is fulfilled by Amazon.
     * @param  ?string  $optionalFulfillmentProgram  An optional enrollment program to return the estimated fees when the offer is fulfilled by Amazon (IsAmazonFulfilled is set to true).
     */
    public function __construct(
        public readonly string $marketplaceId,
        public readonly PriceToEstimateFees $priceToEstimateFees,
        public readonly string $identifier,
        public readonly ?bool $isAmazonFulfilled = null,
        public readonly ?string $optionalFulfillmentProgram = null,
    ) {
    }
}

This is with the changes I made:

<?php

namespace SellingPartnerApi\Seller\ProductFeesV0\Dto;

use Crescat\SaloonSdkGenerator\BaseDto;

final class FeesEstimateRequest extends BaseDto
{
    protected static array $attributeMap = [
        'MarketplaceId' => 'MarketplaceId',
        'PriceToEstimateFees' => 'PriceToEstimateFees',
        'Identifier' => 'Identifier',
        'isAmazonFulfilled' => 'IsAmazonFulfilled',
        'optionalFulfillmentProgram' => 'OptionalFulfillmentProgram',
    ];

    /**
     * @param  string  $marketplaceId  A marketplace identifier.
     * @param  PriceToEstimateFees  $priceToEstimateFees  Price information for an item, used to estimate fees.
     * @param  string  $identifier  A unique identifier provided by the caller to track this request.
     * @param  ?bool  $isAmazonFulfilled  When true, the offer is fulfilled by Amazon.
     * @param  ?string  $optionalFulfillmentProgram  An optional enrollment program to return the estimated fees when the offer is fulfilled by Amazon (IsAmazonFulfilled is set to true).
     */
    public function __construct(
        public readonly string $MarketplaceId,
        public readonly PriceToEstimateFees $PriceToEstimateFees,
        public readonly string $Identifier,
        public readonly ?bool $isAmazonFulfilled = null,
        public readonly ?string $optionalFulfillmentProgram = null,
    ) {
    }
}

So MarketplaceId instead of marketplaceId, PriceToEstimateFees instead of priceToEstimateFees and Identifier instead of identifier in 2 places. I don't know if they all needed changing or not.

Similar changes were made in the other files mentioned.

kankutus commented 6 months ago

I am not expert and maybe there is easy way of doing it but I had the same issue with the MerchantFulfilment API.

attribute map is not applyin to body while sending request. So I have change the line From: $originalName = $this->attributeMap[$name] ?? $name; To: $originalName = static::class::$attributeMap[$name] ?? $name;

in HasArrayableAttributes.php file in hightsightlabs saloon sdk generator (line 50). It is working now but I do not know what I am breaking with this :)

nikgilbe commented 6 months ago

Thanks. That's certainly a cleaner fix for now, and is working for me too.

Inbasecom commented 6 months ago

I am not expert and maybe there is easy way of doing it but I had the same issue with the MerchantFulfilment API.

attribute map is not applyin to body while sending request. So I have change the line From: $originalName = $this->attributeMap[$name] ?? $name; To: $originalName = static::class::$attributeMap[$name] ?? $name;

in HasArrayableAttributes.php file in hightsightlabs saloon sdk generator (line 50). It is working now but I do not know what I am breaking with this :)

Thanks, that is the solution and works fine! @jlevers can you fix in 6.0.6 ?

jlevers commented 5 months ago

This fix is in main and will be released in v7.

jlevers commented 4 months ago

Released in v7.0.0.