Skip to content
This repository has been archived by the owner on Feb 6, 2024. It is now read-only.

Commit

Permalink
feat: create listRecommendations, add enum mock to unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
justinemmanuelmercado committed Jul 8, 2020
1 parent e56474a commit 458df2a
Show file tree
Hide file tree
Showing 4 changed files with 374 additions and 4 deletions.
172 changes: 170 additions & 2 deletions src/sections/recommendations.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Codec, GetInterface } from 'purify-ts'
import { Codec, enumeration, GetInterface, number, optional, string } from 'purify-ts'

import { ParsingError } from '../error'
import { HttpClient, RequestMeta, Resource } from '../http'
import { mwsDate } from '../parsing'
import { ensureArray, mwsDate, nextToken as nextTokenCodec } from '../parsing'
import { getServiceStatusByResource } from './shared'
import { FulfillmentChannelEnum } from './types'

const RECOMMENDATIONS_API_VERSION = '2013-04-01'

Expand All @@ -29,9 +30,176 @@ const GetLastUpdatedTimeForRecommendationsResponse = Codec.interface({
}),
})

type RecommedationCategory =
| 'Inventory'
| 'Selection'
| 'Pricing'
| 'Fulfillment'
| 'ListingQuality'
| 'GlobalSelling'
| 'Advertising'

interface CategoryQuery {
RecommendationCategory: RecommedationCategory
FilterOptions: string
}

interface ListRecommendationsParameters {
MarketplaceId: string
RecommendationCategory?: RecommedationCategory
CategoryQueryList?: CategoryQuery[]
}

const ProductIdentifier = Codec.interface({
Asin: string,
Sku: string,
Upc: string,
})

const Price = Codec.interface({
CurrencyCode: string,
Amount: number,
})

const DimensionMeasure = Codec.interface({
Value: number,
Unit: string,
})

const WeightMeasure = Codec.interface({
Value: number,
Unit: string,
})

const ItemDimensions = Codec.interface({
Height: DimensionMeasure,
Width: DimensionMeasure,
Length: DimensionMeasure,
Weight: WeightMeasure,
})

const FulfillmentRecommendation = Codec.interface({
RecommendationId: string,
RecommendationReason: string,
LastUpdated: mwsDate,
ItemIdentifier: ProductIdentifier,
ItemName: optional(string),
BrandName: optional(string),
ProductCategory: optional(string),
SalesRank: optional(number),
BuyBoxPrice: optional(Price),
NumberOfOffers: optional(number),
NumberOfOffersFulfilledByAmazon: optional(number),
AverageCustomerReview: optional(number),
NumberOfCustomerReviews: optional(number),
ItemDimensions: optional(ItemDimensions),
})

const FulfillmentChannel = enumeration(FulfillmentChannelEnum)

const InventoryRecommendation = Codec.interface({
RecommendationId: string,
RecommendationReason: string,
LastUpdated: mwsDate,
ItemIdentifier: ProductIdentifier,
ItemName: optional(string),
FulfillmentChannel: optional(FulfillmentChannel),
AvailableQuantity: optional(number),
DaysUntilStockRunsOut: optional(number),
DaysOutOfStockLast30Days: optional(number),
})

const PricingRecommendation = Codec.interface({
RecommendationId: string,
RecommendationReason: string,
LastUpdated: mwsDate,
ItemIdentifier: ProductIdentifier,
ItemName: optional(string),
Condition: optional(string),
SubCondition: optional(string),
FulfillmentChannel: optional(FulfillmentChannel),
YourPricePluShipping: optional(Price),
LowestPricePlusShipping: optional(Price),
PriceDifferenceToLowPrice: optional(Price),
MedianPricePlusShipping: optional(Price),
LowestMerchantFulfilledOfferPrice: optional(Price),
LowestAmazonFulfilledOfferPrice: optional(Price),
NumberOfMerchatFulfilledfOffers: optional(number),
NumberOfAmazonFulfilledOrders: optional(number),
})

