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

Commit

Permalink
Merge pull request #113 from ScaleLeap/feature/merchant-fulfillment
Browse files Browse the repository at this point in the history
feat: merchant-fulfillment
  • Loading branch information
justinemmanuelmercado committed Jul 8, 2020
2 parents 3917fcf + 85780de commit d9911d3
Show file tree
Hide file tree
Showing 28 changed files with 3,572 additions and 52 deletions.
384 changes: 384 additions & 0 deletions docs/README.md

Large diffs are not rendered by default.

75 changes: 39 additions & 36 deletions src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ export type HttpMethod = 'GET' | 'POST'
export type ParameterTypes =
| string
| number
| (number | string)[]
| object[]
| (number | string | object)[]
| boolean
| { [key: string]: ParameterTypes }
| undefined
Expand All @@ -79,6 +78,7 @@ export enum Resource {
Sellers = 'Sellers',
Subscriptions = 'Subscriptions',
Feeds = 'Feeds',
MerchantFulfillment = 'MerchantFulfillment',
}

export interface ResourceActions {
Expand Down Expand Up @@ -151,6 +151,13 @@ export interface ResourceActions {
| 'GetFeedSubmissionCount'
| 'CancelFeedSubmissions'
| 'GetFeedSubmissionResult'
[Resource.MerchantFulfillment]:
| 'GetEligibleShippingServices'
| 'GetAdditionalSellerInputs'
| 'CreateShipment'
| 'GetShipment'
| 'CancelShipment'
| 'GetServiceStatus'
}

export interface Request {
Expand Down Expand Up @@ -186,55 +193,51 @@ const canonicalizeParameters = (parameters: CleanParameters): string => {
return sp.toString().replace(/\+/g, '%20')
}

export const toDotNotation = (object: object, prefix: string) => {
const result: { [key: string]: string | number | boolean } = {}
function dotify(plainObject: object, currentKey?: string | number) {
Object.entries(plainObject).forEach(([key, value]) => {
const newKey = currentKey ? `${currentKey}.${key}` : key // joined key with dot
if (value && typeof value === 'object') {
dotify(value, newKey) // it's a nested object, so do it again
} else {
Object.assign(result, { [`${prefix}.${newKey}`]: value }) // it's not an object, so set the property
}
})
}

dotify(object)
return result
}

export const cleanParameters = (parameters: Parameters): CleanParameters =>
export const cleanParameters = (
parameters: Parameters,
baseObject: Record<string, string> = {},
outerKey?: string,
): CleanParameters =>
Object.entries(parameters)

// Filter undefined
.filter(([, parameter]) => parameter !== undefined)
.reduce((result, [key, parameter]) => {
if (typeof parameter === 'string' || !Number.isNaN(Number(parameter))) {
/**
* If parameter is type string or number, assign it to result
*/
Object.assign(result, { [key]: String(parameter) })

// Loop through each key
.reduce((_, [key, parameter]) => {
const trueKey = outerKey ? `${outerKey}.${key}` : key
/**
* If parameter is type string, number, boolean assign it to result
*/
if (
typeof parameter === 'string' ||
!Number.isNaN(Number(parameter)) ||
typeof parameter === 'boolean'
) {
Object.assign(baseObject, { [trueKey]: String(parameter) })
} else if (Array.isArray(parameter)) {
/**
* If parameter is type array reduce it to dotnotation
*/
parameter.forEach((parameterChild: string | number | object, index: number) => {
if (typeof parameterChild === 'string' || !Number.isNaN(Number(parameterChild))) {
Object.assign(result, { [`${key}.${index + 1}`]: String(parameterChild) })
parameter.forEach((parameterChild: object | string | number | boolean, index: number) => {
if (
typeof parameterChild === 'string' ||
!Number.isNaN(Number(parameterChild)) ||
typeof parameter === 'boolean'
) {
Object.assign(baseObject, { [`${trueKey}.${index + 1}`]: String(parameterChild) })
} else {
Object.assign(result, toDotNotation(parameterChild as object, `${key}.${index + 1}`))
cleanParameters(parameterChild as Parameters, baseObject, `${trueKey}.${index + 1}`)
}
})
} else {
/**
* If parameter is type object parameterize it
*/
Object.entries(
cleanParameters(parameter as Parameters),
).forEach(([innerKey, innerValue]: [string, string]) =>
Object.assign(result, { [`${key}.${innerKey}`]: innerValue }),
)
cleanParameters(parameter as Parameters, baseObject, `${trueKey}`)
}

return result
return baseObject
}, {} as CleanParameters)

const defaultFetch = ({ url, method, headers, data }: Request): Promise<RequestResponse> =>
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ export * from './sections/feeds'
export * from './sections/finances/finances'
export * from './sections/finances/codec'
export * from './sections/fulfillment-inventory'
export * from './sections/merchant-fulfillment/merchant-fulfillment'
export * from './sections/merchant-fulfillment/type'
export * from './sections/merchant-fulfillment/codec'
export * from './sections/subscriptions'
export * from './sections/orders'
export * from './sections/products/products'
Expand Down
11 changes: 11 additions & 0 deletions src/mws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { HttpClient } from './http'
import { Feeds } from './sections/feeds'
import { Finances } from './sections/finances/finances'
import { FulfillmentInventory } from './sections/fulfillment-inventory'
import { MerchantFulfillment } from './sections/merchant-fulfillment/merchant-fulfillment'
import { Orders } from './sections/orders'
import { Products } from './sections/products/products'
import { Reports } from './sections/reports'
Expand All @@ -15,6 +16,8 @@ export class MWS {

private _fulfillmentInventory!: FulfillmentInventory

private _merchantFulfillment!: MerchantFulfillment

private _orders!: Orders

private _products!: Products
Expand Down Expand Up @@ -67,6 +70,14 @@ export class MWS {
return this._fulfillmentInventory
}

get merchantFulfillment() {
if (!this._merchantFulfillment) {
this._merchantFulfillment = new MerchantFulfillment(this.httpClient)
}

return this._merchantFulfillment
}

get products() {
if (!this._products) {
this._products = new Products(this.httpClient)
Expand Down
12 changes: 11 additions & 1 deletion src/parsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,17 @@ export const mwsBoolean = Codec.custom<boolean>({
})

export const mwsDate = Codec.custom<Date>({
decode: (x) => string.decode(x).chain((aString) => date.decode(decodeURIComponent(aString))),
decode: (x) =>
string.decode(x).chain((aString) => {
let toDecode = aString
// @todo
// Temp fix. Add UTC if no letter is found in string passed
// (crude way to check if time has timezone)
if (!/[A-Za-z]/g.test(aString)) {
toDecode += ' UTC+00:00'
}
return date.decode(decodeURIComponent(toDecode))
}),
encode: date.encode,
schema: date.schema,
})
Expand Down
11 changes: 11 additions & 0 deletions src/sections/codec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Codec, number, optional, string } from 'purify-ts'

/**
* Shared codecs
*/

// This is different from the CurrencyAmount used by merchant-fulfillment
export const CurrencyAmount = Codec.interface({
CurrencyCode: optional(string),
CurrencyAmount: optional(number),
})
6 changes: 1 addition & 5 deletions src/sections/finances/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from 'purify-ts'

import { ensureArray, ensureString, mwsDate, nextToken as nextTokenCodec } from '../../parsing'
import { CurrencyAmount } from '../codec'
import { FulfillmentChannelEnum } from '../types'

export enum ProcessingStatusEnum {
Expand All @@ -19,11 +20,6 @@ export enum ProcessingStatusEnum {

const ProcessingStatus = enumeration(ProcessingStatusEnum)

const CurrencyAmount = Codec.interface({
CurrencyCode: optional(string),
CurrencyAmount: optional(number),
})

const FinancialEventGroup = Codec.interface({
FinancialEventGroupId: optional(string),
ProcessingStatus: optional(ProcessingStatus),
Expand Down
Loading

0 comments on commit d9911d3

Please sign in to comment.