# YY EFOX pay

## 安装

``` sh
yarn add @efox/pay 
```

or 

``` sh
npm i @efox/pay
```

## 快速接入 AsiaBill

* 复制以下demo代码到你的项目
* 传入需要的参数到 fieldData

#### import 方式接入demo

``` javascript
import sdk from '@efox/pay'
const fieldData = {
    merNo: '99999',
    gatewayNo: '99999001',
    orderNo: '123456789',
    orderCurrency: 'EUR',
    orderAmount: '98',
    signInfo: '4B8FA15BBCA0A22F3FDB',
    returnUrl: 'http://bai.com/result.php',
    firstName: 'Eva',
    lastName: 'Tan',
    email: 'est@Asiabill.com',
    phone: '075525846758',
    paymentMethod: 'Credit Card',
    country: 'US',
    state: 'Tennessee',
    city: 'Collierville',
    address: '110 North Tree Drive',
    zip: '38017'
}
const initialData = {
    env: 'prod',
    sdkName: 'asiaBill',
    fieldData: fieldData,
    reportSDKLoading: (reportSDKLoadingParams) => {
        console.log('sdk加载时间', reportSDKLoadingParams)
    },
}
const pay = new sdk(publicKey, initialData)
//提交到 AsiaBill，如果数据校验失败，submit() 会返回对应错误码与错误信息
const state = pay.getToken()
```

#### CDN方式接入demo

``` html
<script src="https://pushmiddle.bs2dl.yy.com/pay/1.0.47/index.js"></script>
<script>
    const fieldData = {
        merNo: '99999',
        gatewayNo: '99999001',
        orderNo: '123456789',
        orderCurrency: 'EUR',
        orderAmount: '98',
        signInfo: '4B8FA15BBCA0A22F3FDB',
        returnUrl: 'http://bai.com/result.php',
        firstName: 'Eva',
        lastName: 'Tan',
        email: 'est@Asiabill.com',
        phone: '075525846758',
        paymentMethod: 'Credit Card',
        country: 'US',
        state: 'Tennessee',
        city: 'Collierville',
        address: '110 North Tree Drive',
        zip: '38017'
    }
    const initialData = {
        env: 'prod',
        sdkName: 'asiaBill',
        fieldData: fieldData,
        reportSDKLoading: (reportSDKLoadingParams) => {
            console.log('sdk加载时间', reportSDKLoadingParams)
        },
    }
    const pay = new efoxPay.default(publicKey, initialData)
    //提交到 AsiaBill，如果数据校验失败，submit() 会返回对应错误码与错误信息
    const state = pay.getToken()
</script>
```

| 字段  | 含义(字段的 value 均为 String 类型) |
| :--: | :--: |
|merNo |	【商户号】
|gatewayNo|【网关接入号】
|orderNo|【商户订单号】 在该订单号是成功/待处理/待确认的状态下, 不允许再次抛送此订单号。
|orderCurrency|【交易币种】详见【附录】交易币种(ISO 4217)https://www.asiabill.com/developers/347-cn.html#currency
|orderAmount|【交易金额】应为小数点后2位小数。
|firstName|【客人的名】 长度必须在2-100之间。否则不能交易。
|lastName|【客人的姓】 长度必须在2-50之间。否则不能交易。
|email|【客人的邮件】 长度必须在2-200之间。否则不能交易。
|phone|	【客人的联系电话】 长度必须在2-50之间。否则不能交易。
|paymentMethod|【支付方式】 目前只有 Credit Card
|shipFirstName|【收件人的名】
|shipLastName|【收件人的姓】
|shipPhone|【收件人的联系电话】
|shipCountry|【收件人的国家】
|shipState|【收件人的州】
|shipCity|【收件人的城市】
|shipAddress|【收件人的地址】
|shipZip|【收件人的邮编】
|returnUrl|【交易返回地址】Asiabill处理完请求后，自动跳转到请求参数中的returnUrl地址。
|callbackUrl|【后台通知地址】当传了此值则异步通知使用该URL通知
|remark|【备注】可作为扩展信息，提交什么就返回什么。

## 快速接入 PaypalSPB

* 复制以下demo代码到你的项目
* 修改 publicKey.key 为你的 PaypalSPB 的 CLIENT_ID
* 修改 domId 为你指定的 dom 节点
* 启动项目就可以看到出现SDK按钮
* 点击 `SDK按钮` 时回调 `createOrder` ，您可通过下单获取order_id并return返回来打开支付页面
* 点击 `SDK确认付款按钮` 时回调 `createToken` ，您可通过此事件做用户确认支付后你需要的操作

