wechatpy.client.api.invoice   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 418
Duplicated Lines 0 %

Test Coverage

Coverage 46%

Importance

Changes 0
Metric Value
eloc 159
dl 0
loc 418
rs 9.92
c 0
b 0
f 0
ccs 23
cts 50
cp 0.46
wmc 31

19 Methods

Rating   Name   Duplication   Size   Complexity  
A WeChatInvoice.get_auth_data() 0 16 1
A WeChatInvoice.upload_pdf() 0 15 2
A WeChatInvoice.batch_update_reimburse() 0 17 1
A WeChatInvoice.get_reimburse() 0 16 1
A WeChatInvoice.get_pdf() 0 17 1
A WeChatInvoice.scan_title() 0 15 1
B WeChatInvoice.get_auth_url() 0 38 6
A WeChatInvoice.update_reimburse() 0 16 1
A WeChatInvoice.get_select_title_url() 0 16 2
A WeChatInvoice.update_status() 0 16 1
A WeChatInvoice.get_url() 0 12 2
A WeChatInvoice.insert() 0 20 1
A WeChatInvoice.reject_insert() 0 18 1
A WeChatInvoice.get_pay_mch() 0 15 1
A WeChatInvoice.get_user_title_url() 0 35 4
A WeChatInvoice.get_auth_field() 0 15 1
A WeChatInvoice.create_card() 0 25 2
A WeChatInvoice.set_auth_field() 0 20 1
A WeChatInvoice.set_pay_mch() 0 18 1
1
# -*- coding: utf-8 -*-
2 10
from __future__ import absolute_import, unicode_literals
3
4 10
from wechatpy.client.api.base import BaseWeChatAPI
5
6
7 10
class WeChatInvoice(BaseWeChatAPI):
8 10
    API_BASE_URL = 'https://api.weixin.qq.com/card/invoice/'
9
10 10
    def get_url(self):
11
        """
12
        获取自身开票平台专用的授权链接
13
        详情请参考
14
        https://mp.weixin.qq.com/wiki?id=mp1496561481_1TyO7
15
16
        :return:该开票平台专用的授权链接
17
        """
18
        return self._post(
19
            'seturl',
20
            data={},
21
            result_processor=lambda x: x['invoice_url'],
22
        )
23
24 10
    def create_card(self, base_info, payee, invoice_type, detail=None):
25
        """
26
        创建发票卡券模板
27
        注意这里的对象和会员卡有类似之处,但是含义有不同。创建发票卡券模板是创建发票卡券的基础。
28
        详情请参考
29
        https://mp.weixin.qq.com/wiki?id=mp1496561481_1TyO7
30
31
        :param base_info:发票卡券模板基础信息
32
        :type base_info: dict
33
        :param payee: 收款方(开票方)全称,显示在发票详情内。建议一个收款方对应一个发票卡券模板
34
        :param invoice_type: 发票类型描述
35
        :param detail: 备注详情
36
        :return: 发票卡券模板的编号,用于后续该商户发票生成后,作为必填参数在调用插卡接口时传入
37
        """
38
        return self._post(
39
            'platform/createcard',
40
            data={
41
                'invoice_info': {
42
                    'base_info': base_info,
43
                    'payee': payee,
44
                    'type': invoice_type,
45
                    'detail': detail,
46
                },
47
            },
48
            result_processor=lambda x: x['card_id'],
49
        )
50
51 10
    def get_auth_url(self, s_pappid, order_id, money, timestamp, source, ticket, auth_type, redirect_url=None):
