
/*=============================================================================================
	author:ZhaoJun
	version:1.2
	email:2732810281@qq.com
=============================================================================================*/


//严格模式
/*-------------------------------------------------------------------------------------------*/	
'use strict';
/*-------------------------------------------------------------------------------------------*/
const query=require('querystring')
const fs=require('fs')
const crypto=require('crypto')
//key为在微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 

// 微信的操作
/*-------------------------------------------------------------------------------------------*/	
class wxPay
{
    static order(obj)
    {
        let oreder=Object.keys(obj)
        //1.获取所有请求参数，不包括字节类型参数，如文件、字节流，剔除sign字段，剔除值为空的参数
        oreder = oreder.filter((k) => obj[k]);
        //2.按照字符的键值ASCII码递增排序
        oreder.sort();
        //3.组合成“参数=参数值”的格式，并且把这些参数用&字符连接起来
        return oreder.map((k) => `${k}=${obj[k]}`).join('&');
    }

    static paysignapi(obj) 
    { 
        obj.appid=obj.appid?obj.appid:$ToolPay.wx.appid
        obj.mch_id=obj.mch_id?obj.mch_id:$ToolPay.wx.mch_id
        obj.nonce_str=$Sys.uid().toString()

        var string = wxPay.order(obj); 
        string+='&key='+ (obj.key?obj.key:$ToolPay.wx.key)
        var sign = crypto.createHash('md5').update(string,'utf8').digest('hex').toUpperCase(); 
        obj.sign=sign
        return obj; 
    }

    static paysign(obj)
    {
        let string = wxPay.order(obj); 

        string = string + '&key=' + (obj.key?obj.key:$ToolPay.wx.key); 
        var sign = crypto.createHash('md5').update(string,'utf8').digest('hex'); 
        return sign.toUpperCase(); 
    }

    // 此处的attach不能为空值 否则微信提示签名错误 
    static async buildParams (opt) 
    {  
        var timeStamp = parseInt(Date.now()/1000).toString(); 

        opt.spbill_create_ip=opt.spbill_create_ip?opt.spbill_create_ip:'127.0.0.1'
        //JSAPI -JSAPI支付
        //NATIVE -Native支付
        //APP -APP支付
        opt.trade_type=opt.trade_type?opt.trade_type:'JSAPI'
        opt=wxPay.paysignapi(opt)

        let data= await $Sys.model
        (
            '/request/fetch','post',
            [
                {
                    host: 'api.mch.weixin.qq.com',
                    path: '/pay/unifiedorder',
                    method: 'POST',
                    data:$Sys.model('/tool/wx/xml','setXml',[opt]),
                }
            ]
        );
        
        data=data.data
        
        if(opt.trade_type=='NATIVE')return {code_url:$Sys.model('/tool/wx/xml','getXmlNode',[data,'code_url'])}
        if(opt.trade_type=='MWEB')return {mweb_url:$Sys.model('/tool/wx/xml','getXmlNode',[data,'mweb_url'])}
        
        var prepay_id = $Sys.model('/tool/wx/xml','getXmlNode',[data,'prepay_id']); 
        
        var _opt
        if(opt.trade_type=='APP')
        {
            _opt={appid:opt.appid,noncestr:opt.nonce_str,package:"Sign=WXPay",timestamp:timeStamp,prepayid:prepay_id,partnerid:$ToolPay.wx.mch_id}
        }
        else
        {
            _opt={appId:opt.appid,nonceStr:opt.nonce_str,package:'prepay_id=' + prepay_id,signType:'MD5',timeStamp:timeStamp}
        }
        _opt.paySign=wxPay.paysign(_opt); 

        return _opt
    }

    static async back(obj)
    {
        let sign=wxPay.paysignapi(obj)
        let data= await $Sys.model
        (
            '/request/fetch','post',
            [
                {
                    host: 'api.mch.weixin.qq.com',
                    path: '/secapi/pay/refund',
                    method: 'POST',
                    key: fs.readFileSync($ToolPay.wx.keyFile),
                    cert: fs.readFileSync($ToolPay.wx.certFile),
                    data:$Sys.model('/tool/wx/xml','setXml',[sign]),
                }
            ]
        );

        return $Sys.model('/tool/wx/xml','getXml',[data.data])
    }

    static verifySign(obj)
    {
        let sign=obj.sign
        Reflect.deleteProperty(obj,'sign')
        var string =query.stringify(obj,null,null,{ encodeURIComponent: res=>res }); 
        string+='&key='+ (obj.key?obj.key:$ToolPay.wx.key)
        let signAfter = crypto.createHash('md5').update(string,'utf8').digest('hex').toUpperCase(); 
        return (sign==signAfter)
    }

    static async back(obj)
    {
        let sign=wxPay.paysignapi(obj)
        let data= await $Sys.model
        (
            '/request/fetch','post',
            [
                {
                    host: 'api.mch.weixin.qq.com',
                    path: '/secapi/pay/refund',
                    method: 'POST',
                    key: fs.readFileSync($ToolPay.wx.keyFile),
                    cert: fs.readFileSync($ToolPay.wx.certFile),
                    data:$Sys.model('/tool/wx/xml','setXml',[sign]),
                }
            ]
        );

        return $Sys.model('/tool/wx/xml','getXml',[data.data])
    }

    static async query(obj,url='/pay/orderquery')
    {
        let sign=wxPay.paysignapi(obj)
        let data= await $Sys.model
        (
            '/request/fetch','post',
            [
                {
                    host: 'api.mch.weixin.qq.com',
                    path: url,
                    method: 'POST',
                    key: fs.readFileSync($ToolPay.wx.keyFile),
                    cert: fs.readFileSync($ToolPay.wx.certFile),
                    data:$Sys.model('/tool/wx/xml','setXml',[sign]),
                }
            ]
        );

        return $Sys.model('/tool/wx/xml','getXml',[data.data])
    }

    static async tran(obj,url='/mmpaymkttransfers/promotion/transfers')
    {
        if(obj.re_user_name)obj.check_name='FORCE_CHECK'
        let sign=wxPay.paysignapi(obj)
        let data= await $Sys.model
        (
            '/request/fetch','post',
            [
                {
                    host: 'api.mch.weixin.qq.com',
                    path: url,
                    method: 'POST',
                    key: fs.readFileSync($ToolPay.wx.keyFile),
                    cert: fs.readFileSync($ToolPay.wx.certFile),
                    data:$Sys.model('/tool/wx/xml','setXml',[sign]),
                }
            ]
        );

        return $Sys.model('/tool/wx/xml','getXml',[data.data])
    }


    static success()
    {
    	return `<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>`
    }
    
}
/*-------------------------------------------------------------------------------------------*/    
module.exports=wxPay;