#### 参数解析

| 字段 | 含义 |
| :--: | :--: |
| PublicKey | 初始化sdk的object对象 |
| PublicKey.key | 初始化paypalSPB的 `CLIENT_ID` |
| PublicKey.expand.currency | 初始化paypalSPB的货币码 |
| initialData | 初始化sdk的基础数据 |
| initialData.env | 当前环境 用于个别SDK加载脚本环境区分，值为：'prod' 或 'dev' |
| initialData.sdkName | sdk名字，'paypalSPB' |
| initialData.domId | 需要渲染的dom id |
| initialData.createOrder | 点击 `SDK按钮` 时回调 `createOrder` ，您可通过下单获取order_id并return返回来打开支付页面 |
| initialData.createToken | 点击 `SDK确认付款按钮` 时回调 `createToken` ，您可通过此事件做用户确认支付后你需要的操作 |
| initialData.reportSDKLoading | SDK加载时间 |
| initialData.styleOption | SDK样式 |
| initialData.commonStyle.paypalSPBStyle.layout | 布局方式，值为 'vertical' 或 'horizontal' |
| initialData.commonStyle.paypalSPBStyle.color | 按钮颜色，值为 'gold' 或 'blue' 或 'silver' 或 'white' 或 'black' |
| initialData.commonStyle.paypalSPBStyle.shape | 按钮形状，值为 'rect' 或 'pill' |
| initialData.commonStyle.paypalSPBStyle.label | 按钮文本，值为 'paypal' 或 'checkout' 或 'buynow' 或 'pay' 或 'installment' |
| initialData.commonStyle.paypalSPBStyle.height | set the style.height option to a value from 25 to 55. 建议使用默认 |
| initialData.commonStyle.paypalSPBStyle.tagline | 禁用标语文字，当 `layout` 为 `horizontal` 才能设置为 `true` |

#### Typescirpt接入demo

``` javascript
import sdk, {
    InitialData,
    PublicKey,
    ReportSDKLoadingParams
} from '@efox/pay'

const publicKey: PublicKey = {
    key: 'AUY6Budt21Ebh5ZSHgaKVTflqTj6oicuszaGsr-cBZv-GsQfcdOGIOxLx0mIf-eqx-zP19uBQ2scXshz', // CLIENT_ID
    expand: {
        currency: 'USD', // 货币码, 可不传, 默认USD
    },
}

const initialData: InitialData = {
    env: 'prod',
    sdkName: 'paypalSPB',
    domId: 'paypalSPB_feild', // dom 节点Id
    createOrder: async (response: any) => {
        // 点击 `SDK按钮` 时回调 `createOrder` ，您可通过下单获取order_id并return返回来打开支付页面
        console.log('paypalSPB选择按钮时的回调', response)
        // return payUrl?.chDealId || ''
        return '8FW20256UD7626911' // 返回order_id来启动paypalSPB支付
    },
    createToken: (response: any) => {
        // 点击 `SDK确认付款按钮` 时回调 `createToken` ，您可通过此事件做用户确认支付后你需要的操作
        console.log('SDK确认付款按钮的回调', response)
    },
    reportSDKLoading: (reportSDKLoadingParams: ReportSDKLoadingParams) => {
        console.log('sdk加载时间', reportSDKLoadingParams)
    },
    styleOption: {
        commonStyle: {
            // SDK按钮样式，可不传使用默认样式
            paypalSPBStyle: {
                layout: 'vertical', // 'vertical' | 'horizontal'
                color: 'gold', // 'gold' | 'blue' | 'silver' | 'white' | 'black'
                shape: 'rect', // 'rect' | 'pill'
                label: 'paypal', // 'paypal' | 'checkout' | 'buynow' | 'pay' | 'installment'
                tagline: false,
            },
        },
    },
}
new sdk(publicKey, initialData)
```

#### JavaScript接入demo