52
        """
53
        获取授权页链接
54
        详情请参考
55
        https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
56
57
        :param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供
58
        :param order_id: 订单id,在商户内单笔开票请求的唯一识别号
59
        :param money: 订单金额,以分为单位
60
        :type money: int
61
        :param timestamp: Unix 时间戳
62
        :type timestamp: int
63
        :param source: 开票来源。app: App开票, web: 微信H5开票, wap: 普通网页开票
64
        :param ticket: 根据获取授权ticket接口取得
65
        :param auth_type: 授权类型。0: 开票授权,1: 填写字段开票授权,2: 领票授权
66
        :type auth_type: int
67
        :param redirect_url: 授权成功后跳转页面。本字段只有在source为H5的时候需要填写。
68
        :return: 获取授权页链接
69
        """
70
        if source not in {'app', 'web', 'wap'}:
71
            raise ValueError('Unsupported source. Valid sources are "app", "web" or "wap"')
72
        if source == 'web' and redirect_url is None:
73
            raise ValueError('redirect_url is required if source is web')
74
        if not (0 <= auth_type <= 2):
75
            raise ValueError('Unsupported auth type. Valid auth types are 0, 1 or 2')
76
        return self._post(
77
            'getauthurl',
78
            data={
79
                's_pappid': s_pappid,
80
                'order_id': order_id,
81
                'money': money,
82
                'timestamp': timestamp,
83
                'source': source,
84
                'ticket': ticket,
85
                'type': auth_type,
86
                'redirect_url': redirect_url,
87
            },
88
            result_processor=lambda x: x['auth_url'],
89
        )
90
91 10
    def set_auth_field(self, user_field, biz_field):
92
        """
93
        设置授权页字段信息
94
        详情请参考
95
        https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
96
97
        :param user_field: 授权页个人发票字段
98
        :type user_field: dict
99
        :param biz_field: 授权页单位发票字段
100
        :type biz_field: dict
101
        """
102
        return self._post(
103
            'setbizattr',
104
            params={
105
                'action': 'set_auth_field',
106
            },
107
            data={
108
                'auth_field': {
109
                    'user_field': user_field,
110
                    'biz_field': biz_field,
111
                },
112
            },
113
        )
114
115 10
    def get_auth_field(self):
116
        """
117
        获取授权页字段信息
118
        详情请参考
119
        https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
120
121
        :return: 授权页的字段设置
122
        :rtype: dict
123
        """
124
        return self._post(
125
            'setbizattr',
126
            params={
127
                'action': 'get_auth_field',
128
            },
129
            data={},
130
        )
131
132 10
    def get_auth_data(self, s_pappid, order_id):
133
        """
134
        查询授权数据
135
        详情请参考
136
        https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
137
138
        :param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供
139
        :param order_id: 订单id,在商户内单笔开票请求的唯一识别号
140
        :return: 用户的开票信息
141
        :rtype: dict
142
        """
143
        return self._post(
144
            'getauthdata',
145
            data={
146
                's_pappid': s_pappid,
147
                'order_id': order_id,
148
            },
149
        )
150
151 10
    def reject_insert(self, s_pappid, order_id, reason, redirect_url=None):
152
        """
153
        拒绝用户的开发票请求
154
        详情请参考
155
        https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
156
157
        :param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供
158
        :param order_id: 订单id,在商户内单笔开票请求的唯一识别号
159
        :param reason: 拒绝原因
160
        :param redirect_url: 跳转链接
161
        """
162
        return self._post(
163
            'rejectinsert',
164
            data={
165
                's_pappid': s_pappid,
166
                'order_id': order_id,
167
                'reason': reason,
168
                'url': redirect_url,
169
            },
170
        )
171
172 10
    def insert(self, order_id, card_id, appid, card_ext):
173
        """
174
        制作发票卡券,并放入用户卡包
175
        详情请参考
176
        https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
177
178
        :param order_id: 订单id,在商户内单笔开票请求的唯一识别号
179
        :param card_id: 发票卡券模板的编号
180
        :param appid: 商户 AppID
181
        :param card_ext: 发票具体内容
182
        :type card_ext: dict
183
        :return: 随机防重字符串,以及用户 Open ID
184
        """
