123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- # -*- coding: utf-8 -*-
- from __future__ import absolute_import, unicode_literals
- from library.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,
- },
- )
|