Skip to content

Instantly share code, notes, and snippets.

@CandyMi
Last active January 7, 2025 08:55
Show Gist options
  • Save CandyMi/09aeb2120fd7742fe1f5b018b58a07e6 to your computer and use it in GitHub Desktop.
Save CandyMi/09aeb2120fd7742fe1f5b018b58a07e6 to your computer and use it in GitHub Desktop.
微信支付Lua SDK

微信支付Lua SDK

接口列表

  1. order 查询订单状态、关闭订单

  2. native/micro/h5 扫码支付、付款码支付、H5支付等等接口

  3. banks 银行卡对应表中文

  4. sign 签名与验证(外部一般无需使用)

推荐的使用流程

  1. 客户端调用服务端接口完成支付下单流程, 服务端使用上述接口列表提供的方法完成下单流程并且返回prepay_id给客户端.

  2. 客户端正确得到prepay_id后引导用户完成下单操作, 服务端根据order实现的2个接口实现订单支付查询与关闭订单的交互接口

  3. 客户端如遇用户取消支付则应该调用服务端的关闭订单接口完成订单关闭, 遇到用户支付成功则需要主动调用查询是否支付成功.

  4. 根据实际情况完成后续业务.

注意

  1. trade_no必须唯一(无论是否支付成功或关闭订单).

  2. 付款码支付需要客户端传入openid.

  3. 目前尚不支持退款接口.