185
        return self._post(
186
            'insert',
187
            data={
188
                'order_id': order_id,
189
                'card_id': card_id,
190
                'appid': appid,
191
                'card_ext': card_ext,
192
            },
193
        )
194
195 10
    def upload_pdf(self, pdf):
196
        """
197
        上传电子发票中的消费凭证 PDF
198
        详情请参考
199
        https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
200
201
        :param pdf: 要上传的 PDF 文件,一个 File-object
202
        :return: 64位整数,在将发票卡券插入用户卡包时使用用于关联pdf和发票卡券。有效期为3天。
203
        """
204
        return self._post(
205
            'platform/setpdf',
206
            files={
207
                'pdf': pdf,
208
            },
209
            result_processor=lambda x: x['s_media_id'],
210
        )
211
212 10
    def get_pdf(self, s_media_id):
213
        """
214
        查询已上传的 PDF
215
        详情请参考
216
        https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
217
218
        :param s_media_id: PDF 文件上传时的 s_media_id
219
        :return: PDF 文件的 URL,以及过期时间
220
        :rtype: dict
221
        """
222
        return self._post(
223
            'platform/getpdf',
224
            params={
225
                'action': 'get_url',
226
            },
227
            data={
228
                's_media_id': s_media_id,
229
            },
230
        )
231
232 10
    def update_status(self, card_id, code, reimburse_status):
233
        """
234
        更新发票卡券的状态
235
        详情请参考
236
        https://mp.weixin.qq.com/wiki?id=mp1497082828_r1cI2
237
238
        :param card_id: 发票卡券模板的编号
239
        :param code: 发票卡券的编号
240
        :param reimburse_status: 发票报销状态
241
        """
242
        return self._post(
243
            'platform/updatestatus',
244
            data={
245
                'card_id': card_id,
246
                'code': code,
247
                'reimburse_status': reimburse_status,
248
            },
249
        )
250
251 10
    def set_pay_mch(self, mchid, s_pappid):
252
        """
253
        关联商户号与开票平台,设置支付后开票
254
        详情请参考
255
        https://mp.weixin.qq.com/wiki?id=mp1496561731_2Z55U
256
257
        :param mchid: 微信支付商户号
258
        :param s_pappid: 开票平台在微信的标识号,商户需要找开票平台提供
259
        """
260
        return self._post(
261
            'setbizattr',
262
            params={
263
                'action': 'set_pay_mch',
264
            },
265
            data={
266
                'paymch_info': {
267
                    'mchid': mchid,
268
                    's_pappid': s_pappid,
269
                },
270
            },
271
        )
272
273 10
    def get_pay_mch(self):
274
        """
275
        查询商户号与开票平台关联情况
276
        详情请参考
277
        https://mp.weixin.qq.com/wiki?id=mp1496561731_2Z55U
278
279
        :return: mchid 和 s_pappid
280
        :rtype: dict
281
        """
282
        return self._post(
283
            'setbizattr',
284
            params={
285
                'action': 'get_pay_mch',
286
            },
287
            data={},
288
        )
289
290 10
    def get_reimburse(self, card_id, encrypt_code):
291
        """
292
        报销方查询发票信息
293
        详情请参考
294
        https://mp.weixin.qq.com/wiki?id=mp1496561749_f7T6D
295
296
        :param card_id: 发票卡券的 Card ID
297
        :param encrypt_code: 发票卡券的加密 Code
298
        :return: 电子发票的结构化信息
299
        :rtype: dict
300
        """
301
        return self._post(
302
            'reimburse/getinvoiceinfo',
303
            data={
304
                'card_id': card_id,
305
                'encrypt_code': encrypt_code,
306
            },
307
        )
308
309 10
    def update_reimburse(self, card_id, encrypt_code, reimburse_status):