const GlobalSellingRecommendation = Codec.interface({
RecommendationId: string,
RecommendationReason: string,
LastUpdated: mwsDate,
ItemIdentifier: ProductIdentifier,
ItemName: optional(string),
BrandName: optional(string),
ProductCategory: optional(string),
SalesRank: optional(number),
BuyBoxPrice: optional(Price),
NumberOfOffers: optional(number),
NumberOfOffersFulfilledByAmazon: optional(number),
AverageCustomerReview: optional(number),
NumberOfCustomerReviews: optional(number),
ItemDimensions: optional(ItemDimensions),
})

const AdvertisingRecommendation = Codec.interface({
RecommendationId: string,
RecommendationReason: string,
LastUpdated: mwsDate,
ItemIdentifier: ProductIdentifier,
ItemName: optional(string),
BrandName: optional(string),
ProductCategory: optional(string),
SalesRank: optional(number),
YourPricePluShipping: optional(Price),
LowestPricePlusShipping: optional(Price),
AvailableQuantity: optional(number),
SalesForTheLast30Days: optional(number),
})

const ListRecommendations = Codec.interface({
NextToken: optional(nextTokenCodec('ListRecommendations')),
FulfillmentRecommendations: optional(ensureArray('member', FulfillmentRecommendation)),
InventoryRecommendations: optional(ensureArray('member', InventoryRecommendation)),
PricingRecommendations: optional(ensureArray('member', PricingRecommendation)),
GlobalSellingRecommendations: optional(ensureArray('member', GlobalSellingRecommendation)),
AdvertisingRecommendations: optional(ensureArray('member', AdvertisingRecommendation)),
})

type ListRecommendations = GetInterface<typeof ListRecommendations>

const ListRecommendationsResponse = Codec.interface({
ListRecommendationsResponse: Codec.interface({
ListRecommendationsResult: ListRecommendations,
}),
})