-- 对应此处的银行类型: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_2
return {
ICBC_DEBIT = "工商银行(借记卡)",
ICBC_CREDIT = "工商银行(信用卡)",
ABC_DEBIT = "农业银行(借记卡)",
ABC_CREDIT = "农业银行(信用卡)",
PSBC_CREDIT = "邮储银行(信用卡)",
PSBC_DEBIT = "邮储银行(借记卡)",
CCB_DEBIT = "建设银行(借记卡)",
CCB_CREDIT = "建设银行(信用卡)",
CMB_DEBIT = "招商银行(借记卡)",
CMB_CREDIT = "招商银行(信用卡)",
BOC_DEBIT = "中国银行(借记卡)",
BOC_CREDIT = "中国银行(信用卡)",
COMM_DEBIT = "交通银行(借记卡)",
COMM_CREDIT = "交通银行(信用卡)",
SPDB_DEBIT = "浦发银行(借记卡)",
SPDB_CREDIT = "浦发银行(信用卡)",
GDB_DEBIT = "广发银行(借记卡)",
GDB_CREDIT = "广发银行(信用卡)",
CMBC_DEBIT = "民生银行(借记卡)",
CMBC_CREDIT = "民生银行(信用卡)",
PAB_DEBIT = "平安银行(借记卡)",
PAB_CREDIT = "平安银行(信用卡)",
CEB_DEBIT = "光大银行(借记卡)",
CEB_CREDIT = "光大银行(信用卡)",
CIB_DEBIT = "兴业银行(借记卡)",
CIB_CREDIT = "兴业银行(信用卡)",
CITIC_DEBIT = "中信银行(借记卡)",
CITIC_CREDIT = "中信银行(信用卡)",
BOSH_DEBIT = "上海银行(借记卡)",
BOSH_CREDIT = "上海银行(信用卡)",
AHRCUB_CREDIT = "安徽省农村信用社联合社(信用卡)",
AHRCUB_DEBIT = "安徽省农村信用社联合社(借记卡)",
AIB_DEBIT = "百信银行(借记卡)",
ASCB_DEBIT = "鞍山银行(借记卡)",
ATRB_DEBIT = "盘山安泰村镇银行(借记卡)",
BCZ_CREDIT = "沧州银行(信用卡)",
BCZ_DEBIT = "沧州银行(借记卡)",
BDB_DEBIT = "保定银行(借记卡)",
BEEB_CREDIT = "鄞州银行(信用卡)",
BEEB_DEBIT = "鄞州银行(借记卡)",
BGZB_DEBIT = "贵州银行(借记卡)",
BHB_CREDIT = "河北银行(信用卡)",
BHB_DEBIT = "河北银行(借记卡)",
BJRCB_CREDIT = "北京农商行(信用卡)",
BJRCB_DEBIT = "北京农商行(借记卡)",
BNC_CREDIT = "江西银行(信用卡)",
BNC_DEBIT = "江西银行(借记卡)",
BOB_CREDIT = "北京银行(信用卡)",
BOB_DEBIT = "北京银行(借记卡)",
BOBBG_CREDIT = "北部湾银行(信用卡)",
BOBBG_DEBIT = "北部湾银行(借记卡)",
BOCD_DEBIT = "成都银行(借记卡)",
BOCDB_DEBIT = "承德银行(借记卡)",
BOCFB_DEBIT = "中银富登村镇银行(借记卡)",
BOCTS_DEBIT = "焦作中旅银行(借记卡)",
BOD_CREDIT = "东莞银行(信用卡)",
BOD_DEBIT = "东莞银行(借记卡)",
BOFS_DEBIT = "抚顺银行(借记卡)",
BOHN_DEBIT = "海南银行(借记卡)",
BOIMCB_CREDIT = "内蒙古银行(信用卡)",
BOIMCB_DEBIT = "内蒙古银行(借记卡)",
BOJN_DEBIT = "济宁银行(借记卡)",
BOJX_DEBIT = "嘉兴银行(借记卡)",
BOLB_DEBIT = "洛阳银行(借记卡)",
BOLFB_DEBIT = "廊坊银行(借记卡)",
BONX_CREDIT = "宁夏银行(信用卡)",
BONX_DEBIT = "宁夏银行(借记卡)",
BOPDS_DEBIT = "平顶山银行(借记卡)",
BOPJ_DEBIT = "盘锦银行(借记卡)",
BOQHB_CREDIT = "青海银行(信用卡)",
BOQHB_DEBIT = "青海银行(借记卡)",
BOSXB_DEBIT = "绍兴银行(借记卡)",
BOSZS_DEBIT = "石嘴山银行(借记卡)",
BOTSB_DEBIT = "唐山银行(借记卡)",
BOZ_CREDIT = "张家口银行(信用卡)",
BOZ_DEBIT = "张家口银行(借记卡)",
BSB_CREDIT = "包商银行(信用卡)",
BSB_DEBIT = "包商银行(借记卡)",
BYK_DEBIT = "营口银行(借记卡)",
CBHB_DEBIT = "渤海银行(借记卡)",
CCAB_CREDIT = "长安银行(信用卡)",
CCAB_DEBIT = "长安银行(借记卡)",
CDRCB_DEBIT = "成都农商银行(借记卡)",
CITIB_CREDIT = "花旗银行(信用卡)",
CITIB_DEBIT = "花旗银行(借记卡)",
CJCCB_DEBIT = "江苏长江商业银行(借记卡)",
CQB_CREDIT = "重庆银行(信用卡)",
CQB_DEBIT = "重庆银行(借记卡)",
CQRCB_CREDIT = "重庆农村商业银行(信用卡)",
CQRCB_DEBIT = "重庆农村商业银行(借记卡)",
CQTGB_DEBIT = "重庆三峡银行(借记卡)",
CRB_CREDIT = "珠海华润银行(信用卡)",
CRB_DEBIT = "珠海华润银行(借记卡)",
CSCB_CREDIT = "长沙银行(信用卡)",
CSCB_DEBIT = "长沙银行(借记卡)",
CSRCB_CREDIT = "常熟农商银行(信用卡)",
CSRCB_DEBIT = "常熟农商银行(借记卡)",
CSXB_DEBIT = "三湘银行(借记卡)",
CYCB_CREDIT = "朝阳银行(信用卡)",
CYCB_DEBIT = "朝阳银行(借记卡)",
CZB_CREDIT = "浙商银行(信用卡)",
CZB_DEBIT = "浙商银行(借记卡)",
CZCB_CREDIT = "稠州银行(信用卡)",
CZCB_DEBIT = "稠州银行(借记卡)",
CZCCB_DEBIT = "长治银行(借记卡)",
DANDONGB_CREDIT = "丹东银行(信用卡)",
DANDONGB_DEBIT = "丹东银行(借记卡)",
DBSB_DEBIT = "星展银行(借记卡)",
DCSFRB_DEBIT = "大城舜丰村镇银行(借记卡)",
DHDYB_DEBIT = "德惠敦银村镇银行(借记卡)",
DHRB_DEBIT = "调兵山惠民村镇银行(借记卡)",
DLB_CREDIT = "大连银行(信用卡)",
DLB_DEBIT = "大连银行(借记卡)",
DLRCB_DEBIT = "大连农商行(借记卡)",
DRCB_CREDIT = "东莞农商银行(信用卡)",
DRCB_DEBIT = "东莞农商银行(借记卡)",
DSB_DEBIT = "大新银行(借记卡)",
DTCCB_DEBIT = "大同银行(借记卡)",
DYB_CREDIT = "东营银行(信用卡)",
DYB_DEBIT = "东营银行(借记卡)",
DYCCB_DEBIT = "长城华西银行(借记卡)",
DYLSB_DEBIT = "东营莱商村镇银行(借记卡)",
DZB_DEBIT = "德州银行(借记卡)",
DZCCB_DEBIT = "达州银行(借记卡)",
EDRB_DEBIT = "鼎业村镇银行(借记卡)",
ESUNB_DEBIT = "玉山银行(借记卡)",
FBB_DEBIT = "富邦华一银行(借记卡)",
FDB_CREDIT = "富滇银行(信用卡)",
FDB_DEBIT = "富滇银行(借记卡)",
FJHXB_CREDIT = "福建海峡银行(信用卡)",
FJHXB_DEBIT = "福建海峡银行(借记卡)",
FJNX_CREDIT = "福建农信银行(信用卡)",
FJNX_DEBIT = "福建农信银行(借记卡)",
FUXINB_CREDIT = "阜新银行(信用卡)",
FUXINB_DEBIT = "阜新银行(借记卡)",
FXLZB_DEBIT = "费县梁邹村镇银行(借记卡)",
GADRB_DEBIT = "贵安新区发展村镇银行(借记卡)",
GDHX_DEBIT = "广东华兴银行(借记卡)",
GDNYB_CREDIT = "南粤银行(信用卡)",
GDNYB_DEBIT = "南粤银行(借记卡)",
GDRCU_DEBIT = "广东农信银行(借记卡)",
GLB_CREDIT = "桂林银行(信用卡)",
GLB_DEBIT = "桂林银行(借记卡)",
GLGMCB_DEBIT = "桂林国民村镇银行(借记卡)",
GRCB_CREDIT = "广州农商银行(信用卡)",
GRCB_DEBIT = "广州农商银行(借记卡)",
GSB_DEBIT = "甘肃银行(借记卡)",
GSNX_DEBIT = "甘肃农信(借记卡)",
GSRB_DEBIT = "广阳舜丰村镇银行(借记卡)",
GXNX_CREDIT = "广西农信(信用卡)",
GXNX_DEBIT = "广西农信(借记卡)",
GYCB_CREDIT = "贵阳银行(信用卡)",
GYCB_DEBIT = "贵阳银行(借记卡)",
GZCB_CREDIT = "广州银行(信用卡)",
GZCB_DEBIT = "广州银行(借记卡)",
GZCCB_CREDIT = "赣州银行(信用卡)",
GZCCB_DEBIT = "赣州银行(借记卡)",
GZNX_DEBIT = "贵州农信(借记卡)",
HAINNX_CREDIT = "海南农信(信用卡)",
HAINNX_DEBIT = "海南农信(借记卡)",
HANAB_DEBIT = "韩亚银行(借记卡)",
HBCB_CREDIT = "湖北银行(信用卡)",
HBCB_DEBIT = "湖北银行(借记卡)",
HBNX_CREDIT = "湖北农信(信用卡)",
HBNX_DEBIT = "湖北农信(借记卡)",
HDCB_DEBIT = "邯郸银行(借记卡)",
HEBNX_DEBIT = "河北农信(借记卡)",
HFB_CREDIT = "恒丰银行(信用卡)",
HFB_DEBIT = "恒丰银行(借记卡)",
HKB_CREDIT = "汉口银行(信用卡)",
HKB_DEBIT = "汉口银行(借记卡)",
HKBEA_CREDIT = "东亚银行(信用卡)",
HKBEA_DEBIT = "东亚银行(借记卡)",
HKUB_DEBIT = "海口联合农商银行(借记卡)",
HLDCCB_DEBIT = "葫芦岛银行(借记卡)",
HLDYB_DEBIT = "和龙敦银村镇银行(借记卡)",
HLJRCUB_DEBIT = "黑龙江农信社(借记卡)",
HMCCB_DEBIT = "哈密银行(借记卡)",
HNNX_DEBIT = "河南农信(借记卡)",
HRBB_CREDIT = "哈尔滨银行(信用卡)",
HRBB_DEBIT = "哈尔滨银行(借记卡)",
HRCB_DEBIT = "保德慧融村镇银行(借记卡)",
HRXJB_CREDIT = "华融湘江银行(信用卡)",
HRXJB_DEBIT = "华融湘江银行(借记卡)",
HSB_CREDIT = "徽商银行(信用卡)",
HSB_DEBIT = "徽商银行(借记卡)",
HSBC_DEBIT = "恒生银行(借记卡)",
HSBCC_CREDIT = "汇丰银行(信用卡)",
HSBCC_DEBIT = "汇丰银行(借记卡)",
HSCB_DEBIT = "衡水银行(借记卡)",
HUIHEB_DEBIT = "新疆汇和银行(借记卡)",
HUNNX_DEBIT = "湖南农信(借记卡)",
HUSRB_DEBIT = "湖商村镇银行(借记卡)",
HXB_CREDIT = "华夏银行(信用卡)",
HXB_DEBIT = "华夏银行(借记卡)",
HZB_CREDIT = "杭州银行(信用卡)",
HZB_DEBIT = "杭州银行(借记卡)",
HZCCB_DEBIT = "湖州银行(借记卡)",
IBKB_DEBIT = "企业银行(借记卡)",
JCB_DEBIT = "晋城银行(借记卡)",
JCBK_CREDIT = "晋城银行(信用卡)",
JDHDB_DEBIT = "上海嘉定洪都村镇银行(借记卡)",
JDZCCB_DEBIT = "景德镇市商业银行(借记卡)",
JHCCB_CREDIT = "金华银行(信用卡)",
JHCCB_DEBIT = "金华银行(借记卡)",
JJCCB_CREDIT = "九江银行(信用卡)",
JJCCB_DEBIT = "九江银行(借记卡)",
JLB_CREDIT = "吉林银行(信用卡)",
JLB_DEBIT = "吉林银行(借记卡)",
JLNX_DEBIT = "吉林农信(借记卡)",
JNRCB_CREDIT = "江南农商行(信用卡)",
JNRCB_DEBIT = "江南农商行(借记卡)",
JRCB_CREDIT = "江阴农商行(信用卡)",
JRCB_DEBIT = "江阴农商行(借记卡)",
JSB_CREDIT = "江苏银行(信用卡)",
JSB_DEBIT = "江苏银行(借记卡)",
JSHB_CREDIT = "晋商银行(信用卡)",
JSHB_DEBIT = "晋商银行(借记卡)",
JSNX_CREDIT = "江苏农信(信用卡)",
JSNX_DEBIT = "江苏农信(借记卡)",
JUFENGB_DEBIT = "临朐聚丰村镇银行(借记卡)",
JXB_DEBIT = "西昌金信村镇银行(借记卡)",
JXNXB_DEBIT = "江西农信(借记卡)",
JZB_CREDIT = "晋中银行(信用卡)",
JZB_DEBIT = "晋中银行(借记卡)",
JZCB_CREDIT = "锦州银行(信用卡)",
JZCB_DEBIT = "锦州银行(借记卡)",
KCBEB_DEBIT = "天津金城银行(借记卡)",
KLB_CREDIT = "昆仑银行(信用卡)",
KLB_DEBIT = "昆仑银行(借记卡)",
KRCB_DEBIT = "昆山农商(借记卡)",
KSHB_DEBIT = "梅州客商银行(借记卡)",
KUERLECB_DEBIT = "库尔勒市商业银行(借记卡)",
LCYRB_DEBIT = "陵城圆融村镇银行(借记卡)",
LICYRB_DEBIT = "历城圆融村镇银行(借记卡)",
LJB_DEBIT = "龙江银行(借记卡)",
LLB_DEBIT = "山东兰陵村镇银行(借记卡)",
LLHZCB_DEBIT = "柳林汇泽村镇银行(借记卡)",
LNNX_DEBIT = "辽宁农信(借记卡)",
LPCB_DEBIT = "凉山州商业银行(借记卡)",
LPSBLVB_DEBIT = "钟山凉都村镇银行(借记卡)",
LSB_CREDIT = "临商银行(信用卡)",
LSB_DEBIT = "临商银行(借记卡)",
LSCCB_DEBIT = "乐山市商业银行(借记卡)",
LUZB_DEBIT = "柳州银行(借记卡)",
LWB_DEBIT = "莱商银行(借记卡)",
LYYHB_DEBIT = "辽阳银行(借记卡)",
LZB_CREDIT = "兰州银行(信用卡)",
LZB_DEBIT = "兰州银行(借记卡)",
LZCCB_DEBIT = "泸州市商业银行(借记卡)",
MHBRB_DEBIT = "闵行上银村镇银行(借记卡)",
MINTAIB_CREDIT = "民泰银行(信用卡)",
MINTAIB_DEBIT = "民泰银行(借记卡)",
MPJDRB_DEBIT = "牟平胶东村镇银行(借记卡)",
MYCCB_DEBIT = "绵阳市商业银行(借记卡)",
NBCB_CREDIT = "宁波银行(信用卡)",
NBCB_DEBIT = "宁波银行(借记卡)",
NCB_DEBIT = "宁波通商银行(借记卡)",
NCBCB_DEBIT = "南洋商业银行(借记卡)",
NCCB_DEBIT = "四川天府银行(借记卡)",
NJCB_CREDIT = "南京银行(信用卡)",
NJCB_DEBIT = "南京银行(借记卡)",
NJJDRB_DEBIT = "宁津胶东村镇银行(借记卡)",
NJXLRB_DEBIT = "内江兴隆村镇银行(借记卡)",
NMGNX_DEBIT = "内蒙古农信(借记卡)",
NNGMB_DEBIT = "南宁江南国民村镇银行(借记卡)",
NUB_DEBIT = "辽宁振兴银行(借记卡)",
NYCCB_DEBIT = "南阳村镇银行(借记卡)",
OCBCWHCB_DEBIT = "华侨永亨银行(借记卡)",
OHVB_DEBIT = "鄂托克旗汇泽村镇银行(借记卡)",
ORDOSB_CREDIT = "鄂尔多斯银行(信用卡)",
ORDOSB_DEBIT = "鄂尔多斯银行(借记卡)",
PBDLRB_DEBIT = "平坝鼎立村镇银行(借记卡)",
PJDWHFB_DEBIT = "大洼恒丰村镇银行(借记卡)",
PJJYRB_DEBIT = "浦江嘉银村镇银行(借记卡)",
PZHCCB_DEBIT = "攀枝花银行(借记卡)",
QDCCB_CREDIT = "青岛银行(信用卡)",
QDCCB_DEBIT = "青岛银行(借记卡)",
QHDB_DEBIT = "秦皇岛银行(借记卡)",
QHJDRB_DEBIT = "齐河胶东村镇银行(借记卡)",
QHNX_DEBIT = "青海农信(借记卡)",
QJSYB_DEBIT = "衢江上银村镇银行(借记卡)",
QLB_CREDIT = "齐鲁银行(信用卡)",
QLB_DEBIT = "齐鲁银行(借记卡)",
QLVB_DEBIT = "青隆村镇银行(借记卡)",
QSB_CREDIT = "齐商银行(信用卡)",
QSB_DEBIT = "齐商银行(借记卡)",
QZCCB_CREDIT = "泉州银行(信用卡)",
QZCCB_DEBIT = "泉州银行(借记卡)",
RHCB_DEBIT = "长子县融汇村镇银行(借记卡)",
RQCZB_DEBIT = "任丘村镇银行(借记卡)",
RXYHB_DEBIT = "瑞信村镇银行(借记卡)",
RZB_DEBIT = "日照银行(借记卡)",
SCB_CREDIT = "渣打银行(信用卡)",
SCB_DEBIT = "渣打银行(借记卡)",
SCNX_DEBIT = "四川农信(借记卡)",
SDEB_CREDIT = "顺德农商行(信用卡)",
SDEB_DEBIT = "顺德农商行(借记卡)",
SDRCU_DEBIT = "山东农信(借记卡)",
SHHJB_DEBIT = "商河汇金村镇银行(借记卡)",
SHINHAN_DEBIT = "新韩银行(借记卡)",
SHRB_DEBIT = "上海华瑞银行(借记卡)",
SJB_CREDIT = "盛京银行(信用卡)",
SJB_DEBIT = "盛京银行(借记卡)",
SNB_DEBIT = "苏宁银行(借记卡)",
SNCCB_DEBIT = "遂宁银行(借记卡)",
SPDYB_DEBIT = "四平铁西敦银村镇银行(借记卡)",
SRB_DEBIT = "上饶银行(借记卡)",
SRCB_CREDIT = "上海农商银行(信用卡)",
SRCB_DEBIT = "上海农商银行(借记卡)",
SUZB_CREDIT = "苏州银行(信用卡)",
SUZB_DEBIT = "苏州银行(借记卡)",
SXNX_DEBIT = "山西农信(借记卡)",
SXXH_DEBIT = "陕西信合(借记卡)",
SZRCB_CREDIT = "深圳农商银行(信用卡)",
SZRCB_DEBIT = "深圳农商银行(借记卡)",
TACCB_CREDIT = "泰安银行(信用卡)",
TACCB_DEBIT = "泰安银行(借记卡)",
TCRCB_DEBIT = "太仓农商行(借记卡)",
TJB_CREDIT = "天津银行(信用卡)",
TJB_DEBIT = "天津银行(借记卡)",
TJBHB_CREDIT = "天津滨海农商行(信用卡)",
TJBHB_DEBIT = "天津滨海农商行(借记卡)",
TJHMB_DEBIT = "天津华明村镇银行(借记卡)",
TJNHVB_DEBIT = "天津宁河村镇银行(借记卡)",
TLB_DEBIT = "铁岭银行(借记卡)",
TLVB_DEBIT = "铁岭新星村镇银行(借记卡)",
TMDYB_DEBIT = "图们敦银村镇银行(借记卡)",
TRCB_CREDIT = "天津农商(信用卡)",
TRCB_DEBIT = "天津农商(借记卡)",
TZB_CREDIT = "台州银行(信用卡)",
TZB_DEBIT = "台州银行(借记卡)",
UOB_DEBIT = "大华银行(借记卡)",
URB_DEBIT = "联合村镇银行(借记卡)",
VBCB_DEBIT = "村镇银行(借记卡)",
WACZB_DEBIT = "武安村镇银行(借记卡)",
WB_DEBIT = "友利银行(借记卡)",
WEB_DEBIT = "微众银行(借记卡)",
WEGOB_DEBIT = "蓝海银行(借记卡)",
WFB_CREDIT = "潍坊银行(信用卡)",
WFB_DEBIT = "潍坊银行(借记卡)",
WHB_CREDIT = "威海商业银行(信用卡)",
WHB_DEBIT = "威海商业银行(借记卡)",
WHRC_CREDIT = "武汉农商行(信用卡)",
WHRC_DEBIT = "武汉农商行(借记卡)",
WHRYVB_DEBIT = "芜湖圆融村镇银行(借记卡)",
WJRCB_CREDIT = "吴江农商行(信用卡)",
WJRCB_DEBIT = "吴江农商行(借记卡)",
WLMQB_CREDIT = "乌鲁木齐银行(信用卡)",
WLMQB_DEBIT = "乌鲁木齐银行(借记卡)",
WRCB_CREDIT = "无锡农商行(信用卡)",
WRCB_DEBIT = "无锡农商行(借记卡)",
WUHAICB_DEBIT = "乌海银行(借记卡)",
WZB_CREDIT = "温州银行(信用卡)",
WZB_DEBIT = "温州银行(借记卡)",
WZMSB_DEBIT = "温州民商(借记卡)",
XAB_CREDIT = "西安银行(信用卡)",
XAB_DEBIT = "西安银行(借记卡)",
XCXPB_DEBIT = "许昌新浦村镇银行(借记卡)",
XHB_DEBIT = "大连鑫汇村镇银行(借记卡)",
XHNMB_DEBIT = "安顺西航南马村镇银行(借记卡)",
XIB_DEBIT = "厦门国际银行(借记卡)",
XINANB_DEBIT = "安徽新安银行(借记卡)",
XJB_DEBIT = "新疆银行(借记卡)",
XJJDRB_DEBIT = "夏津胶东村镇银行(借记卡)",
XJRCCB_DEBIT = "新疆农信银行(借记卡)",
XMCCB_CREDIT = "厦门银行(信用卡)",
XMCCB_DEBIT = "厦门银行(借记卡)",
XRTB_DEBIT = "元氏信融村镇银行(借记卡)",
XTB_CREDIT = "邢台银行(信用卡)",
XTB_DEBIT = "邢台银行(借记卡)",
XWB_DEBIT = "新网银行(借记卡)",
XXCB_DEBIT = "新乡银行(借记卡)",
XXHZCB_DEBIT = "兴县汇泽村镇银行(借记卡)",
XXRB_DEBIT = "新乡新兴村镇银行(借记卡)",
XYPQZYCB_DEBIT = "信阳平桥中原村镇银行(借记卡)",
XZB_DEBIT = "西藏银行(借记卡)",
YACCB_DEBIT = "雅安市商业银行(借记卡)",
YBCCB_DEBIT = "宜宾商业银行(借记卡)",
YKCB_DEBIT = "营口沿海银行(借记卡)",
YLB_DEBIT = "亿联银行(借记卡)",
YNHTB_CREDIT = "云南红塔银行(信用卡)",
YNHTB_DEBIT = "云南红塔银行(借记卡)",
YNRCCB_CREDIT = "云南农信(信用卡)",
YNRCCB_DEBIT = "云南农信(借记卡)",
YQCCB_DEBIT = "阳泉市商业银行(借记卡)",
YQMYRB_DEBIT = "玉泉蒙银村镇银行(借记卡)",
YRRCB_CREDIT = "黄河农商银行(信用卡)",
YRRCB_DEBIT = "黄河农商银行(借记卡)",
YTB_DEBIT = "烟台银行(借记卡)",
YYBSCB_DEBIT = "沂源博商村镇银行(借记卡)",
ZCRB_DEBIT = "遵义新蒲长征村镇银行(借记卡)",
ZGB_DEBIT = "自贡银行(借记卡)",
ZGCB_DEBIT = "北京中关村银行(借记卡)",
ZHCB_DEBIT = "庄河汇通村镇银行(借记卡)",
ZHQYTB_DEBIT = "沾化青云村镇银行(借记卡)",
ZJB_DEBIT = "紫金农商银行(借记卡)",
ZJLXRB_DEBIT = "兰溪越商银行(借记卡)",
ZJRCUB_CREDIT = "浙江农信(信用卡)",
ZJRCUB_DEBIT = "浙江农信(借记卡)",
ZJTLCB_CREDIT = "浙江泰隆银行(信用卡)",
ZJTLCB_DEBIT = "浙江泰隆银行(借记卡)",
ZRCB_CREDIT = "张家港农商行(信用卡)",
ZRCB_DEBIT = "张家港农商行(借记卡)",
ZSXKCCB_DEBIT = "中山小榄村镇银行(借记卡)",
ZYB_CREDIT = "中原银行(信用卡)",
ZYB_DEBIT = "中原银行(借记卡)",
ZZB_CREDIT = "郑州银行(信用卡)",
ZZB_DEBIT = "郑州银行(借记卡)",
ZZCCB_DEBIT = "枣庄银行(借记卡)",
WPHK = "WPHK",
QSK = "亲属卡",
DINERSCLUD = "DINERSCLUD",
MASTERCARD = "MASTERCARD",
VISA = "VISA",
CFT = "CFT",
LQT = "LQT",
AMERICANEXPRESS = "AMERICANEXPRESS",
DISCOVER = "DISCOVER",
OTHERS = "其他(银行卡以外)",
}
return {
"https://api.mch.weixin.qq.com",
"https://api2.mch.weixin.qq.com",
}
--[[
微信支付SDK v0.1
(H5)移动支付
]]
local httpc = require "httpc"
local xml2lua = require "xml2lua"
local domains = require "cloud.wechat.domains"
local sign = require "cloud.wechat.sign"
local order = require "cloud.wechat.order"
local type = type
local next = next
local tostring = tostring
local tonumber = tonumber
-- 验证域名是否规范
local function is_domain(URI)
if not URI or URI == '' then
return nil
end
return string.find(URI, "http[s]://[^/]+/.*")
end
local h5 = { __Version__ = 0.1, domains = domains }
-- 验证请求返回签名(请勿在外部调用)
h5.sign_varify = sign.sign_varify
-- 出错信息格式化(请勿在外部调用)
h5.error_format = sign.error_format
-- 查询订单
h5.h5_query = order.query
-- 关闭订单
h5.h5_close = order.close
-- 退款
h5.refund = order.refund
-- 退款查询
h5.refund_query = order.refund_query
--[[
1. H5提交订单
]]
function h5.h5_pay( opt )
assert(type(opt) == 'table' and next(opt), "invalide parameters.")
-- appid 必须是string类型并且不能为空
assert(type(opt.appid) == 'string' and opt.appid ~= '', "invalide appid.")
-- apikey 必须是string类型并且不能为空
assert(type(opt.apikey) == 'string' and opt.apikey ~= '', "invalide apikey.")
-- mch_id 必须是string类型并且不能为空
assert(type(opt.mch_id) == 'string' and opt.mch_id ~= '', "invalide mch_id.")
-- trade_no 必须是string类型并且不能为空
assert(type(opt.trade_no) == 'string' and opt.trade_no ~= '', "invalide trade_no.")
-- describe 必须是string类型并且不能为空
assert(type(opt.describe) == 'string' and opt.describe ~= '', "invalide describe.")
-- sign_type 必须是HMAC-SHA256或者MD5其中一个
assert(opt.sign_type == 'HMAC-SHA256' or opt.sign_type == 'MD5', "invalide sign_type(need HMAC-SHA256 or MD5).")
-- notify_url 必须是一个可以正确回应的微信支付后回调的url
assert(type(opt.notify_url) == 'string' and is_domain(opt.notify_url), "invalide notify_url.")
-- ip 必须是string类型并且不能为空
assert(type(opt.ip) == 'string' and opt.ip ~= '', "invalide ip address.")
-- amount 必须是整数类型
assert(math.tointeger(opt.amount), "invalide amoun.")
-- 初始化参数
local req = {
appid = opt.appid,
mch_id = opt.mch_id,
total_fee = opt.amount,
product_id = tostring(opt.product_id),
fee_type = opt.amount_type or "CNY",
nonce_str = sign.gen_nonce(),
trade_type = "MWEB",
out_trade_no = opt.trade_no,
-- openid = opt.openid,
body = opt.describe,
receipt = opt.receipt and "Y" or nil,
notify_url = opt.notify_url,
limit_pay = opt.limit_pay and "no_credit" or nil,
spbill_create_ip = opt.ip,
attach = opt.customize,
}
-- 签名
local sign_str = nil
if opt.sign_type == 'MD5' then
opt.sign_type = "MD5"
req.sign_type = "MD5"
req.sign = sign.md5(req, opt.apikey)
else
opt.sign_type = "HMAC-SHA256"
req.sign_type = "HMAC-SHA256"
req.sign = sign.hmac_sha256(req, opt.apikey)
end
local code, response = httpc.raw { domain = h5.domains[1] .. '/pay/unifiedorder', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
if code ~= 200 then
if code == nil then
code, response = httpc.raw { domain = h5.domains[2] .. '/pay/unifiedorder', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
end
if code ~= 200 then
return nil, response
end
end
-- print(response)
response = xml2lua.parser(response)
if type(response) ~= 'table' then
return nil, "invalide response"
end
-- var_dump(response)
response = response['xml']
if response['result_code'] ~= 'SUCCESS' then
return nil, h5.error_format(response)
end
-- 签名验证
return h5.sign_varify(opt, req, response)
end
return h5
--[[
微信支付SDK v0.1
提交(付款码)支付
]]
local httpc = require "httpc"
local xml2lua = require "xml2lua"
local domains = require "cloud.wechat.domains"
local sign = require "cloud.wechat.sign"
local order = require "cloud.wechat.order"
local type = type
local next = next
-- 验证域名是否规范
local function is_domain(URI)
if not URI or URI == '' then
return nil
end
return string.find(URI, "http[s]://[^/]+/.*")
end
local micro = { __Version__ = 0.1, domains = domains }
-- 验证请求返回签名(请勿在外部调用)
micro.sign_varify = sign.sign_varify
-- 出错信息格式化(请勿在外部调用)
micro.error_format = sign.error_format
-- 查询订单
micro.micro_query = order.query
-- 关闭订单
micro.micro_close = order.close
-- 退款
micro.refund = order.refund
-- 退款查询
micro.refund_query = order.refund_query
--[[
1. 付款码下单
]]
function micro.micro_pay( opt )
assert(type(opt) == 'table' and next(opt), "invalide parameters.")
-- appid 必须是string类型并且不能为空
assert(type(opt.appid) == 'string' and opt.appid ~= '', "invalide appid.")
-- apikey 必须是string类型并且不能为空
assert(type(opt.apikey) == 'string' and opt.apikey ~= '', "invalide apikey.")
-- mch_id 必须是string类型并且不能为空
assert(type(opt.mch_id) == 'string' and opt.mch_id ~= '', "invalide mch_id.")
-- trade_no 必须是string类型并且不能为空
assert(type(opt.trade_no) == 'string' and opt.trade_no ~= '', "invalide trade_no.")
-- describe 必须是string类型并且不能为空
assert(type(opt.describe) == 'string' and opt.describe ~= '', "invalide describe.")
-- sign_type 必须是HMAC-SHA256或者MD5其中一个
assert(opt.sign_type == 'HMAC-SHA256' or opt.sign_type == 'MD5', "invalide sign_type(need HMAC-SHA256 or MD5).")
-- auth_code 必须是string类型并且不能为空
assert(type(opt.auth_code) == 'string' and opt.auth_code ~= '', "invalide auth_code.")
-- openid 必须是string类型并且不能为空
assert(type(opt.openid) == 'string' and opt.openid ~= '', "invalide openid.")
-- notify_url 必须是一个可以正确回应的微信支付后回调的url
assert(type(opt.notify_url) == 'string' and is_domain(opt.notify_url), "invalide notify_url.")
-- amount 必须是是整数类型
assert(math.tointeger(opt.amount), "invalide amoun.")
-- 初始化参数
local req = {
appid = opt.appid,
mch_id = opt.mch_id,
total_fee = opt.amount,
product_id = opt.product_id,
fee_type = opt.amount_type or "CNY",
nonce_str = sign.gen_nonce(),
auth_code = opt.auth_code,
openid = opt.openid,
out_trade_no = opt.trade_no,
body = opt.describe,
receipt = opt.receipt and "Y" or nil,
notify_url = opt.notify_url,
limit_pay = opt.limit_pay and "no_credit" or nil,
spbill_create_ip = opt.ip,
attach = opt.customize,
}
-- 签名
local sign_str = nil
if opt.sign_type == 'MD5' then
opt.sign_type = "MD5"
req.sign_type = "MD5"
req.sign = sign.md5(req, opt.apikey)
else
opt.sign_type = "HMAC-SHA256"
req.sign_type = "HMAC-SHA256"
req.sign = sign.hmac_sha256(req, opt.apikey)
end
local code, response = httpc.raw { domain = micro.domains[1] .. '/pay/micropay', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
if code ~= 200 then
if code == nil then
code, response = httpc.raw { domain = micro.domains[2] .. '/pay/micropay', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
end
if code ~= 200 then
return nil, response
end
end
-- print(response)
response = xml2lua.parser(response)
if type(response) ~= 'table' then
return nil, "invalide response"
end
-- var_dump(response)
response = response['xml']
if response['result_code'] ~= 'SUCCESS' then
return nil, micro.error_format(response)
end
-- 签名验证
return micro.sign_varify(opt, req, response)
end
return micro
--[[
微信支付SDK v0.1
(Native)扫码支付
]]
local httpc = require "httpc"
local xml2lua = require "xml2lua"
local domains = require "cloud.wechat.domains"
local sign = require "cloud.wechat.sign"
local order = require "cloud.wechat.order"
local type = type
local next = next
-- 验证域名是否规范
local function is_domain(URI)
if not URI or URI == '' then
return nil
end
return string.find(URI, "http[s]://[^/]+/.*")
end
local native = { __Version__ = 0.1, domains = domains }
-- 验证请求返回签名(请勿在外部调用)
native.sign_varify = sign.sign_varify
-- 出错信息格式化(请勿在外部调用)
native.error_format = sign.error_format
-- 查询订单
native.native_query = order.query
-- 关闭订单
native.native_close = order.close
-- 退款
native.refund = order.refund
-- 退款查询
native.refund_query = order.refund_query
--[[
1. NATIVE(扫码)支付下单
appid -- 公众号APPID,
apikey -- API KEY,
mch_id -- 支付商户号,
amount -- 支付金额(分),
amount_type -- 币种(默认CNY),
trade_no -- 支付订单号,
describe -- 商品描述,
opt.ip -- 指定客户端IP(当前版本可不指定)
sign_type -- 签名类型(MD5/HMAC-SHA256),
notify_url -- 交易成功的回调地址,
receipt -- 电子发票入口开放标识,
limit_pay -- limit_pay == true 则不允许信用卡支付,
]]
function native.native_pay( opt )
assert(type(opt) == 'table' and next(opt), "invalide parameters.")
-- appid 必须是string类型并且不能为空
assert(type(opt.appid) == 'string' and opt.appid ~= '', "invalide appid.")
-- apikey 必须是string类型并且不能为空
assert(type(opt.apikey) == 'string' and opt.apikey ~= '', "invalide apikey.")
-- mch_id 必须是string类型并且不能为空
assert(type(opt.mch_id) == 'string' and opt.mch_id ~= '', "invalide mch_id.")
-- trade_no 必须是string类型并且不能为空
assert(type(opt.trade_no) == 'string' and opt.trade_no ~= '', "invalide trade_no.")
-- product_id 必须是string类型并且不能为空
-- assert((type(opt.product_id) == 'string' or tonumber(opt.product_id)) and opt.product_id ~= '', "invalide product_id.")
-- describe 必须是string类型并且不能为空
assert(type(opt.describe) == 'string' and opt.describe ~= '', "invalide describe.")
-- sign_type 必须是HMAC-SHA256或者MD5其中一个
assert(opt.sign_type == 'HMAC-SHA256' or opt.sign_type == 'MD5', "invalide sign_type(need HMAC-SHA256 or MD5).")
-- notify_url 必须是一个可以正确回应的微信支付后回调的url
assert(type(opt.notify_url) == 'string' and is_domain(opt.notify_url), "invalide notify_url.")
-- amount 必须是是整数类型
assert(math.tointeger(opt.amount), "invalide amoun.")
-- 初始化参数
local req = {
appid = opt.appid,
mch_id = opt.mch_id,
total_fee = opt.amount,
product_id = opt.product_id,
fee_type = opt.amount_type or "CNY",
nonce_str = sign.gen_nonce(),
trade_type = "NATIVE",
out_trade_no = opt.trade_no,
body = opt.describe,
receipt = opt.receipt and "Y" or nil,
notify_url = opt.notify_url,
limit_pay = opt.limit_pay and "no_credit" or nil,
spbill_create_ip = opt.ip,
attach = opt.customize,
}
-- 签名
local sign_str = nil
if opt.sign_type == 'MD5' then
opt.sign_type = "MD5"
req.sign_type = "MD5"
req.sign = sign.md5(req, opt.apikey)
else
opt.sign_type = "HMAC-SHA256"
req.sign_type = "HMAC-SHA256"
req.sign = sign.hmac_sha256(req, opt.apikey)
end
local code, response = httpc.raw { domain = native.domains[1] .. '/pay/unifiedorder', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
if code ~= 200 then
if code == nil then
code, response = httpc.raw { domain = native.domains[2] .. '/pay/unifiedorder', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
end
if code ~= 200 then
return nil, response
end
end
-- print(response)
response = xml2lua.parser(response)
if type(response) ~= 'table' then
return nil, "invalide response"
end
-- var_dump(response)
response = response['xml']
if response['result_code'] ~= 'SUCCESS' then
return nil, native.error_format(response)
end
-- 签名验证
return native.sign_varify(opt, req, response)
end
--[[
2. NATIVE回调通知内容验证
response -- 回调内容
apikey -- API KEY
]]
native.native_notice_varify = sign.notice_varify
return native
--[[
微信支付SDK v0.1
(Native)扫码支付
]]
local httpc = require "httpc"
local xml2lua = require "xml2lua"
local sign = require "cloud.wechat.sign"
local domains = require "cloud.wechat.domains"
local type = type
local next = next
local assert = assert
local order = { __Version__ = 0.1, domains = domains }
-- 验证请求返回签名(请勿在外部调用)
order.sign_varify = sign.sign_varify
-- 出错信息格式化(请勿在外部调用)
order.error_format = sign.error_format
--[[
1. 查询order订单
appid -- 微信支付分配的公众账号ID(企业号corpid即为此appId)
mch_id -- 微信支付分配的商户号
out_trade_no -- 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。 详见商户订单号
nonce_str -- 随机字符串,不长于32位。推荐随机数生成算法
sign -- 通过签名算法计算得出的签名值,详见签名生成算法
sign_type -- HMAC-SHA256 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
]]
function order.query( opt )
assert(type(opt) == 'table' and next(opt), "Invalid parameters.")
-- appid 必须是string类型并且不能为空
assert(type(opt.appid) == 'string' and opt.appid ~= '', "Invalid appid")
-- apikey 必须是string类型并且不能为空
assert(type(opt.apikey) == 'string' and opt.apikey ~= '', "Invalid apikey")
-- mch_id 必须是string类型并且不能为空
assert(type(opt.mch_id) == 'string' and opt.mch_id ~= '', "Invalid mch_id")
-- trade_no 必须是string类型并且不能为空
assert(type(opt.trade_no) == 'string' and opt.trade_no ~= '', "Invalid trade_no")
local req = {
appid = opt.appid,
mch_id = opt.mch_id,
out_trade_no = opt.trade_no,
nonce_str = sign.gen_nonce(),
}
-- 签名
if opt.sign_type == 'MD5' then
opt.sign_type = "MD5"
req.sign_type = "MD5"
req.sign = sign.md5(req, opt.apikey)
else
opt.sign_type = "HMAC-SHA256"
req.sign_type = "HMAC-SHA256"
req.sign = sign.hmac_sha256(req, opt.apikey)
end
local code, response = httpc.raw { domain = order.domains[1] .. '/pay/orderquery', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
if code ~= 200 then
if code == nil then
code, response = httpc.raw { domain = order.domains[2] .. '/pay/orderquery', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
end
if code ~= 200 then
return nil, response
end
end
-- print(response)
response = xml2lua.parser(response)
if type(response) ~= 'table' then
return nil, "Invalid response"
end
-- var_dump(response)
response = response['xml']
if response['result_code'] ~= 'SUCCESS' then
return nil, order.error_format(response)
end
-- 签名验证
return order.sign_varify(opt, req, response, opt.apikey)
end
--[[
2. 关闭order订单
appid -- 微信支付分配的公众账号ID(企业号corpid即为此appId)
mch_id -- 微信支付分配的商户号
out_trade_no -- 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。 详见商户订单号
nonce_str -- 随机字符串,不长于32位。推荐随机数生成算法
sign -- 通过签名算法计算得出的签名值,详见签名生成算法
sign_type -- HMAC-SHA256 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
]]
function order.close( opt )
assert(type(opt) == 'table' and next(opt), "Invalid parameters.")
-- appid 必须是string类型并且不能为空
assert(type(opt.appid) == 'string' and opt.appid ~= '', "Invalid appid")
-- apikey 必须是string类型并且不能为空
assert(type(opt.apikey) == 'string' and opt.apikey ~= '', "Invalid apikey")
-- mch_id 必须是string类型并且不能为空
assert(type(opt.mch_id) == 'string' and opt.mch_id ~= '', "Invalid mch_id")
-- trade_no 必须是string类型并且不能为空
assert(type(opt.trade_no) == 'string' and opt.trade_no ~= '', "Invalid trade_no")
local req = {
appid = opt.appid,
mch_id = opt.mch_id,
nonce_str = sign.gen_nonce(),
out_trade_no = opt.trade_no,
}
-- 签名
if opt.sign_type == 'MD5' then
opt.sign_type = "MD5"
req.sign_type = "MD5"
req.sign = sign.md5(req, opt.apikey)
else
opt.sign_type = "HMAC-SHA256"
req.sign_type = "HMAC-SHA256"
req.sign = sign.hmac_sha256(req, opt.apikey)
end
local code, response = httpc.raw { domain = order.domains[1] .. '/pay/closeorder', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
if code ~= 200 then
if code == nil then
code, response = httpc.raw { domain = order.domains[2] .. '/pay/closeorder', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
end
if code ~= 200 then
return nil, response
end
end
-- print(response)
response = xml2lua.parser(response)
if type(response) ~= 'table' then
return nil, "Invalid response"
end
-- var_dump(response)
response = response['xml']
if response['result_code'] ~= 'SUCCESS' then
return nil, order.error_format(response)
end
-- 签名验证
return order.sign_varify(opt, req, response, opt.apikey)
end
--[[
3. 退款订单
appid -- 微信支付分配的公众账号ID(企业号corpid即为此appId)
mch_id -- 微信支付分配的商户号
out_trade_no -- 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。 详见商户订单号
nonce_str -- 随机字符串,不长于32位。推荐随机数生成算法
sign -- 通过签名算法计算得出的签名值,详见签名生成算法
sign_type -- HMAC-SHA256 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
]]
function order.refund( opt )
assert(type(opt) == 'table' and next(opt), "Invalid parameters.")
-- appid 必须是string类型并且不能为空
assert(type(opt.appid) == 'string' and opt.appid ~= '', "Invalid appid")
-- apikey 必须是string类型并且不能为空
assert(type(opt.apikey) == 'string' and opt.apikey ~= '', "Invalid apikey")
-- mch_id 必须是string类型并且不能为空
assert(type(opt.mch_id) == 'string' and opt.mch_id ~= '', "Invalid mch_id")
-- 订单金额必须为正整数
assert(math.tointeger(opt.order_amount) and math.tointeger(opt.order_amount) > 0, "Invalid amount.")
-- 退款金额必须为正整数
assert(math.tointeger(opt.refund_amount) and math.tointeger(opt.refund_amount) > 0, "Invalid amount.")
-- API 证书
assert(type(opt.cert_path) == 'string' and opt.cert_path ~= '', "Invalid API cert file")
-- API 私钥
assert(type(opt.key_path) == 'string' and opt.key_path ~= '', "Invalid API private key")
local req = {
appid = opt.appid,
mch_id = opt.mch_id,
nonce_str = sign.gen_nonce(),
transaction_id = opt.transaction_id,
out_refund_no = opt.refund_no,
out_trade_no = opt.trade_no,
total_fee = opt.order_amount,
refund_fee = opt.refund_amount,
refund_fee_type = opt.refund_type or "CNY",
refund_account = opt.refund_account or "REFUND_SOURCE_RECHARGE_FUNDS",
refund_desc = opt.refund_desc or nil,
notify_url = opt.notify_url or nil,
}
-- 签名
if opt.sign_type == 'MD5' then
opt.sign_type = "MD5"
req.sign_type = "MD5"
req.sign = sign.md5(req, opt.apikey)
else
opt.sign_type = "HMAC-SHA256"
req.sign_type = "HMAC-SHA256"
req.sign = sign.hmac_sha256(req, opt.apikey)
end
var_dump(req)
local code, response = httpc.raw { domain = order.domains[1] .. '/secapi/pay/refund', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml"), cert_path = opt.cert_path, key_path = opt.key_path }
if code ~= 200 then
if code == nil then
code, response = httpc.raw { domain = order.domains[2] .. '/secapi/pay/refund', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml"), cert_path = opt.cert_path, key_path = opt.key_path }
end
if code ~= 200 then
return nil, response
end
end
-- print(response)
response = xml2lua.parser(response)
if type(response) ~= 'table' then
return nil, "Invalid response"
end
-- var_dump(response)
response = response['xml']
if response['result_code'] ~= 'SUCCESS' then
return nil, order.error_format(response)
end
-- 签名验证
return order.sign_varify(opt, req, response, opt.apikey)
end
--[[
4. 退款查询
appid -- 微信支付分配的公众账号ID(企业号corpid即为此appId)
mch_id -- 微信支付分配的商户号
out_trade_no -- 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。 详见商户订单号
nonce_str -- 随机字符串,不长于32位。推荐随机数生成算法
sign -- 通过签名算法计算得出的签名值,详见签名生成算法
sign_type -- HMAC-SHA256 签名类型,目前支持HMAC-SHA256和MD5(默认为MD5)
]]
function order.refund_query( opt )
assert(type(opt) == 'table' and next(opt), "Invalid parameters.")
-- appid 必须是string类型并且不能为空
assert(type(opt.appid) == 'string' and opt.appid ~= '', "Invalid appid")
-- apikey 必须是string类型并且不能为空
assert(type(opt.apikey) == 'string' and opt.apikey ~= '', "Invalid apikey")
-- mch_id 必须是string类型并且不能为空
assert(type(opt.mch_id) == 'string' and opt.mch_id ~= '', "Invalid mch_id")
local req = {
appid = opt.appid,
mch_id = opt.mch_id,
nonce_str = sign.gen_nonce(),
transaction_id = opt.transaction_id,
out_refund_no = opt.refund_no,
out_refund_id = opt.refund_id,
out_trade_no = opt.trade_no,
offset = math.tointeger(opt.offset) and opt.offset or nil,
}
-- 签名
if opt.sign_type == 'MD5' then
opt.sign_type = "MD5"
req.sign_type = "MD5"
req.sign = sign.md5(req, opt.apikey)
else
opt.sign_type = "HMAC-SHA256"
req.sign_type = "HMAC-SHA256"
req.sign = sign.hmac_sha256(req, opt.apikey)
end
local code, response = httpc.raw { domain = order.domains[1] .. '/pay/refundquery', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
if code ~= 200 then
if code == nil then
code, response = httpc.raw { domain = order.domains[2] .. '/pay/refundquery', method = "POST", headers = {{ "Content-Type", "application/xml;"}}, body = xml2lua.toxml(req, "xml") }
end
if code ~= 200 then
return nil, response
end
end
-- print(response)
response = xml2lua.parser(response)
if type(response) ~= 'table' then
return nil, "Invalid response"
end
-- var_dump(response)
response = response['xml']
if response['result_code'] ~= 'SUCCESS' then
return nil, order.error_format(response)
end
-- 签名验证
return order.sign_varify(opt, req, response, opt.apikey)
end
return order
local crypt = require "crypt"
local uuid = crypt.uuid
local md5 = crypt.md5
local hmac_sha256 = crypt.hmac_sha256
local xml = require "xml2lua"
local type = type
local pairs = pairs
local ipairs = ipairs
local fmt = string.format
local table_sort = table.sort
local table_concat = table.concat
-- 进行key排序
local function key_sort(opt)
local keys = {}
for key, value in pairs(opt) do
if key ~= '' and value ~= '' and key ~= 'sign' then
keys[#keys+1] = key
end
end
table_sort(keys)
return keys
end
-- 进行key连接
local function key_concat(keys, opt, apikey)
local parameters = {}
for _, k in ipairs(keys) do
parameters[#parameters+1] = fmt("%s=%s", k, opt[k])
end
parameters[#parameters+1] = "key=" .. apikey
return parameters
end
-- 微信支付的HMAC_SHA256签名方法
local function hmac_sha256_sign(opt, apikey)
-- 1. 首先对所有参数进行排序
local keys = key_sort(opt)
-- 2. 对排序后的字段进行拼接
local parameters = key_concat(keys, opt, apikey)
-- 3. 使用hmac_sha256对参数结果与apikey进行签名, 最后将签名的结果大写化
return hmac_sha256(apikey, table_concat(parameters, "&"), true):upper()
end
-- 微信支付的MD5签名方法
local function hmac_md5_sign(opt, apikey)
-- 1. 首先对所有参数进行排序
local keys = key_sort(opt)
-- 2. 对排序后的字段进行拼接
local parameters = key_concat(keys, opt, apikey)
-- 3. 使用md5对参数结果进行签名, 最后将签名的结果大写化.
return md5(table_concat(parameters, "&"), true):upper()
end
-- 回调签名验证
local function notice_varify(response, apikey)
if type(response) ~= 'table' or type(apikey) ~= 'string' then
return nil, "invalide response or apikey"
end
if response["xml"] then
response = xml.parser(response["body"])["xml"]
end
local sign_str = response.sign
response.sign = nil
if response.sign_type == 'MD5' and sign_str ~= hmac_md5_sign(response, apikey) then
return nil, "notice: MD5签名验证失败"
elseif response.sign_type == 'HMAC-SHA256' and sign_str ~= hmac_sha256_sign(response, apikey) then
return nil, "notice: HMAC-SHA256签名验证失败"
elseif not response.sign_type and sign_str ~= hmac_md5_sign(response, apikey) then
return nil, "notice: (None)MD5签名验证失败"
end
response.sign = sign_str
return response
end
-- 回应验证签名
local function sign_varify(opt, request, response)
local sign_str = response.sign
response.sign = nil
if request.sign_type == 'MD5' and sign_str ~= hmac_md5_sign(response, opt.apikey) then
return nil, "Sign : MD5签名验证失败"
elseif request.sign_type == 'HMAC-SHA256' and sign_str ~= hmac_sha256_sign(response, opt.apikey) then
return nil, "Sign : HMAC-SHA256签名验证失败"
end
response.sign = sign_str
return response
end
-- 出错信息格式化
local function error_format(response)
return fmt('["%s", "%s", "%s", "%s"]',
response['return_code'] or "unknown",
response['return_msg'] or "unknown",
response['err_code'] or "unknown",
response['err_code_des'] or "unknown"
)
end
-- 生成Nonce_str
local function gen_nonce()
return md5(uuid(), true)
end
return {
gen_nonce = gen_nonce,
sign_varify = sign_varify,
notice_varify = notice_varify,
error_format = error_format,
md5 = hmac_md5_sign,
hmac_sha256 = hmac_sha256_sign,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment