-
Notifications
You must be signed in to change notification settings - Fork 0
/
pandadocument.py
221 lines (194 loc) · 7.18 KB
/
pandadocument.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
"""pandadocument.py implements API Wrapper for Documents https://developers.pandadoc.com/reference#list-documents"""
__author__ = "Kostyantyn Ovechko"
__copyright__ = "Copyright 2020, Zxscript"
__license__ = "MIT"
__version__ = "0.0.1"
__email__ = "kos@zxscript.com"
__status__ = "Production"
from abc import ABC
from enum import Enum
from typing import List, Dict
from .panda_exceptions import ApiException
from .pandarecipient import Pandarecipient
class DocumentIdRequiredException(Exception):
pass
class PandaDocumentDoesNotExist(Exception):
pass
class PandaDocumentAbstract(ABC):
_pandaworkspace = None
def __init__(self, id_: str = None):
"""
:str id: - Id provided by Panda
"""
if id_ is None:
raise DocumentIdRequiredException()
self.__id = id_
@property
def id(self):
return self.__id
class Document(str, Enum):
draft = 0
sent = 1
completed = 2
viewed = 5
waiting_approval = 6
approved = 7
rejected = 8
waiting_pay = 9
paid = 10
voided = 11
declined = 12
@classmethod
def list(
cls,
q: str = None,
tag: str = None,
status_: Document = None,
count: int = None,
page: int = None,
metadata: str = None,
deleted: bool = None,
id_: str = None,
template_id: str = None,
folder_uuid: str = None,
) -> List[Dict]:
"""
:param q: str: Optional search query. Filter by document reference number (this token is stored on template level) or name.
:param tag: str: Optional search tag. Filter by document tag.
:param status_: PandaDocumentStatus: Optionally specify the status of documents to return.
:param count: int: Optionally specify how many document results to return. Default is 50 documents, maximum is 100 documents.
:param page: int: Optionally specify which page of the dataset to return.
:param metadata: str: Optionally specify metadata to filter by in the format of metadata_{metadata-key}={metadata-value} such as metadata_opportunity_id=2181432. The metadata_ prefix is always required.
:param deleted: bool: Optionally returns only deleted documents
:param id_: str: Optionally specify document's ID
:param template_id: str: Optionally specify template used for documents creation.
:param folder_uuid: str: The UUID of the folder where the documents are stored.
:return List[Dict]: List of documents
"""
data = {}
if q:
data['q'] = q
if tag:
data['tag'] = tag
if status_:
data['status'] = status_
if count:
data['count'] = count
if page:
data['page'] = page
if metadata:
data['metadata'] = metadata
if deleted is not None:
data['deleted'] = deleted
if id_:
data['id'] = id_
if template_id:
data['template_id'] = template_id
if folder_uuid:
data['folder_uuid'] = folder_uuid
response = cls._pandaworkspace.get('documents', data=data)
if response.status_code != 200:
raise ApiException(response.text)
results = response.json().get('results')
return results
@classmethod
def create(
cls,
template_uuid: str,
recipients: List[Pandarecipient],
name: str = 'Sample Template',
folder_uuid: str = '',
tokens: List[Dict] = None
):
"""
:param folder_uuid:
:param recipients:
:param name:
:param template_uuid: e.g.: "Cu7KZisX2Hrnug6FgrYX4d"
:param tokens:
:return:
"""
data = {
"name": name,
"template_uuid": template_uuid,
"recipients": [recipient.as_dict for recipient in recipients],
}
if folder_uuid:
data['folder_uuid'] = folder_uuid
if tokens:
data['tokens'] = tokens
response = cls._pandaworkspace.post('documents', data=data)
response_json = response.json()
document_id = response_json.get('id', None)
print("document_id:", document_id)
return cls(document_id)
def send(
self,
message: str = 'Hello! This document was sent from the PandaDoc API.',
subject: str = 'Please check this test API document from PandaDoc',
silent: bool = False,
) -> Dict:
"""
:param message:
:param subject:
:param silent:
:return:
"""
if self.id is None:
raise PandaDocumentDoesNotExist()
data = {
"message": message,
"subject": subject,
"silent": silent,
}
response = self.__class__._pandaworkspace.post(
'documents/{document_id}/send'.format(document_id=self.id),
data=data,
)
return response.json()
def status(self) -> Dict:
response = self.__class__._pandaworkspace.get('documents/{document_id}'.format(document_id=self.id))
return response.json()
def details(self) -> Dict:
response = self.__class__._pandaworkspace.get('documents/{document_id}/details'.format(document_id=self.id))
return response.json()
def delete(self) -> int:
response = self.__class__._pandaworkspace.delete('documents/{document_id}'.format(document_id=self.id))
return response.status_code
def share(self, recipient: Pandarecipient, lifetime: int = 3600):
"""
:type recipient: Pandarecipient
:type lifetime: int - Provide the number of seconds for which a document link should be valid for.
Default is 3600 seconds.
"""
data = {
"recipient": recipient.email,
"lifetime": lifetime,
}
response = self.__class__._pandaworkspace.post(
'documents/{document_id}/session'.format(document_id=self.id),
data=data,
)
link_id = response.json().get('id', None)
if link_id:
return self.__class__._pandaworkspace.get_app_url(uri='s/{link_id}'.format(link_id=link_id))
else:
raise ApiException(response)
def download(self, filename=None, download_folder=None) -> str:
return self.__class__._pandaworkspace.download(
'documents/{document_id}/download'.format(document_id=self.id),
filename,
download_folder,
)
def download_protected(self, filename=None, download_folder=None) -> str:
return self.__class__._pandaworkspace.download(
'documents/{document_id}/download-protected'.format(document_id=self.id),
filename,
download_folder,
)
def download_large(self, filename=None, download_folder=None) -> str:
return self.__class__._pandaworkspace.download_large(
'documents/{document_id}/download'.format(document_id=self.id),
filename,
download_folder
)