``` javascript
import sdk from '@efox/pay'

const publicKey = {
    key: 'AUY6Budt21Ebh5ZSHgaKVTflqTj6oicuszaGsr-cBZv-GsQfcdOGIOxLx0mIf-eqx-zP19uBQ2scXshz', // CLIENT_ID
    expand: {
        currency: 'USD', // 货币码, 可不传, 默认USD
    },
}

const initialData = {
    env: 'prod',
    sdkName: 'paypalSPB',
    domId: 'paypalSPB_feild', // dom 节点Id
    createOrder: async (response) => {
        // 点击 `SDK按钮` 时回调 `createOrder` ，您可通过下单获取order_id并return返回来打开支付页面
        console.log('paypalSPB选择按钮时的回调', response)
        // return payUrl?.chDealId || ''
        return '8FW20256UD7626911' // 返回order_id来启动paypalSPB支付
    },
    createToken: (response) => {
        // 点击 `SDK确认付款按钮` 时回调 `createToken` ，您可通过此事件做用户确认支付后你需要的操作
        console.log('SDK确认付款按钮的回调', response)
    },
    reportSDKLoading: (reportSDKLoadingParams) => {
        console.log('sdk加载时间', reportSDKLoadingParams)
    },
    styleOption: {
        commonStyle: {
            // SDK按钮样式，可不传使用默认样式
            paypalSPBStyle: {
                layout: 'vertical', // 'vertical' | 'horizontal'
                color: 'gold', // 'gold' | 'blue' | 'silver' | 'white' | 'black'
                shape: 'rect', // 'rect' | 'pill'
                label: 'paypal', // 'paypal' | 'checkout' | 'buynow' | 'pay' | 'installment'
                tagline: false,
            },
        },
    },
}
new sdk(publicKey, initialData)
```

#### CDN方式接入demo

``` javascript
< !doctype html >
    <
    html >
    <
    head >
    <
    meta charset = "utf-8" >
    <
    meta content = "width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale-1.0, user-scalable=0"
name = "viewport" >
    <
    title > PaypalSPB Example < /title> < /
head >

    <
    body >
    <
    div id = "paypalSPB_feild" > < /div>

    <
    script src = "https://pushmiddle.bs2dl.yy.com/pay/1.0.41/index.js" > < /script> <
script >
    console.log(efoxPay)

const publicKey = {
    key: 'AUY6Budt21Ebh5ZSHgaKVTflqTj6oicuszaGsr-cBZv-GsQfcdOGIOxLx0mIf-eqx-zP19uBQ2scXshz',
    expand: {
        currency: 'USD',
    },
}

const initialData = {
    env: 'prod',
    sdkName: 'paypalSPB',
    domId: 'paypalSPB_feild',
    createOrder: response => {
        // 点击 `SDK按钮` 时回调 `createOrder` ，您可通过下单获取order_id并return返回来打开支付页面
        console.log('paypalSPB选择按钮时的回调', response)
        // return payUrl?.chDealId || ''
        return '8FW20256UD7626911' // 返回order_id来启动paypalSPB支付
    },
    createToken: response => {
        // 点击 `SDK确认付款按钮` 时回调 `createToken` ，您可通过此事件做用户确认支付后你需要的操作
        console.log('SDK确认付款按钮的回调', response)
    },
    styleOption: {
        commonStyle: {
            // SDK按钮样式，可不传使用默认样式
            paypalSPBStyle: {
                layout: 'vertical',
                color: 'gold',
                shape: 'rect',
                label: 'paypal',
                tagline: false,
            },
        },
    },
}

const pay = new efoxPay.default(publicKey, initialData)
console.log(pay) <
    /script> < /
body >

    <
    /html>
```

## 快速接入2checkout

* 复制以下代码到你的项目
* 修改 publicKey.key 为你的 2checkout MERCHANT_CODE
* 修改 domId 为你指定的 dom 节点
* 启动项目就可以看到出现表单
* 使用 pay.getToken(holderName) 获取 token

#### JavaScript接入demo

``` JavaScript
import sdk from '@efox/pay'

const publicKey = {
    key: 'AVLRNG',
}
const initialData = {
    domId: 'payment',
    sdkName: '2checkout',
    reportSDKLoading: time => {
        console.log(time)
    },
    label: {
        userNameLabel: '持卡人姓名',
    },
    errorTips: {
        userNameErrorTips: '請輸入有效的持卡人姓名'
    },
    styleOption: {
        commonStyle: {},
        componentStyle: {},
    },
    language: 'zy',
}
const pay = new sdk(publicKey, initialData)
const holderName = "持卡人姓名"
const token = pay.getToken(holderName)
console.log(token)
```

#### CDN方式接入demo，以接入 2checkout 为例

