ipaynow 现在支付的 think.js 服务端的实现

很想吐槽现在支付,文档资料不全,写的东西有误,文档让我给value字段用URL Encodeing,按照文档做结果无法完成通知,后来删掉所有的URL Encoding才解决问题。

而且返回参数的方式奇葩,必须用payload的模式来获取返回值,还得装一个额外的组件

https://github.com/thinkjs/think-payload

可以用这个组建来获取数据,安装流程参考github的说明,需要在中间件内加一个解析器,在middlewares.js内,增加在 Think.js的payload 解析器后面。

  {
    handle: 'payload',
    options: {
      keepExtensions: true,
      limit: '5mb'
    }
  },

  // 《---------------加在这儿
  {
    handle: payload,
    options: {
      extendTypes: {
        json: ['application/x-javascript'], // will parse application/x-javascript type body in the same way as JSON type
        form: ['application/thinkjs-form'], // will parse application/thinkjs-form type body in the same way as form type
        text: ['application/thinkjs-text'], // will parse application/thinkjs-text type body in the same way as text type
        multipart: ['application/thinkjs-multipart'], // will parse application/thinkjs-multipart type body in the same way as multipart-form type
        xml: ['application/thinkjs-xml'], // will parse application/thinkjs-xml type body in the same way as xml type
      }
    }
  },  
  {
    handle: 'router',
    options: {}
  },
  'logic',
  'controller'

好了,接下来就是实现代码(Controller):

const Base = require('./base.js');
const crypto = require('crypto');
const { ctx } = require('./base.js');
const ThinkSessionFile = require('think-session-file');
const { Console } = require('console');
const { request } = require('http');
const { version } = require('os');



module.exports = class extends Base {


    sort(map)
    {
        let keys = new Array();
        for( var key in map ) {
            keys.push( key );
        }

        keys.sort();

        let new_map = new Map();
        keys.forEach(key => {
          new_map[key] = map[key];
        })
        return new_map;
    }


    signature(map, key) 
    {
        let result = '';
        for( var mapkey in map )
        {
            if( mapkey == 'signature'    || 
                mapkey == 'mhtSignature' || 
                map[mapkey] == '' ) {
                continue;
            }

            result = result + mapkey + '=' + map[mapkey] + '&';
        }

        let hex = crypto.createHash('md5').update(key   ).digest("hex");
        result += hex;

        console.log( result );
        result  = crypto.createHash('md5').update(result).digest("hex");
        return result;
    }


    datetime_string()
    {
        let now     = new Date();
        let day     = now.getDate();
        let month   = now.getMonth() + 1; 
        let year    = now.getFullYear();
        let hour    = now.getHours();
        let minuate = now.getMinutes();
        let second  = now.getSeconds();

        String( month   ).length < 2 ? ( month   = "0" + month   ) : month;
        String( day     ).length < 2 ? ( day     = "0" + day     ) : day;
        String( hour    ).length < 2 ? ( hour    = "0" + hour    ) : hour;
        String( minuate ).length < 2 ? ( minuate = "0" + minuate ) : minuate;
        String( second  ).length < 2 ? ( second  = "0" + second  ) : second;

        let result = year + "" + month + "" + day + "" + hour + "" + minuate + "" + second;
        return result;
    }


    async submitAction()
    {
        // 客户端上传,get方式
        let account         = this.get('account');
        let item_name       = this.get('item_name');    // 商品识别码
        let count           = this.get('count');
        let pay_type        = this.get('pay_type');
        let comment         = this.get('comment');

        if( think.isEmpty(account)   ||
            think.isEmpty(item_name) || 
            think.isEmpty(count)     ||
            think.isEmpty(pay_type) )
        {
            return this.fail( 6000, "invalid argument" );
        }

        if( think.isEmpty(comment) ) {
            comment = '';
        }

        // 查询得到商品的数据(这部分自己实现)
        let item = await this.model('commodity', 'mysql_nova').find_item( item_name );

        if( think.isEmpty(item) ) {
            return this.fail( 6001, "invalid item" );
        }        

        // 填充商品数据
        let detail          = item.name + " * " + count;                       // 比如xxx * 3
        let sale_off        = item.sale_off;
        let original_price  = item.price * count;
        let actual_price    = original_price * sale_off;

        // 创建订单并插入到数据库中(这部分自己实现)
        let order_id = await this.model('order', 'mysql_nova').save(
            account, item_name, detail, count, original_price, actual_price, sale_off, comment );

        if( think.isEmpty(order_id) ) {
            return this.fail( 6002, "create order failed" );
        }

        // 生成订单的签名字符串
        let map = new Map();
        map['appId']                = think.config('pay.appid');
        map['funcode']              = 'WP001';
        map['version']              = '1.0.3';
        map['mhtOrderType']         = '05';
        map['deviceType']           = '01';
        map['mhtOrderNo']           = order_id.toString();
        map['mhtOrderName']         = item_name;
        map['mhtReserved']          = item_name;
        map['mhtOrderDetail']       = detail;
        map['mhtOrderAmt']          = actual_price;
        map['mhtOrderStartTime']    = this.datetime_string();
        map['payChannelType']       = pay_type;
        map['mhtCurrencyType']      = think.config('pay.currency');
        map['mhtOrderTimeOut']      = think.config('pay.timeout');
        map['notifyUrl']            = think.config('pay.notify');
        map['mhtCharset']           = think.config('pay.charset');
        map['mhtSignType']          = think.config('pay.signtype');
        map['mhtSubAppId']          = think.config('pay.subappid');
        map['consumerCreateIp']     = this.ctx.ip;


        map = this.sort( map );
        let sign = this.signature( map, think.config('pay.key') );
        map['mhtSignature']         = sign;
        

        let launch = true;
        let result = "";
        for( var key in map )
        {
            if( launch != true ) {
                result += '&';
            }

            result = result + key + '=' + map[key]; 
            launch = false;
        }        


        return this.json(result);
    }


    async notifyAction()
    {
        // 回调通知
        // should install think-payload first.
        // detail: https://github.com/thinkjs/think-payload

        let info = this.ctx.request.body;
        if( think.isEmpty(info) ) {
            return this.json('success=N, extract body post failed');
        }

        console.log( 'notify info', info );

        // 拆分字符串
        let array = info.split('&');

        let map = new Map();
        array.forEach(key => {

            let pair = key.split('=');
            map[pair[0]] = decodeURIComponent(pair[1]);
        });

        map = this.sort( map );
        let secret = this.signature( map, think.config('pay.key') );

        if( secret != map['signature'] &&
            secret != map['mhtSignature'] ) 
        {
            return this.json('success=N, signature failed.');
        }

        // 检验校验码通过,接下来就需要判断是否支付成功,
        // 订单号是否正确
        let state      = map['tradeStatus'];
        let order_id   = map['mhtOrderNo'];
        let payment_sn = map['nowPayOrderNo'];

        if( state == 'A001' )
        {
            // (数据库的更新自己实现)
            let retval = await this.model('order', 'mysql_nova').update_payment(order_id, payment_sn);

            if( retval == 1 ) {
                return this.json('success=Y');
            }
        }

        return this.json('success=N, invalid state or order id');
    }


}

这个代码测试了可用,config需要自己去重新配。这儿就不累述了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值