# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
from wechatpy.client.api.base import BaseWeChatAPI
[文档]class WeChatInvoice(BaseWeChatAPI):
API_BASE_URL = 'https://api.weixin.qq.com/card/invoice/'
[文档] def get_url(self):
"""
获取自身开票平台专用的授权链接
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1496561481_1TyO7
:return:该开票平台专用的授权链接
"""
return self._post(
'seturl',
data={},
result_processor=lambda x: x['invoice_url'],
)
[文档] def create_card(self, base_info, payee, invoice_type, detail=None):
"""
创建发票卡券模板
注意这里的对象和会员卡有类似之处,但是含义有不同。创建发票卡券模板是创建发票卡券的基础。
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1496561481_1TyO7
:param base_info:发票卡券模板基础信息
:type base_info: dict
:param payee: 收款方(开票方)全称,显示在发票详情内。建议一个收款方对应一个发票卡券模板
:param invoice_type: 发票类型描述
:param detail: 备注详情
:return: 发票卡券模板的编号,用于后续该商户发票生成后,作为必填参数在调用插卡接口时传入
"""
return self._post(
'platform/createcard',
data={
'invoice_info': {
'base_info': base_info,
'payee': payee,
'type': invoice_type,
'detail': detail,
},
},
result_processor=lambda x: x['card_id'],
)
[文档] def get_auth_url(self, s_pappid, order_id, money, timestamp, source, ticket, auth_type, redirect_url=None):
"""
获取授权页链接
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
:param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供
:param order_id: 订单id,在商户内单笔开票请求的唯一识别号
:param money: 订单金额,以分为单位
:type money: int
:param timestamp: Unix 时间戳
:type timestamp: int
:param source: 开票来源。app: App开票, web: 微信H5开票, wap: 普通网页开票
:param ticket: 根据获取授权ticket接口取得
:param auth_type: 授权类型。0: 开票授权,1: 填写字段开票授权,2: 领票授权
:type auth_type: int
:param redirect_url: 授权成功后跳转页面。本字段只有在source为H5的时候需要填写。
:return: 获取授权页链接
"""
if source not in {'app', 'web', 'wap'}:
raise ValueError('Unsupported source. Valid sources are "app", "web" or "wap"')
if source == 'web' and redirect_url is None:
raise ValueError('redirect_url is required if source is web')
if not (0 <= auth_type <= 2):
raise ValueError('Unsupported auth type. Valid auth types are 0, 1 or 2')
return self._post(
'getauthurl',
data={
's_pappid': s_pappid,
'order_id': order_id,
'money': money,
'timestamp': timestamp,
'source': source,
'ticket': ticket,
'type': auth_type,
'redirect_url': redirect_url,
},
result_processor=lambda x: x['auth_url'],
)
[文档] def set_auth_field(self, user_field, biz_field):
"""
设置授权页字段信息
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
:param user_field: 授权页个人发票字段
:type user_field: dict
:param biz_field: 授权页单位发票字段
:type biz_field: dict
"""
return self._post(
'setbizattr',
params={
'action': 'set_auth_field',
},
data={
'auth_field': {
'user_field': user_field,
'biz_field': biz_field,
},
},
)
[文档] def get_auth_field(self):
"""
获取授权页字段信息
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
:return: 授权页的字段设置
:rtype: dict
"""
return self._post(
'setbizattr',
params={
'action': 'get_auth_field',
},
data={},
)
[文档] def get_auth_data(self, s_pappid, order_id):
"""
查询授权数据
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
:param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供
:param order_id: 订单id,在商户内单笔开票请求的唯一识别号
:return: 用户的开票信息
:rtype: dict
"""
return self._post(
'getauthdata',
data={
's_pappid': s_pappid,
'order_id': order_id,
},
)
[文档] def reject_insert(self, s_pappid, order_id, reason, redirect_url=None):
"""
拒绝用户的开发票请求
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
:param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供
:param order_id: 订单id,在商户内单笔开票请求的唯一识别号
:param reason: 拒绝原因
:param redirect_url: 跳转链接
"""
return self._post(
'rejectinsert',
data={
's_pappid': s_pappid,
'order_id': order_id,
'reason': reason,
'url': redirect_url,
},
)
[文档] def insert(self, order_id, card_id, appid, card_ext):
"""
制作发票卡券,并放入用户卡包
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
:param order_id: 订单id,在商户内单笔开票请求的唯一识别号
:param card_id: 发票卡券模板的编号
:param appid: 商户 AppID
:param card_ext: 发票具体内容
:type card_ext: dict
:return: 随机防重字符串,以及用户 Open ID
"""
return self._post(
'insert',
data={
'order_id': order_id,
'card_id': card_id,
'appid': appid,
'card_ext': card_ext,
},
)
[文档] def upload_pdf(self, pdf):
"""
上传电子发票中的消费凭证 PDF
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
:param pdf: 要上传的 PDF 文件,一个 File-object
:return: 64位整数,在将发票卡券插入用户卡包时使用用于关联pdf和发票卡券。有效期为3天。
"""
return self._post(
'platform/setpdf',
files={
'pdf': pdf,
},
result_processor=lambda x: x['s_media_id'],
)
[文档] def get_pdf(self, s_media_id):
"""
查询已上传的 PDF
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
:param s_media_id: PDF 文件上传时的 s_media_id
:return: PDF 文件的 URL,以及过期时间
:rtype: dict
"""
return self._post(
'platform/getpdf',
params={
'action': 'get_url',
},
data={
's_media_id': s_media_id,
},
)
[文档] def update_status(self, card_id, code, reimburse_status):
"""
更新发票卡券的状态
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
:param card_id: 发票卡券模板的编号
:param code: 发票卡券的编号
:param reimburse_status: 发票报销状态
"""
return self._post(
'platform/updatestatus',
data={
'card_id': card_id,
'code': code,
'reimburse_status': reimburse_status,
},
)
[文档] def set_pay_mch(self, mchid, s_pappid):
"""
关联商户号与开票平台,设置支付后开票
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1496561731_2Z55U
:param mchid: 微信支付商户号
:param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供
"""
return self._post(
'setbizattr',
params={
'action': 'set_pay_mch',
},
data={
'paymch_info': {
'mchid': mchid,
's_pappid': s_pappid,
},
},
)
[文档] def get_pay_mch(self):
"""
查询商户号与开票平台关联情况
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1496561731_2Z55U
:return: mchid 和 s_pappid
:rtype: dict
"""
return self._post(
'setbizattr',
params={
'action': 'get_pay_mch',
},
data={},
)
[文档] def get_reimburse(self, card_id, encrypt_code):
"""
报销方查询发票信息
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1496561749_f7T6D
:param card_id: 发票卡券的 Card ID
:param encrypt_code: 发票卡券的加密 Code
:return: 电子发票的结构化信息
:rtype: dict
"""
return self._post(
'reimburse/getinvoiceinfo',
data={
'card_id': card_id,
'encrypt_code': encrypt_code,
},
)
[文档] def update_reimburse(self, card_id, encrypt_code, reimburse_status):
"""
报销方更新发票信息
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1496561749_f7T6D
:param card_id: 发票卡券的 Card ID
:param encrypt_code: 发票卡券的加密 Code
:param reimburse_status: 发票报销状态
"""
return self._post(
'reimburse/updateinvoicestatus',
data={
'card_id': card_id,
'encrypt_code': encrypt_code,
'reimburse_status': reimburse_status,
},
)
[文档] def batch_update_reimburse(self, openid, reimburse_status, invoice_list):
"""
报销方批量更新发票信息
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1496561749_f7T6D
:param openid: 用户的 Open ID
:param reimburse_status: 发票报销状态
:param invoice_list: 发票列表
:type invoice_list: list[dict]
"""
return self._post(
'reimburse/updatestatusbatch',
data={
'openid': openid,
'reimburse_status': reimburse_status,
'invoice_list': invoice_list,
},
)
[文档] def get_user_title_url(
self, user_fill, title=None, phone=None, tax_no=None, addr=None, bank_type=None, bank_no=None,
out_title_id=None):
"""
获取添加发票链接
获取链接,发送给用户。用户同意以后,发票抬头信息将会录入到用户微信中
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1496554912_vfWU0
:param user_fill: 企业设置抬头为0,用户自己填写抬头为1
:type user_fill: bool
:param title: 抬头,当 user_fill 为 False 时必填
:param phone: 联系方式
:param tax_no: 税号
:param addr: 地址
:param bank_type: 银行类型
:param bank_no: 银行号码
:param out_title_id: 开票码
:return: 添加发票的链接
"""
if user_fill and title is None:
raise ValueError('title is required when user_fill is False')
return self._post(
'biz/getusertitleurl',
data={
'user_fill': int(user_fill),
'title': title,
'phone': phone,
'tax_no': tax_no,
'addr': addr,
'bank_type': bank_type,
'bank_no': bank_no,
'out_title_id': out_title_id,
},
result_processor=lambda x: x['url'],
)
[文档] def get_select_title_url(self, attach=None):
"""
获取商户专属开票链接
商户调用接口,获取链接。用户扫码,可以选择抬头发给商户。可以将链接转成二维码,立在收银台。
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1496554912_vfWU0
:param attach: 附加字段,用户提交发票时会发送给商户
:return: 商户专属开票链接
"""
return self._post(
'biz/getselecttitleurl',
data={
'attach': attach,
},
result_processor=lambda x: x['url'],
)
[文档] def scan_title(self, scan_text):
"""
根据扫描码,获取用户发票抬头
商户扫用户“我的—个人信息—我的发票抬头”里面的抬头二维码后,通过调用本接口,可以获取用户抬头信息
详情请参考
https://mp.weixin.qq.com/wiki?id=mp1496554912_vfWU0
:param scan_text: 扫码后获取的文本
:return: 用户的发票抬头数据
:rtype: dict
"""
return self._post(
'scantitle',
data={
'scan_text': scan_text,
},
)