``` html
<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>2Checkout Example</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>

<body>
    <div class="container">

        <div class="card mt-3">
            <div class="card-body">
                <div id="payment"></div>
            </div>
        </div>
        <button type="button" id="submit" class="btn btn-success btn-block mt-3 mb-3">提交</button>
    </div>
    <script src="https://unpkg.com/@efox/pay@1.0.23/dist/index.js"></script>
    <script>
        console.log(efoxPay)
        const publicKey = {
            key: 'AVLRNG',
        }
        const initialData = {
            domId: 'payment',
            sdkName: '2checkout',
            // btnText: '提交',
            createToken: token => {
                console.log(token)
            },
            reportSDKLoading: time => {
                console.log(time)
            },
            label: {
                userNameLabel: '持卡人姓名',
            },
            errorTips: {
                userNameErrorTips: '請輸入有效的持卡人姓名'
            },
            styleOption: {
                commonStyle: {},
                componentStyle: {},
            },
            language: 'zy',
        }
        const pay = new efoxPay.default(publicKey, initialData)
        console.log(pay)
    </script>
</body>

</html>
```

## 详细接入，以接入 2checkout 为例

``` js
import sdk from '@efox/pay'

/*
必选参数: publicKey
publicKey 的 key 根据要使用的第三方 SDK 而定:
2checkout, 请为 key 传入 MERCHANT_CODE
*/
const publicKey = {
    key: ''
}

/*
必选参数: InitialData
参数较多，请详细阅读《参数解释》
*/
const initialData: InitialData = {
    //需要渲染的dom id，必选参数。传空值则取body
    domId: '',

    //传入用的第三方 sdk 名,目前支持 2checkout,ebanx
    sdkName: '2checkout',

    /*
    获取token需要提交holderName，以下方法三选一
    1.可以初始化表单数据，传入fieldData.userName
    2.可以通过传入 label.userNameLabel ，启用 SDK 内置的 holderName input,通过 SDK 内置input输入
    3.可以通过使用获取 token 的函数，pay.getToken(holderName),传入参数 holderName
    */

    // 表单初始化默认数据
    fieldData: {
        userName: '持卡人姓名'
    },

    // 开启 Holder name input
    label: {
        userNameLabel: '持卡人姓名',
    },

    // 错误信息
    errorTips: {
        userNameErrorTips: '请输入有效的持卡人姓名'
    },

    // SDK 样式定制
    styleOption: {
        commonStyle: {},
        componentStyle: {},
    },

    /*
    点击SDK自带提交按钮时的 token 的回调函数，可选参数
    */
    createToken: (token: string): void => {
        console.log(token)
    },

    /*
    加载时间的回调函数，可选参数
    */
    reportSDKLoading: (time: number): void => {
        console.log(time)
    }

    // SDK 语种
    language: 'zy',
}

const pay = new sdk(publicKey, initialData)
const holderName = "持卡人姓名"
/* 
获取 token
注意：填全表单信息才能获取token
*/
pay.getToken(holderName)
```

### 注意：

#### 需要开启 持卡人姓名输入栏需要在 initialData 对象内传入 label 参数

例如： 

``` javascript
  label: {
      userNameLabel: '持卡人姓名',
  },
```

#### 需要开启 提交按钮需要在 initialData 对象传入 btnText 参数

``` javascript
btnText: '提交',
```

到这里，应该就可以在您指定的 dom 元素处看到支付界面出现。
如果需要进一步自定义 SDK，则需要阅读以下参数解释

## 参数解释

``` javascript
/*
publicKey 的 key 根据要使用的第三方 SDK 而定:
2checkout, 请为 key 传入 MERCHANT_CODE
*/

export interface PublicKey {
    key: string
    expand ? : Expand
}

export interface Expand {
    currency ? : string
}

/*
初始化 SDK 的参数
*/
export interface InitialData {
    env: 'prod' | 'dev' // 当前环境 用于个别SDK加载脚本环境区分
    sdkName: '2checkout' | 'ebanx' | 'checkout' // sdk名
    domId: string // 需要渲染的dom id
    rewriteCssUrl ? : string // oceanPay css重写地址  必须https
    layoutType ? : 0 // 布局类型
    styleOption ? : StyleOption
    language ? : string // 语言 没传根据sdk按照sdk本身的默认locale
    country ? : string // 国家码 没传根据sdk按照sdk本身的默认country
    label ? : Label // label提示
    placeholder ? : Placeholder // input框提示
    errorTips ? : ErrorTips // 表单错误提示
    btnText ? : string // 按钮文本
    createToken ? : (response: any) => void // 点击按钮获取token回调
    fieldOnChange ? : (fieldParams: FieldParams) => void // 表单填写无效信息时回调
    fieldOnBlur ? : (fieldParams: FieldParams) => void // 表单输入框失焦时回调 // 表单填写无效信息时回调
    fieldComplete ? : (fieldCompleteParams: FieldCompleteParams) => void // 表单填写完成时回调
    reportSDKLoading ? : (reportSDKLoadingParams: ReportSDKLoadingParams) => void // SDK脚本加载时间
    createOrder ? : (response: any) => Promise < string > // paypalSPB选择按钮时的回调
        // todo 暴露各个表单事件
}
```