310
        """
311
        报销方更新发票信息
312
        详情请参考
313
        https://mp.weixin.qq.com/wiki?id=mp1496561749_f7T6D
314
315
        :param card_id: 发票卡券的 Card ID
316
        :param encrypt_code: 发票卡券的加密 Code
317
        :param reimburse_status: 发票报销状态
318
        """
319
        return self._post(
320
            'reimburse/updateinvoicestatus',
321
            data={
322
                'card_id': card_id,
323
                'encrypt_code': encrypt_code,
324
                'reimburse_status': reimburse_status,
325
            },
326
        )
327
328 10
    def batch_update_reimburse(self, openid, reimburse_status, invoice_list):
329
        """
330
        报销方批量更新发票信息
331
        详情请参考
332
        https://mp.weixin.qq.com/wiki?id=mp1496561749_f7T6D
333
334
        :param openid: 用户的 Open ID
335
        :param reimburse_status: 发票报销状态
336
        :param invoice_list: 发票列表
337
        :type invoice_list: list[dict]
338
        """
339
        return self._post(
340
            'reimburse/updatestatusbatch',
341
            data={
342
                'openid': openid,
343
                'reimburse_status': reimburse_status,
344
                'invoice_list': invoice_list,
345
            },
346
        )
347
348 10
    def get_user_title_url(
349
            self, user_fill, title=None, phone=None, tax_no=None, addr=None, bank_type=None, bank_no=None,
350
            out_title_id=None):
351
        """
352
        获取添加发票链接
353
        获取链接,发送给用户。用户同意以后,发票抬头信息将会录入到用户微信中
354
        详情请参考
355
        https://mp.weixin.qq.com/wiki?id=mp1496554912_vfWU0
356
357
        :param user_fill: 企业设置抬头为0,用户自己填写抬头为1
358
        :type user_fill: bool
359
        :param title: 抬头,当 user_fill 为 False 时必填
360
        :param phone: 联系方式
361
        :param tax_no: 税号
362
        :param addr: 地址
363
        :param bank_type: 银行类型
364
        :param bank_no: 银行号码
365
        :param out_title_id: 开票码
366
        :return: 添加发票的链接
367
        """
368
        if user_fill and title is None:
369
            raise ValueError('title is required when user_fill is False')
370
        return self._post(
371
            'biz/getusertitleurl',
372
            data={
373
                'user_fill': int(user_fill),
374
                'title': title,
375
                'phone': phone,
376
                'tax_no': tax_no,
377
                'addr': addr,
378
                'bank_type': bank_type,
379
                'bank_no': bank_no,
380
                'out_title_id': out_title_id,
381
            },
382
            result_processor=lambda x: x['url'],
383
        )
384
385 10
    def get_select_title_url(self, attach=None):
386
        """
387
        获取商户专属开票链接
388
        商户调用接口,获取链接。用户扫码,可以选择抬头发给商户。可以将链接转成二维码,立在收银台。
389
        详情请参考
390
        https://mp.weixin.qq.com/wiki?id=mp1496554912_vfWU0
391
392
        :param attach: 附加字段,用户提交发票时会发送给商户
393
        :return: 商户专属开票链接
394
        """
395
        return self._post(
396
            'biz/getselecttitleurl',
397
            data={
398
                'attach': attach,
399
            },
400
            result_processor=lambda x: x['url'],
401
        )
402
403 10
    def scan_title(self, scan_text):
404
        """
405
        根据扫描码,获取用户发票抬头
406
        商户扫用户“我的—个人信息—我的发票抬头”里面的抬头二维码后,通过调用本接口,可以获取用户抬头信息
407
        详情请参考
408
        https://mp.weixin.qq.com/wiki?id=mp1496554912_vfWU0
409
410
        :param scan_text: 扫码后获取的文本
411
        :return: 用户的发票抬头数据
412
        :rtype: dict
413
        """
414
        return self._post(
415
            'scantitle',
416
            data={
417
                'scan_text': scan_text,
418
            },
419
        )
420