ericblade/mws-advanced

listOrderItems returns object instead of an array

pwrnrd opened this issue · 4 comments

The API call to listOrderItems returns an object if there are multiple items in an order.

Output:

{
   "0" : {
       OrderItem_ 1
    },
    "1": {
        OrderItem_2 
    }
    isGift: "someval"
    quantityOrdered: "someval"
    quantityShipped: "someval"
    productInfo: "someval"
}

Where OrderItem_1 and OrderItem_2 are objects in line with the MWS documentation regarding OrderItem: https://docs.developer.amazonservices.com/en_UK/orders-2013-09-01/Orders_Datatypes.html#OrderItem .

Expected:

[ {OrderItem_1}, {OrderItem_2}]

I did some digging and I found that the input to the function parseOrderItems in orderItems.js does not meet the expected input. The argument orderItemsList of this function retrieves the following:

const parseOrderItems = orderItemsList => {
	const { NextToken: nextToken, AmazonOrderId: orderId } = orderItemsList;
	console.log(JSON.stringify(orderItemsList, null, 4));
        ....
        ....

The above outputs:

{
    "OrderItems": {
        "OrderItem": [
            {OrderItem_1},
            {OrderItem_2}
         ]
    }
}

Perhaps this should be/expected:

{
    "OrderItems": [{
        "OrderItem": OrderItem_1,
        "OrderItem": OrderItem_2
    }]
}

OR: 

{
    "OrderItems": [
        OrderItem_1,
        OrderItem_2
    ]
}


I think I found where the error arises, but I don't know how to fix this... Where should I dig next in order to solve this issue? How could this issue be solved?

Hmm. Interesting question. I can't think of any orders i've had in memorable history with multiple items, if any . . so I don't really have anything to check it on.

If the parser is receiving data in a format that doesn't make sense, then it's probably the fault of lib/util/flatten-result.js.

Perhaps you could have a look at the results of parseEndpoint(parseOrderItems)('ListOrderItems')({ AmazonOrderId: '...' }, { noFlatten: true })

If flatten is breaking it, and there's not an obvious way to fix flatten, it might be easier to fix list-order-items to use noFlatten mode and deal with it in there.

also, if you were to save the raw output to disk, using { saveRaw: 'filename.json' } then you could run parseOrderItems(flattenResult(fileText)) on it to further examine it without having to hit the servers while figuring it out.

one thought might be to use

const parseOrderItems = (orderItemsList) => {
    const { NextToken: nextToken, AmazonOrderId: orderId } = orderItemsList;
    ~~const arr = forceArray(orderItemsList.OrderItems);~~
    const arr = forceArray(orderItemsList.OrderItems).map(x => Object.values(x));
    const orderItems = arr.map(x => transformIntsAndBools(transformObjectKeys(x.OrderItem)));

i'm having a little trouble envisioning exactly how to fix it without seeing it though. And the worst case, is that it appears totally differently for individual items versus multiple items, thanks to flattenResult . . .

Thank you! You send me in the right direction. Apparently the structure of the results object from the API is similar:

{
  "ListOrderItemsResponse": {
      "$": {
          "xmlns": "https://mws.amazonservices.com/Orders/2013-09-01"
      },
      "ListOrderItemsResult": [
          {
              "OrderItems": [
                  {
                      "OrderItem": [
                          OrderItem1,
                          OrderItem2
                      ]
                  }
                ]
          }
        ]
   }
}

Hence, luckily, flattening was not the issue. I implemented the following solution which seems to work for me:

const parseOrderItems = orderItemsList => {
  const { NextToken: nextToken, AmazonOrderId: orderId } = orderItemsList;
  const arr = forceArray(orderItemsList.OrderItems.OrderItem);

  const orderItems = arr.map(x => {
    const xTransformedKeys = transformObjectKeys(x);
    const xTransformedKeysIntAndBools = transformIntsAndBools(xTransformedKeys);
    return xTransformedKeysIntAndBools;
  });
 
  const ret = {
    orderItems,
    nextToken,
    orderId
  };
  return ret;
};

I did not yet run any of the tests. After my holiday I'll fix the getOrder function and this one as well.

ahhh i wonder if that's my error doing the forceArray on orderItemsList.OrderItems instead of OrderItems.OrderItem

If that works with 1 and multiples, then that's almost definitely the way to do it.

i'd keep the map as the oneliner, it's still pretty easy to read, and without assigning temp vars, it'll lessen the amount of garbage thrown at the garbage collector. If you're going to do a pull req on that section, you might as well remove the "const ret =" assignment, and just return { orderItems, nextToken, orderId }; too