### 注意： 

    2checkout 语言码（非规范国家码）
    https://knowledgecenter.2checkout.com/Documentation/07Commerce/Checkout-links-and-options/2Checkout-supported-languages
    

### 样式参数

/* 
styleOption
样式传入采用对象形式，属性名使用小驼峰命名
*/

``` javascript
export interface StyleOption {
    commonStyle ? : CommonStyle // 传给sdk的style实例对象，不是css对象
    componentStyle ? : ComponentStyle
}

export interface CommonStyle extends JSONObject {
    paypalSPBStyle ? : {
        layout ? : 'vertical' | 'horizontal'
        color ? : 'gold' | 'blue' | 'silver' | 'white' | 'black'
        shape ? : 'rect' | 'pill'
        label ? : 'paypal' | 'checkout' | 'buynow' | 'pay' | 'installment'
        height ? : number // set the style.height option to a value from 25 to 55.
        tagline ? : boolean
    }
}

export interface CommonStyle {
    fontFamily: string
    fontSize: string
    fontWeight: string
    color: string
    textAlign: string
    backgroundColor: string
    boxSizing: string
    padding: string
    margin: string
}

export interface ComponentStyle {
    formStyle ? : JSONObject
    nameInputStyle ? : InputStyle
    cardInputStyle ? : InputStyle
    expirationInputStyle ? : InputStyle
    cvvInputStyle ? : InputStyle
    btnStyle ? : {
        normalBackground: string // 正常按钮颜色
        disableBackground: string // 禁用按钮颜色
    } & JSONObject
}

export interface InputStyle {
    labelStyle ? : JSONObject
    inputWrapperStyle ? : JSONObject
    inputStyle ? : JSONObject
    messageStyle ? : JSONObject
}
```

#### Input 组件样式

``` javascript
export interface InputStyle {
    labelStyle ? : JSONObject // Input 中 label 元素的样式
    inputWrapperStyle ? : JSONObject // Input 中 inputWrapper 元素的样式
    inputStyle ? : JSONObject // Input 中 input 元素的样式
    messageStyle ? : JSONObject // Input 中 message 元素的样式
}
```

#### Label , label提示

``` javascript
export interface Label {
    userNameLabel ? : string
    cardNumberLabel ? : string
    expirationLabel ? : string
    cvvLabel ? : string
}
```

#### Placeholder , input框提示

``` javascript
export interface Placeholder {
    userNamePlaceholder ? : string
    cardNumberPlaceholder ? : string
    expiryMonthPlaceholder ? : string
    expiryYearPlaceholder ? : string
    cvvPlaceholder ? : string
}
```

#### ErrorTips , 表单错误提示

``` javascript
export interface ErrorTips {
    userNameErrorTips ? : string
    cardNumberErrorTips ? : string
    expirationErrorTips ? : string
    cvvErrorTips ? : string
}
```

#### 输入框修改或失焦时回调参数

``` javascript
export interface FieldParams {
    message ? : string
    param ? : 'username' | 'cardnumber' | 'expiration' | 'cvv'
}
```

#### sdk加载时间回调参数

``` javascript
export interface ReportSDKLoadingParams {
    time ? : number
}
```

#### 表单填写完成回调参数

``` javascript
export interface FieldCompleteParams {
    userName ? : string
    cardNumber ? : string
    expiration ? : string
    cvv ? : string
}
```

#### 表单初始化的表单数据

``` javascript
export interface FieldData {
    userName ? : string
}
```

### 例子

#### styleOption 对象例子

``` javascript
const initialData = {
    styleOption: {
        componentStyle: {
            cardInputStyle: {
                labelStyle: {
                    backgroundColor: 'red',
                },
            }
        }
    }
}
```

### SDK 内置 function

#### getToken() 

* 注意：填全表单信息才能获取token
* 传入可选参数holderName， 字符串类型， 获取第三方支付 SDK 返回的 Token
* 当 sdkName: '2checkout' 时 holderName 为必选参数
* 例子：

``` javascript
const pay = new sdk(publicKey, initialData)

const holderName = '持卡人姓名'
setTimeout(async () => {
    const token = await pay.getToken(holderName)
    console.log(token)
}, 15000)
```

### 兼容

#### 2checkout

* IE , 仅支持 IE11

![](/img/2checkout_compatibility.png)

* 支持 Egde
* 支持 Chrome
* 支持 Firefox
* 支持 Safari