export class Recommendations {
constructor(private httpClient: HttpClient) {}

async listRecommendations(
parameters: ListRecommendationsParameters,
): Promise<[ListRecommendations, RequestMeta]> {
const [response, meta] = await this.httpClient.request('POST', {
resource: Resource.Recommendations,
version: RECOMMENDATIONS_API_VERSION,
action: 'ListRecommendations',
parameters: {
MarketplaceId: parameters.MarketplaceId,
},
})

return ListRecommendationsResponse.decode(response).caseOf({
Right: (x) => [x.ListRecommendationsResponse.ListRecommendationsResult, meta],
Left: (error) => {
throw new ParsingError(error)
},
})
}

async getLastUpdatedTimeForRecommendations(
parameters: GetLastUpdatedTimeForRecommendationsParameters,
): Promise<[GetLastUpdatedTimeForRecommendations, RequestMeta]> {
Expand Down
169 changes: 169 additions & 0 deletions test/unit/__snapshots__/recommendations.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,172 @@ Array [
},
]
`;

exports[`recommendations listRecommendations returns a list of recommendations if succesful 1`] = `
Array [
Object {
"AdvertisingRecommendations": Array [
Object {
"AvailableQuantity": 1,
"BrandName": "String",
"ItemIdentifier": Object {
"Asin": "String",
"Sku": "String",
"Upc": "String",
},
"ItemName": "String",
"LastUpdated": 1969-07-21T02:56:03.000Z,
"LowestPricePlusShipping": Object {
"Amount": 100,
"CurrencyCode": "String",
},
"ProductCategory": "String",
"RecommendationId": "String",
"RecommendationReason": "String",
"SalesForTheLast30Days": 1,
"SalesRank": 1,
},
],
"FulfillmentRecommendations": Array [
Object {
"AverageCustomerReview": 100,
"BrandName": "String",
"ItemDimensions": Object {
"Height": Object {
"Unit": "String",
"Value": 100,
},
"Length": Object {
"Unit": "String",
"Value": 100,
},
"Weight": Object {
"Unit": "String",
"Value": 100,
},
"Width": Object {
"Unit": "String",
"Value": 100,
},
},
"ItemIdentifier": Object {
"Asin": "String",
"Sku": "String",
"Upc": "String",
},
"ItemName": "String",
"LastUpdated": 1969-07-21T02:56:03.000Z,
"NumberOfCustomerReviews": 1,
"NumberOfOffers": 1,
"NumberOfOffersFulfilledByAmazon": 1,
"ProductCategory": "String",
"RecommendationId": "String",
"RecommendationReason": "String",
"SalesRank": 1,
},
],
"GlobalSellingRecommendations": Array [
Object {
"AverageCustomerReview": 100,
"BrandName": "String",
"ItemDimensions": Object {
"Height": Object {
"Unit": "String",
"Value": 100,
},
"Length": Object {
"Unit": "String",
"Value": 100,
},
"Weight": Object {
"Unit": "String",
"Value": 100,
},
"Width": Object {
"Unit": "String",
"Value": 100,
},
},
"ItemIdentifier": Object {
"Asin": "String",
"Sku": "String",
"Upc": "String",
},
"ItemName": "String",
"LastUpdated": 1969-07-21T02:56:03.000Z,
"NumberOfCustomerReviews": 1,
"NumberOfOffers": 1,
"NumberOfOffersFulfilledByAmazon": 1,
"ProductCategory": "String",
"RecommendationId": "String",
"RecommendationReason": "String",
"SalesRank": 1,
},
],
"InventoryRecommendations": Array [
Object {
"AvailableQuantity": 1,
"DaysOutOfStockLast30Days": 1,
"DaysUntilStockRunsOut": 1,
"FulfillmentChannel": "String",
"ItemIdentifier": Object {
"Asin": "String",
"Sku": "String",
"Upc": "String",
},
"ItemName": "String",
"LastUpdated": 1969-07-21T02:56:03.000Z,
"RecommendationId": "String",
"RecommendationReason": "String",
},
],
"NextToken": NextToken {
"action": "ListRecommendations",
"token": "String",
},
"PricingRecommendations": Array [
Object {
"Condition": "String",
"FulfillmentChannel": "String",
"ItemIdentifier": Object {
"Asin": "String",
"Sku": "String",
"Upc": "String",
},
"ItemName": "String",
"LastUpdated": 1969-07-21T02:56:03.000Z,
"LowestAmazonFulfilledOfferPrice": Object {
"Amount": 100,
"CurrencyCode": "String",
},
"LowestMerchantFulfilledOfferPrice": Object {
"Amount": 100,
"CurrencyCode": "String",
},
"LowestPricePlusShipping": Object {
"Amount": 100,
"CurrencyCode": "String",
},
"MedianPricePlusShipping": Object {
"Amount": 100,
"CurrencyCode": "String",
},
"PriceDifferenceToLowPrice": Object {
"Amount": 100,
"CurrencyCode": "String",
},
"RecommendationId": "String",
"RecommendationReason": "String",
"SubCondition": "String",
},
],
},
Object {
"quotaMax": 1000,
"quotaRemaining": 999,
"quotaResetOn": 2020-04-06T10:22:23.582Z,
"requestId": "0",
"timestamp": 2020-05-06T09:22:23.582Z,
},
]
`;
4 changes: 2 additions & 2 deletions test/unit/finances.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ParsingError } from '../../src'
import { NextToken } from '../../src/parsing'
import { createMockHttpClient, mockMwsFail, mockMwsServiceStatus, parsingError } from '../utils'

function mockFunctions() {
function mockEnum() {
/**
* Mock everything in purify-ts, restore it back to normal,
* except for `enumeration` which will be stubbed to accept
Expand Down Expand Up @@ -33,7 +33,7 @@ function mockFunctions() {
},
}
}
jest.mock('purify-ts', () => mockFunctions())
jest.mock('purify-ts', () => mockEnum())

describe('finances', () => {
describe('listFinancialEventsByNextToken', () => {
Expand Down

0 comments on commit 458df2a

Please sign in to comment.