diff --git a/README.md b/README.md index 93dab9b..df450c2 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,9 @@ Purchase example ### Node.js ```js -const GMOPG = require('gmopg').GMOPG; +const {default: GMOPG, ENUMS} = require('gmopg'); -const gmopg = GMOPG.CREATE({ +const gmopg = new GMOPG({ axios: { baseURL: 'https://p01.mul-pay.jp' }, SiteID: 'Your SiteID', SitePass: 'Your SitePass', @@ -40,14 +40,14 @@ const amount = 1234 gmopg.entryTran({ OrderID: orderID, - JobCd: GMOPG.ENUMS.JobCd.Auth, + JobCd: ENUMS.JobCd.Auth, Amount: amount }).then((entryRes) => { gmopg.execTran({ AccessID: entryRes.AccessID, AccessPass: entryRes.AccessPass, OrderID: orderID, - Method: GMOPG.ENUMS.Method.Lump, + Method: ENUMS.Method.Lump, CardNo: '1234123412341234', Expire: '2024', SecurityCode: '123' @@ -55,7 +55,7 @@ gmopg.entryTran({ gmopg.alterTran({ AccessID: entryRes.AccessID, AccessPass: entryRes.AccessPass, - JobCd: GMOPG.ENUMS.JobCd.Sales, + JobCd: ENUMS.JobCd.Sales, Amount: amount }).then((alterRes) => { console.log(alterRes) @@ -67,7 +67,7 @@ gmopg.entryTran({ ### TypeScript ```ts -import GMOPG from 'gmopg' +import GMOPG, {ENUMS} from 'gmopg' const gmopg = new GMOPG({ axios: { baseURL: 'https://p01.mul-pay.jp' }, @@ -82,7 +82,7 @@ const amount = 1234 const entryRes = await gmopg.entryTran({ OrderID: orderID, - JobCd: GMOPG.ENUMS.JobCd.Auth, + JobCd: ENUMS.JobCd.Auth, Amount: amount }) @@ -90,7 +90,7 @@ const execRes = await gmopg.execTran({ AccessID: entryRes.AccessID, AccessPass: entryRes.AccessPass, OrderID: orderID, - Method: GMOPG.ENUMS.Method.Lump, + Method: ENUMS.Method.Lump, CardNo: '1234123412341234', Expire: '2024', SecurityCode: '123' @@ -99,7 +99,7 @@ const execRes = await gmopg.execTran({ const alterRes = await gmopg.alterTran({ AccessID: entryRes.AccessID, AccessPass: entryRes.AccessPass, - JobCd: GMOPG.ENUMS.JobCd.Sales, + JobCd: ENUMS.JobCd.Sales, Amount: amount }) ``` diff --git a/src/client.test.ts b/src/client.test.ts index f23750e..c7420f7 100644 --- a/src/client.test.ts +++ b/src/client.test.ts @@ -16,7 +16,7 @@ test.beforeEach((t) => { }) test('.post requests body correctly', async (t) => { - t.context.client.options = { + t.context.client.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'AccessID=accessid&AccessPass=accesspass', diff --git a/src/client.ts b/src/client.ts index 31e654d..e15d27f 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,13 +1,21 @@ -import {AxiosInstance, AxiosResponse} from 'axios' +import Axios, {AxiosInstance, AxiosResponse} from 'axios' import {BadRequest} from './errors' +import {IConfig} from './config.interface' +import {buildByEnv, defaults} from './config' import * as qs from 'qs' +import * as merge from 'deepmerge' export default class Client { public client: AxiosInstance - public options: object = {} + public config: IConfig + + constructor(config: IConfig = {}) { + this.config = merge(merge(defaults, config), buildByEnv()) + this.client = Axios.create(this.config.axios) + } public async post(endpoint: string, data: any): Promise { - const res: AxiosResponse = await this.client.post(endpoint, qs.stringify(data, { encode: false }), this.options) + const res: AxiosResponse = await this.client.post(endpoint, qs.stringify(data, {encode: false}), this.config.axios) const parsed: any = qs.parse(res.data) if (this.isError(parsed)) { diff --git a/src/client/cardable.test.ts b/src/client/cardable.test.ts index 7bcc0dd..f484146 100644 --- a/src/client/cardable.test.ts +++ b/src/client/cardable.test.ts @@ -1,23 +1,20 @@ -import anyTest, {TestInterface} from 'ava' +import test from 'ava' import Axios, {AxiosRequestConfig, AxiosResponse} from 'axios' -import Cardable from './cardable' +import Client from '../client' +import WithCardable from './cardable' import {SeqMode} from '../client.enum' import {IDeleteCardResult, ISaveCardResult, ISearchCardResult} from './cardable.interface' -interface Context { - card: Cardable -} +const Cardable = WithCardable(Client) +let card: any -const test = anyTest as TestInterface; - -test.beforeEach((t) => { - const card = new Cardable() +test.beforeEach(() => { + card = new Cardable() card.client = Axios.create({}) - t.context.card = card }) test('.defaultCardData returns default object', async (t) => { - const res = await t.context.card.defaultCardData() + const res = await card.defaultCardData() const expect = { SiteID: undefined, SitePass: undefined, @@ -27,7 +24,7 @@ test('.defaultCardData returns default object', async (t) => { }) test('.saveCard calls API and returns response', async (t) => { - t.context.card.options = { + card.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'CardSeq=cardseq&CardNo=cardno&Forward=forward&Brand=brand', @@ -46,7 +43,7 @@ test('.saveCard calls API and returns response', async (t) => { SitePass: 'sitepass', MemberID: 'memberid' } - const res = await t.context.card.saveCard(args) + const res = await card.saveCard(args) const expect: ISaveCardResult = { CardSeq: 'cardseq', @@ -58,7 +55,7 @@ test('.saveCard calls API and returns response', async (t) => { }) test('.deleteCard calls API and returns response', async (t) => { - t.context.card.options = { + card.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'CardSeq=cardseq', @@ -79,7 +76,7 @@ test('.deleteCard calls API and returns response', async (t) => { SeqMode: SeqMode.Logic, CardSeq: 'cardseq' } - const res = await t.context.card.deleteCard(args) + const res = await card.deleteCard(args) const expect: IDeleteCardResult = { CardSeq: 'cardseq' @@ -88,7 +85,7 @@ test('.deleteCard calls API and returns response', async (t) => { }) test('.searchCard calls API and returns response', async (t) => { - t.context.card.options = { + card.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'CardSeq=cardseq&DefaultFlag=1&CardName=cardname&CardNo=cardno&Expire=expire&HolderName=holdername&DeleteFlag=0', @@ -109,7 +106,7 @@ test('.searchCard calls API and returns response', async (t) => { SeqMode: SeqMode.Logic, CardSeq: 'cardseq' } - const res = await t.context.card.searchCard(args) + const res = await card.searchCard(args) const result: ISearchCardResult = { CardSeq: 'cardseq', diff --git a/src/client/cardable.ts b/src/client/cardable.ts index ffc452c..3bf3aea 100644 --- a/src/client/cardable.ts +++ b/src/client/cardable.ts @@ -1,7 +1,6 @@ -import {AxiosInstance} from 'axios' import * as merge from 'deepmerge' import Client from '../client' -import {IConfig} from '../config.interface' +import {Constructor} from '../util' import { IDeleteCardArgs, IDeleteCardResult, @@ -11,24 +10,13 @@ import { ISearchCardResult } from './cardable.interface' -export default class Cardable extends Client { - public name: string = 'Cardable' - public config: IConfig - public client: AxiosInstance - public options: object = {} - +export default >(Base: T) => class Cardable extends Base { public defaultCardData(): any { - let siteID - let sitePass - - if (this.config !== undefined) { - siteID = this.config.SiteID - sitePass = this.config.SitePass - } + const {SiteID, SitePass} = this.config return { - SiteID: siteID, - SitePass: sitePass, + SiteID, + SitePass, MemberID: undefined } } @@ -37,14 +25,14 @@ export default class Cardable extends Client { const data: ISaveCardArgs = merge(this.defaultCardData(), args) const parsed: any = await this.post('/payment/SaveCard.idPass', data) - return parsed + return parsed } public async deleteCard(args: IDeleteCardArgs): Promise { const data: IDeleteCardArgs = merge(this.defaultCardData(), args) const parsed: any = await this.post('/payment/DeleteCard.idPass', data) - return parsed + return parsed } public async searchCard(args: ISearchCardArgs): Promise { diff --git a/src/client/cvsTranable.test.ts b/src/client/cvsTranable.test.ts index f3bbd57..8d5f111 100644 --- a/src/client/cvsTranable.test.ts +++ b/src/client/cvsTranable.test.ts @@ -1,23 +1,24 @@ -import anyTest, {TestInterface} from 'ava' +import test from 'ava' import Axios, {AxiosRequestConfig, AxiosResponse} from 'axios' import {CvsCode, Status} from '../client.enum' -import CvsTranable from './cvsTranable' +import Client from '../client' +import WithCvsTranable from './cvsTranable' import { ICancelCvsResult, IEntryTranCvsResult, IExecTranCvsResult } from './cvsTranable.interface' -const test = anyTest as TestInterface<{cvsTran: CvsTranable}>; +const CvsTranable = WithCvsTranable(Client) +let cvsTran: any -test.beforeEach((t) => { - const cvsTran = new CvsTranable() +test.beforeEach(() => { + cvsTran = new CvsTranable() cvsTran.client = Axios.create({}) - t.context.cvsTran = cvsTran }) test('.entryTranCvs calls API and returns response', async (t) => { - t.context.cvsTran.options = { + cvsTran.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'AccessID=accessid&AccessPass=accesspass', @@ -38,7 +39,7 @@ test('.entryTranCvs calls API and returns response', async (t) => { Amount: 1234, Tax: 123 } - const res = await t.context.cvsTran.entryTranCvs(args) + const res = await cvsTran.entryTranCvs(args) const expect: IEntryTranCvsResult = { AccessID: 'accessid', @@ -48,7 +49,7 @@ test('.entryTranCvs calls API and returns response', async (t) => { }) test('.execTranCvs calls API and returns response', async (t) => { - t.context.cvsTran.options = { + cvsTran.config.axios = { adapter: async (config: AxiosRequestConfig) => { const text = [ 'OrderID=orderid', @@ -86,7 +87,7 @@ test('.execTranCvs calls API and returns response', async (t) => { ReceiptsDisp12: '09011112222', ReceiptsDisp13: '10:00-19:00' } - const res = await t.context.cvsTran.execTranCvs(args) + const res = await cvsTran.execTranCvs(args) const expect: IExecTranCvsResult = { OrderID: 'orderid', @@ -104,7 +105,7 @@ test('.execTranCvs calls API and returns response', async (t) => { }) test('.cancelCvs calls API and returns response', async (t) => { - t.context.cvsTran.options = { + cvsTran.config.axios = { adapter: async (config: AxiosRequestConfig) => { const text = [ 'OrderID=orderid', @@ -129,7 +130,7 @@ test('.cancelCvs calls API and returns response', async (t) => { AccessPass: 'accesspass', OrderID: 'orderid' } - const res = await t.context.cvsTran.cancelCvs(args) + const res = await cvsTran.cancelCvs(args) const expect: ICancelCvsResult = { OrderID: 'orderid', diff --git a/src/client/cvsTranable.ts b/src/client/cvsTranable.ts index c377b32..6068a8a 100644 --- a/src/client/cvsTranable.ts +++ b/src/client/cvsTranable.ts @@ -1,8 +1,7 @@ -import {AxiosInstance} from 'axios' import * as encoding from 'encoding-japanese' import * as merge from 'deepmerge' import Client from '../client' -import {IConfig} from '../config.interface' +import {Constructor} from '../util' import { ICancelCvsArgs, ICancelCvsResult, @@ -12,16 +11,11 @@ import { IExecTranCvsResult } from './cvsTranable.interface' -export default class CvsTranable extends Client { - public name: string = 'CvsTranable' - public config: IConfig - public client: AxiosInstance - public options: object = {} - +export default >(Base: T) => class extends Base { public async entryTranCvs(args: IEntryTranCvsArgs): Promise { const defaultData = { - ShopID: this.config !== undefined ? this.config.ShopID : undefined, - ShopPass: this.config !== undefined ? this.config.ShopPass : undefined, + ShopID: this.config.ShopID, + ShopPass: this.config.ShopPass, OrderID: undefined, Amount: undefined, Tax: undefined @@ -29,7 +23,7 @@ export default class CvsTranable extends Client { const data: IEntryTranCvsArgs = merge(defaultData, args) const parsed: any = await this.post('/payment/EntryTranCvs.idPass', data) - return parsed + return parsed } public async execTranCvs(args: IExecTranCvsArgs): Promise { @@ -39,7 +33,7 @@ export default class CvsTranable extends Client { CustomerKana: encoding.urlEncode(encoding.convert(args.CustomerKana, 'SJIS')) }) - return parsed + return parsed } public async cancelCvs(args: ICancelCvsArgs): Promise { diff --git a/src/client/memberable.test.ts b/src/client/memberable.test.ts index f1d0405..012c455 100644 --- a/src/client/memberable.test.ts +++ b/src/client/memberable.test.ts @@ -1,6 +1,7 @@ -import anyTest, {TestInterface} from 'ava' +import test from 'ava' import Axios, {AxiosRequestConfig, AxiosResponse} from 'axios' -import Memberable from './memberable' +import Client from '../client' +import WithMemberable from './memberable' import { IDeleteMemberResult, ISaveMemberResult, @@ -8,20 +9,16 @@ import { IUpdateMemberResult } from './memberable.interface' -interface Context { - member: Memberable -} +const Memberable = WithMemberable(Client) +let member: any -const test = anyTest as TestInterface; - -test.beforeEach((t) => { - const member = new Memberable() +test.beforeEach(() => { + member = new Memberable() member.client = Axios.create({}) - t.context.member = member }) test('.defaultMemberData returns default object', async (t) => { - const res = await t.context.member.defaultMemberData() + const res = await member.defaultMemberData() const expect = { SiteID: undefined, SitePass: undefined, @@ -31,7 +28,7 @@ test('.defaultMemberData returns default object', async (t) => { }) test('.saveMember calls API and returns response', async (t) => { - t.context.member.options = { + member.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'MemberID=memberid', @@ -51,7 +48,7 @@ test('.saveMember calls API and returns response', async (t) => { MemberID: 'memberid', MemberName: 'membername' } - const res = await t.context.member.saveMember(args) + const res = await member.saveMember(args) const expect: ISaveMemberResult = { MemberID: 'memberid' @@ -60,7 +57,7 @@ test('.saveMember calls API and returns response', async (t) => { }) test('.updateMember calls API and returns response', async (t) => { - t.context.member.options = { + member.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'MemberID=memberid', @@ -80,7 +77,7 @@ test('.updateMember calls API and returns response', async (t) => { MemberID: 'memberid', MemberName: 'membername' } - const res = await t.context.member.updateMember(args) + const res = await member.updateMember(args) const expect: IUpdateMemberResult = { MemberID: 'memberid' @@ -89,7 +86,7 @@ test('.updateMember calls API and returns response', async (t) => { }) test('.deleteMember calls API and returns response', async (t) => { - t.context.member.options = { + member.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'MemberID=memberid', @@ -108,7 +105,7 @@ test('.deleteMember calls API and returns response', async (t) => { SitePass: 'sitepass', MemberID: 'memberid' } - const res = await t.context.member.deleteMember(args) + const res = await member.deleteMember(args) const expect: IDeleteMemberResult = { MemberID: 'memberid' @@ -117,7 +114,7 @@ test('.deleteMember calls API and returns response', async (t) => { }) test('.searchMember calls API and returns response', async (t) => { - t.context.member.options = { + member.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'MemberID=memberid&MemberName=membername&DeleteFlag=1', @@ -136,7 +133,7 @@ test('.searchMember calls API and returns response', async (t) => { SitePass: 'sitepass', MemberID: 'memberid' } - const res = await t.context.member.searchMember(args) + const res = await member.searchMember(args) const expect: ISearchMemberResult = { MemberID: 'memberid', @@ -147,5 +144,5 @@ test('.searchMember calls API and returns response', async (t) => { }) test('.post is function', (t) => { - t.is(typeof t.context.member.post, 'function') + t.is(typeof member.post, 'function') }) diff --git a/src/client/memberable.ts b/src/client/memberable.ts index 0b25cd4..491abff 100644 --- a/src/client/memberable.ts +++ b/src/client/memberable.ts @@ -1,7 +1,6 @@ -import {AxiosInstance} from 'axios' import * as merge from 'deepmerge' import Client from '../client' -import {IConfig} from '../config.interface' +import {Constructor} from '../util' import { IDeleteMemberArgs, IDeleteMemberResult, @@ -13,24 +12,13 @@ import { IUpdateMemberResult } from './memberable.interface' -export default class Memberable extends Client { - public name: string = 'Memberable' - public config: IConfig - public client: AxiosInstance - public options: object = {} - +export default >(Base: T) => class extends Base { public defaultMemberData(): any { - let siteID - let sitePass - - if (this.config !== undefined) { - siteID = this.config.SiteID - sitePass = this.config.SitePass - } + const {SiteID, SitePass} = this.config return { - SiteID: siteID, - SitePass: sitePass, + SiteID, + SitePass, MemberID: undefined } } @@ -39,27 +27,27 @@ export default class Memberable extends Client { const data: ISaveMemberArgs = merge(this.defaultMemberData(), args) const parsed: any = await this.post('/payment/SaveMember.idPass', data) - return parsed + return parsed } public async updateMember(args: IUpdateMemberArgs): Promise { const data: IUpdateMemberArgs = merge(this.defaultMemberData(), args) const parsed: any = await this.post('/payment/UpdateMember.idPass', data) - return parsed + return parsed } public async deleteMember(args: IDeleteMemberArgs): Promise { const data: IDeleteMemberArgs = merge(this.defaultMemberData(), args) const parsed: any = await this.post('/payment/DeleteMember.idPass', data) - return parsed + return parsed } public async searchMember(args: ISearchMemberArgs): Promise { const data: ISearchMemberArgs = merge(this.defaultMemberData(), args) const parsed: any = await this.post('/payment/SearchMember.idPass', data) - return parsed + return parsed } } diff --git a/src/client/multiTranable.test.ts b/src/client/multiTranable.test.ts index f08b316..6e66fb1 100644 --- a/src/client/multiTranable.test.ts +++ b/src/client/multiTranable.test.ts @@ -1,22 +1,23 @@ -import anyTest, {TestInterface} from 'ava' +import test from 'ava' import Axios, {AxiosRequestConfig, AxiosResponse} from 'axios' import {CvsCode, PayType, Status, Method, JobCd} from '../client.enum' -import MultiTranable from './multiTranable' +import Client from '../client' +import WithMultiTranable from './multiTranable' import { ISearchTradeMultiCardResult, ISearchTradeMultiCvsResult } from './multiTranable.interface' -const test = anyTest as TestInterface<{multiTran: MultiTranable}>; +const MultiTranable = WithMultiTranable(Client) +let multiTran: any -test.beforeEach((t) => { - const multiTran = new MultiTranable() +test.beforeEach(() => { + multiTran = new MultiTranable() multiTran.client = Axios.create({}) - t.context.multiTran = multiTran }) test('.searchTradeMulti calls API and returns response - CVS', async (t) => { - t.context.multiTran.options = { + multiTran.config.axios = { adapter: async (config: AxiosRequestConfig) => { const text = [ `Status=${Status.Reqsuccess}`, @@ -53,7 +54,7 @@ test('.searchTradeMulti calls API and returns response - CVS', async (t) => { OrderID: 'orderid', PayType: PayType.Cvs } - const res = await t.context.multiTran.searchTradeMulti(args) + const res = await multiTran.searchTradeMulti(args) const expect: ISearchTradeMultiCvsResult = { Status: Status.Reqsuccess, @@ -76,7 +77,7 @@ test('.searchTradeMulti calls API and returns response - CVS', async (t) => { }) test('.searchTradeMulti calls API and returns response - Credit', async (t) => { - t.context.multiTran.options = { + multiTran.config.axios = { adapter: async (config: AxiosRequestConfig) => { const text = [ `Status=${Status.Capture}`, @@ -119,7 +120,7 @@ test('.searchTradeMulti calls API and returns response - Credit', async (t) => { OrderID: 'orderid', PayType: PayType.Credit } - const res = await t.context.multiTran.searchTradeMulti(args) + const res = await multiTran.searchTradeMulti(args) const expect: ISearchTradeMultiCardResult = { Status: Status.Capture, diff --git a/src/client/multiTranable.ts b/src/client/multiTranable.ts index 1ddfd80..8a94458 100644 --- a/src/client/multiTranable.ts +++ b/src/client/multiTranable.ts @@ -1,31 +1,25 @@ -import {AxiosInstance} from 'axios' import * as merge from 'deepmerge' import Client from '../client' -import {IConfig} from '../config.interface' +import {Constructor} from '../util' import { ISearchTradeMultiArgs, ISearchTradeMultiCardResult, ISearchTradeMultiCvsResult } from './multiTranable.interface' -export default class MultiTranable extends Client { - public name: string = 'MultiTranable' - public config: IConfig - public client: AxiosInstance - public options: object = {} - +export default >(Base: T) => class extends Base { public async searchTradeMulti (args: ISearchTradeMultiArgs): Promise { const defaultData = { - ShopID: this.config !== undefined ? this.config.ShopID : undefined, - ShopPass: this.config !== undefined ? this.config.ShopPass : undefined, + ShopID: this.config.ShopID, + ShopPass: this.config.ShopPass, OrderID: undefined, PayType: undefined } const data: ISearchTradeMultiArgs = merge(defaultData, args) const parsed: any = await this.post('/payment/SearchTradeMulti.idPass', data) - return parsed + return parsed } } diff --git a/src/client/tranable.test.ts b/src/client/tranable.test.ts index 8d7745b..749dccd 100644 --- a/src/client/tranable.test.ts +++ b/src/client/tranable.test.ts @@ -1,7 +1,8 @@ -import anyTest, {TestInterface} from 'ava' +import test from 'ava' import Axios, {AxiosRequestConfig, AxiosResponse} from 'axios' import {JobCd, Method, Status} from '../client.enum' -import Tranable from './tranable' +import Client from '../client' +import WithTranable from './tranable' import { IAlterTranResult, IChangeTranResult, @@ -10,20 +11,16 @@ import { ISearchTradeResult } from './tranable.interface' -interface Context { - tran: Tranable -} +const Tranable = WithTranable(Client) +let tran: any -const test = anyTest as TestInterface; - -test.beforeEach((t) => { - const tran = new Tranable() +test.beforeEach(() => { + tran = new Tranable() tran.client = Axios.create({}) - t.context.tran = tran }) test('.entryTran calls API and returns response', async (t) => { - t.context.tran.options = { + tran.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'AccessID=accessid&AccessPass=accesspass', @@ -47,7 +44,7 @@ test('.entryTran calls API and returns response', async (t) => { JobCd: JobCd.Check, Amount: 1234 } - const res = await t.context.tran.entryTran(args) + const res = await tran.entryTran(args) const expect: IEntryTranResult = { AccessID: 'accessid', @@ -57,7 +54,7 @@ test('.entryTran calls API and returns response', async (t) => { }) test('.execTran calls API and returns response', async (t) => { - t.context.tran.options = { + tran.config.axios = { adapter: async (config: AxiosRequestConfig) => { const text = [ 'Acs=acs', @@ -95,7 +92,7 @@ test('.execTran calls API and returns response', async (t) => { Expire: 'expire', SecurityCode: '123' } - const res = await t.context.tran.execTran(args) + const res = await tran.execTran(args) const expect: IExecTranResult = { Acs: 'acs', @@ -115,7 +112,7 @@ test('.execTran calls API and returns response', async (t) => { }) test('.alterTran calls API and returns response', async (t) => { - t.context.tran.options = { + tran.config.axios = { adapter: async (config: AxiosRequestConfig) => { const response: AxiosResponse = { data: 'AccessID=accessid&AccessPass=accesspass&Forward=forward&Approve=approve&TranID=tranid&TranDate=trandate', @@ -136,7 +133,7 @@ test('.alterTran calls API and returns response', async (t) => { AccessPass: 'accesspass', JobCd: JobCd.Check } - const res = await t.context.tran.alterTran(args) + const res = await tran.alterTran(args) const expect: IAlterTranResult = { AccessID: 'accessid', @@ -150,7 +147,7 @@ test('.alterTran calls API and returns response', async (t) => { }) test('.searchTrade calls API and returns response', async (t) => { - t.context.tran.options = { + tran.config.axios = { adapter: async (config: AxiosRequestConfig) => { const text = [ 'OrderID=orderid', @@ -192,7 +189,7 @@ test('.searchTrade calls API and returns response', async (t) => { ShopPass: 'shoppass', OrderID: 'orderid' } - const res = await t.context.tran.searchTrade(args) + const res = await tran.searchTrade(args) const expect: ISearchTradeResult = { OrderID: 'orderid', @@ -221,7 +218,7 @@ test('.searchTrade calls API and returns response', async (t) => { }) test('.changeTran calls API and returns response', async (t) => { - t.context.tran.options = { + tran.config.axios = { adapter: async (config: AxiosRequestConfig) => { const text = [ 'AccessID=accessid', @@ -251,7 +248,7 @@ test('.changeTran calls API and returns response', async (t) => { JobCd: JobCd.Check, Amount: 1234 } - const res = await t.context.tran.changeTran(args) + const res = await tran.changeTran(args) const expect: IChangeTranResult = { AccessID: 'accessid', diff --git a/src/client/tranable.ts b/src/client/tranable.ts index 6228918..6f0269e 100644 --- a/src/client/tranable.ts +++ b/src/client/tranable.ts @@ -1,7 +1,6 @@ -import {AxiosInstance} from 'axios' import * as merge from 'deepmerge' import Client from '../client' -import {IConfig} from '../config.interface' +import {Constructor} from '../util' import { IAlterTranArgs, IAlterTranResult, @@ -15,16 +14,11 @@ import { ISearchTradeResult } from './tranable.interface' -export default class Tranable extends Client { - public name: string = 'Tranable' - public config: IConfig - public client: AxiosInstance - public options: object = {} - +export default >(Base: T) => class extends Base { public async entryTran(args: IEntryTranArgs): Promise { const defaultData = { - ShopID: this.config !== undefined ? this.config.ShopID : undefined, - ShopPass: this.config !== undefined ? this.config.ShopPass : undefined, + ShopID: this.config.ShopID, + ShopPass: this.config.ShopPass, OrderID: undefined, JobCd: undefined, Amount: undefined @@ -32,19 +26,19 @@ export default class Tranable extends Client { const data: IEntryTranArgs = merge(defaultData, args) const parsed: any = await this.post('/payment/EntryTran.idPass', data) - return parsed + return parsed } public async execTran(args: IExecTranArgs): Promise { const parsed: any = await this.post('/payment/ExecTran.idPass', args) - return parsed + return parsed } public async alterTran(args: IAlterTranArgs): Promise { - const defaultData = { - ShopID: this.config !== undefined ? this.config.ShopID : undefined, - ShopPass: this.config !== undefined ? this.config.ShopPass : undefined, + const defaultData = { + ShopID: this.config.ShopID, + ShopPass: this.config.ShopPass, AccessID: undefined, AccessPass: undefined, JobCd: undefined @@ -52,25 +46,25 @@ export default class Tranable extends Client { const data: IAlterTranArgs = merge(defaultData, args) const parsed: any = await this.post('/payment/AlterTran.idPass', data) - return parsed + return parsed } public async searchTrade(args: ISearchTradeArgs): Promise { const defaultData = { - ShopID: this.config !== undefined ? this.config.ShopID : undefined, - ShopPass: this.config !== undefined ? this.config.ShopPass : undefined, + ShopID: this.config.ShopID, + ShopPass: this.config.ShopPass, OrderID: undefined } const data: ISearchTradeArgs = merge(defaultData, args) const parsed: any = await this.post('/payment/SearchTrade.idPass', data) - return parsed + return parsed } public async changeTran(args: IChangeTranArgs): Promise { const defaultData = { - ShopID: this.config !== undefined ? this.config.ShopID : undefined, - ShopPass: this.config !== undefined ? this.config.ShopPass : undefined, + ShopID: this.config.ShopID, + ShopPass: this.config.ShopPass, AccessID: undefined, AccessPass: undefined, JobCd: undefined, @@ -79,6 +73,6 @@ export default class Tranable extends Client { const data: IChangeTranArgs = merge(defaultData, args) const parsed: any = await this.post('/payment/ChangeTran.idPass', data) - return parsed + return parsed } } diff --git a/src/gmopg.test.ts b/src/gmopg.test.ts index e27e525..7243e59 100644 --- a/src/gmopg.test.ts +++ b/src/gmopg.test.ts @@ -1,14 +1,10 @@ -import anyTest, {TestInterface} from 'ava' -import GMOPG from './gmopg' +import test from 'ava' +import GMOPG, {ENUMS, GENERATE_MEMBER_ID} from './gmopg' -interface Context { - gmopg: GMOPG -} +let gmopg: any -const test = anyTest as TestInterface; - -test.beforeEach((t) => { - t.context.gmopg = new GMOPG() +test.beforeEach(() => { + gmopg = new GMOPG() }) test('constructor.name returns Object', (t) => { @@ -16,11 +12,11 @@ test('constructor.name returns Object', (t) => { }) test('new returns GMOPG instance', (t) => { - t.true(t.context.gmopg instanceof GMOPG) + t.true(gmopg instanceof GMOPG) }) test('.ENUMS returns enum object', (t) => { - t.deepEqual(Object.keys(GMOPG.ENUMS), [ + t.deepEqual(Object.keys(ENUMS), [ 'PayType', 'Method', 'Status', @@ -31,18 +27,13 @@ test('.ENUMS returns enum object', (t) => { ]) }) -test('.CREATE returns new GMOPG instance', (t) => { - const instance = GMOPG.CREATE() - t.true(instance instanceof GMOPG) -}) - test('.GENERATE_MEMBER_ID returns generated memberID', (t) => { - const ID = GMOPG.GENERATE_MEMBER_ID('key') + const ID = GENERATE_MEMBER_ID('key') t.regex(ID, /^key-\w{32}$/) }) test('.GENERATE_MEMBER_ID returns max 60 chars', (t) => { - const ID = GMOPG.GENERATE_MEMBER_ID('0123456789-0123456789-0123456789-0123456789') + const ID = GENERATE_MEMBER_ID('0123456789-0123456789-0123456789-0123456789') t.regex(ID, /^.{60}$/) }) @@ -56,77 +47,77 @@ test('.config returns IConfig', (t) => { } } } - t.deepEqual(t.context.gmopg.config, expect) + t.deepEqual(gmopg.config, expect) }) test('.client returns AxiosInstance', (t) => { - t.is(typeof t.context.gmopg.client, 'function') + t.is(typeof gmopg.client, 'function') }) test('.saveMember is function', (t) => { - t.is(typeof t.context.gmopg.saveMember, 'function') + t.is(typeof gmopg.saveMember, 'function') }) test('.updateMember is function', (t) => { - t.is(typeof t.context.gmopg.updateMember, 'function') + t.is(typeof gmopg.updateMember, 'function') }) test('.deleteMember is function', (t) => { - t.is(typeof t.context.gmopg.deleteMember, 'function') + t.is(typeof gmopg.deleteMember, 'function') }) test('.searchMember is function', (t) => { - t.is(typeof t.context.gmopg.searchMember, 'function') + t.is(typeof gmopg.searchMember, 'function') }) test('.saveCard is function', (t) => { - t.is(typeof t.context.gmopg.saveCard, 'function') + t.is(typeof gmopg.saveCard, 'function') }) test('.deleteCard is function', (t) => { - t.is(typeof t.context.gmopg.deleteCard, 'function') + t.is(typeof gmopg.deleteCard, 'function') }) test('.searchCard is function', (t) => { - t.is(typeof t.context.gmopg.searchCard, 'function') + t.is(typeof gmopg.searchCard, 'function') }) test('.entryTran is function', (t) => { - t.is(typeof t.context.gmopg.entryTran, 'function') + t.is(typeof gmopg.entryTran, 'function') }) test('.execTran is function', (t) => { - t.is(typeof t.context.gmopg.execTran, 'function') + t.is(typeof gmopg.execTran, 'function') }) test('.alterTran is function', (t) => { - t.is(typeof t.context.gmopg.alterTran, 'function') + t.is(typeof gmopg.alterTran, 'function') }) test('.searchTrade is function', (t) => { - t.is(typeof t.context.gmopg.searchTrade, 'function') + t.is(typeof gmopg.searchTrade, 'function') }) test('.changeTran is function', (t) => { - t.is(typeof t.context.gmopg.changeTran, 'function') + t.is(typeof gmopg.changeTran, 'function') }) test('.entryTranCvs is function', (t) => { - t.is(typeof t.context.gmopg.entryTranCvs, 'function') + t.is(typeof gmopg.entryTranCvs, 'function') }) test('.execTranCvs is function', (t) => { - t.is(typeof t.context.gmopg.execTranCvs, 'function') + t.is(typeof gmopg.execTranCvs, 'function') }) test('.cancelCvs is function', (t) => { - t.is(typeof t.context.gmopg.cancelCvs, 'function') + t.is(typeof gmopg.cancelCvs, 'function') }) test('.searchTradeMulti is function', (t) => { - t.is(typeof t.context.gmopg.searchTradeMulti, 'function') + t.is(typeof gmopg.searchTradeMulti, 'function') }) test('.post is function', (t) => { - t.is(typeof t.context.gmopg.post, 'function') + t.is(typeof gmopg.post, 'function') }) diff --git a/src/gmopg.ts b/src/gmopg.ts index 274b6ba..d0676b4 100644 --- a/src/gmopg.ts +++ b/src/gmopg.ts @@ -1,122 +1,19 @@ -import Axios, {AxiosInstance} from 'axios' -import * as merge from 'deepmerge' import * as enums from './client.enum' -import Memberable from './client/memberable' -import Cardable from './client/cardable' -import Tranable from './client/tranable' -import CvsTranable from './client/cvsTranable' -import MultiTranable from './client/multiTranable' -import {buildByEnv, defaults} from './config' -import {applyMixins, generateID} from './util' -import {IConfig} from './config.interface' -import { - IDeleteMemberArgs, - IDeleteMemberResult, - ISaveMemberArgs, - ISaveMemberResult, - ISearchMemberArgs, - ISearchMemberResult, - IUpdateMemberArgs, - IUpdateMemberResult -} from './client/memberable.interface' -import { - IDeleteCardArgs, - IDeleteCardResult, - ISaveCardArgs, - ISaveCardResult, - ISearchCardArgs, - ISearchCardResult -} from './client/cardable.interface' -import { - IAlterTranArgs, - IAlterTranResult, - IChangeTranArgs, - IChangeTranResult, - IEntryTranArgs, - IEntryTranResult, - IExecTranArgs, - IExecTranResult, - ISearchTradeArgs, - ISearchTradeResult -} from './client/tranable.interface' -import { - ICancelCvsArgs, - ICancelCvsResult, - IEntryTranCvsArgs, - IEntryTranCvsResult, - IExecTranCvsArgs, - IExecTranCvsResult -} from './client/cvsTranable.interface' -import { - ISearchTradeMultiArgs, - ISearchTradeMultiCardResult, - ISearchTradeMultiCvsResult -} from './client/multiTranable.interface' - -export class GMOPG implements Memberable, Cardable, Tranable, CvsTranable, MultiTranable { - public name: string = 'GMOPG' - public client: AxiosInstance - public options: object - public config: IConfig - - // client - public post: (endpoint: string, data: any) => Promise - public isError: (res: any) => boolean - - // memberable - public defaultMemberData: () => any - public saveMember: (args: ISaveMemberArgs) => Promise - public updateMember: (args: IUpdateMemberArgs) => Promise - public deleteMember: (args: IDeleteMemberArgs) => Promise - public searchMember: (args: ISearchMemberArgs) => Promise - - // cardable - public defaultCardData: () => any - public saveCard: (args: ISaveCardArgs) => Promise - public deleteCard: (args: IDeleteCardArgs) => Promise - public searchCard: (args: ISearchCardArgs) => Promise - - // tranable - public entryTran: (args: IEntryTranArgs) => Promise - public execTran: (args: IExecTranArgs) => Promise - public alterTran: (args: IAlterTranArgs) => Promise - public searchTrade: (args: ISearchTradeArgs) => Promise - public changeTran: (args: IChangeTranArgs) => Promise - - // tranable - cvs - public entryTranCvs: (args: IEntryTranCvsArgs) => Promise - public execTranCvs: (args: IExecTranCvsArgs) => Promise - public cancelCvs: (args: ICancelCvsArgs) => Promise - - // tranable - multi - public searchTradeMulti: (args: ISearchTradeMultiArgs) => Promise - - constructor(config?: IConfig) { - if (config === undefined) { - config = {} - } - this.config = merge(defaults, config) - const configByEnv: IConfig = buildByEnv() - if (configByEnv !== {}) { - this.config = merge(this.config, configByEnv) - } - this.client = Axios.create(this.config.axios) - } - - public static CREATE(config?: IConfig): GMOPG { - return new GMOPG(config) - } - - public static GENERATE_MEMBER_ID(key: string): string { - return generateID(key).substring(0, 60) - } - - public static get ENUMS() { - return enums - } +import WithMemberable from './client/memberable' +import WithCardable from './client/cardable' +import WithTranable from './client/tranable' +import WithCvsTranable from './client/cvsTranable' +import WithMultiTranable from './client/multiTranable' +import {generateID} from './util' +import Client from './client' + +export default WithCardable(WithCvsTranable(WithMemberable(WithMultiTranable(WithTranable(Client))))) + +export function GENERATE_MEMBER_ID(key: string): string { + return generateID(key).substring(0, 60) } -applyMixins(GMOPG, [Memberable, Cardable, Tranable, CvsTranable, MultiTranable]) +export {enums as ENUMS} export * from './config.interface' export * from './client.interface' @@ -126,4 +23,3 @@ export * from './client/cardable.interface' export * from './client/tranable.interface' export * from './client/cvsTranable.interface' export * from './client/multiTranable.interface' -export default GMOPG diff --git a/src/util.test.ts b/src/util.test.ts index 071fa6a..5c85385 100644 --- a/src/util.test.ts +++ b/src/util.test.ts @@ -1,40 +1,8 @@ import test from 'ava' import * as Util from './util' -class Brand { - public sign() { - } -} - -class Tire extends Brand { - public rollTire() { - } -} - -class Engine extends Brand { - public startEngine() { - } -} - -class Car implements Tire, Engine { - public sign: () => void - public rollTire: () => void - public startEngine: () => void -} - -Util.applyMixins(Car, [Tire, Engine]) - -test('.applyMixins mixes other methods', (t) => { - const car = new Car() - t.is(typeof car.rollTire, 'function') - t.is(typeof car.startEngine, 'function') -}) - -test('.applyMixins mixes prototype chain method', (t) => { - const car = new Car() - t.is(typeof car.sign, 'function') -}) - test('.generateID returns key with hash', (t) => { t.regex(Util.generateID('foo'), /foo-\w{32}/) }) + + diff --git a/src/util.ts b/src/util.ts index 0c7fad3..2ed1c4a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,20 +1,7 @@ import {createHash} from 'crypto' -export function applyMixins(derivedCtor: any, baseCtors: any[]) { - baseCtors.forEach((baseCtor) => { - Object.getOwnPropertyNames(baseCtor.prototype.__proto__).forEach((name) => { - if (name !== 'constructor') { - derivedCtor.prototype[name] = baseCtor.prototype[name] - } - }) - Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => { - if (name !== 'constructor') { - derivedCtor.prototype[name] = baseCtor.prototype[name] - } - }) - }) -} - export function generateID(key: string): string { return `${key}-${createHash('md5').update(`${key}-${new Date().toISOString()}`).digest('hex')}` } + +export type Constructor = new (...args: any[]) => T; diff --git a/tslint.json b/tslint.json index 2a1cd5c..e5ce4c6 100644 --- a/tslint.json +++ b/tslint.json @@ -40,7 +40,8 @@ "parameter", "property-declaration", "member-variable-declaration" - ] + ], + "variable-name": [true, "allow-pascal-case"] }, "linterOptions": { "exclude": [