Skip to content

Commit 9a4d829

Browse files
authored
Errors (#102)
* adding errors from docuemnts * rename errors * non optional * update codecov action * uses * errors tested * lint * verification steps * version * v1
1 parent d5c6df3 commit 9a4d829

7 files changed

Lines changed: 245 additions & 1 deletion

File tree

mati/resources/verifications.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from ..types.enums import (
66
DocumentScore,
7+
Errors,
78
Liveness,
89
UserValidationFile,
910
VerificationDocument,
@@ -83,6 +84,21 @@ def proof_of_life_document(self) -> Optional[Liveness]:
8384
pol = [pol for pol in self.steps if pol.id == 'liveness']
8485
return pol[-1] if pol else None
8586

87+
@property
88+
def proof_of_life_errors(self) -> List[Errors]:
89+
return [
90+
Errors(
91+
identifier=pol.id,
92+
type=pol.error['type'] if 'type' in pol.error else None,
93+
code=pol.error['code'] if 'code' in pol.error else None,
94+
message=pol.error['message']
95+
if 'message' in pol.error
96+
else None,
97+
)
98+
for pol in self.steps # type: ignore
99+
if pol.id == 'liveness' and pol.error
100+
]
101+
86102
@property
87103
def govt_id_document(self) -> Optional[VerificationDocument]:
88104
govs = [

mati/types/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
__all__ = [
2+
'Errors',
23
'SerializableEnum',
34
'PageType',
45
'ValidationInputType',
@@ -13,6 +14,7 @@
1314

1415
from .enums import (
1516
DocumentScore,
17+
Errors,
1618
Liveness,
1719
LivenessMedia,
1820
PageType,

mati/types/enums.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ class VerificationDocumentStep:
3535
data: Optional[Dict] = field(default_factory=dict)
3636

3737

38+
@dataclass
39+
class Errors:
40+
identifier: str
41+
type: str
42+
code: str
43+
message: str
44+
45+
3846
@dataclass
3947
class VerificationDocument:
4048
country: str
@@ -44,6 +52,46 @@ class VerificationDocument:
4452
type: str
4553
fields: Optional[dict] = None
4654

55+
@property
56+
def errors(self) -> List[Errors]:
57+
if not self.steps:
58+
return []
59+
errors = [
60+
Errors(
61+
identifier=step.id,
62+
type=step.error['type'] if 'type' in step.error else None,
63+
code=step.error['code'] if 'code' in step.error else None,
64+
message=step.error['message']
65+
if 'message' in step.error
66+
else None,
67+
)
68+
for step in self.steps
69+
if step.error
70+
]
71+
if self.type == 'proof-of-residency' and self.steps:
72+
step = self.steps[0]
73+
keys = step.data.keys() # type: ignore
74+
required_fileds = []
75+
for key in keys:
76+
data = step.data[key] # type: ignore
77+
if (
78+
'required' in data
79+
and data['required']
80+
and not data['value']
81+
):
82+
required_fileds.append(data['label'])
83+
if required_fileds:
84+
errors.append(
85+
Errors(
86+
identifier=step.id,
87+
type='StepError',
88+
code='document.extractRequiredFields',
89+
message=f"We can't extract the following "
90+
f"fields in the document: {required_fileds}",
91+
)
92+
)
93+
return errors
94+
4795
@property
4896
def document_type(self) -> str:
4997
if self.type in ['national-id', 'passport']:

mati/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '2.0.0' # pragma: no cover
1+
__version__ = '2.0.1' # pragma: no cover

tests/conftest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,13 @@ def verification(client: Client) -> Generator:
221221
)
222222

223223

224+
@pytest.fixture
225+
def verification_without_pol(client: Client):
226+
verification = client.verifications.retrieve('634870763768f1001cac7591')
227+
verification.steps = []
228+
yield verification
229+
230+
224231
@pytest.fixture
225232
def verification_document_national_id() -> VerificationDocument:
226233
return VerificationDocument(
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
interactions:
2+
- request:
3+
body: grant_type=client_credentials
4+
headers:
5+
Accept:
6+
- '*/*'
7+
Accept-Encoding:
8+
- gzip, deflate
9+
Connection:
10+
- keep-alive
11+
Content-Length:
12+
- '29'
13+
Content-Type:
14+
- application/x-www-form-urlencoded
15+
User-Agent:
16+
- mati-python/2.0.1.dev1
17+
method: POST
18+
uri: https://api.getmati.com/oauth
19+
response:
20+
body:
21+
string: '{"access_token": "ACCESS_TOKEN", "expiresIn": 3600, "payload": {"user":
22+
{"_id": "ID", "firstName": "FIRST_NAME", "lastName": "LAST_NAME"}}}'
23+
headers:
24+
Cache-Control:
25+
- no-store, no-cache, must-revalidate, proxy-revalidate
26+
Connection:
27+
- keep-alive
28+
Content-Length:
29+
- '746'
30+
Content-Security-Policy:
31+
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
32+
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
33+
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
34+
Content-Type:
35+
- application/json; charset=utf-8
36+
Date:
37+
- Fri, 14 Oct 2022 19:18:06 GMT
38+
Expect-Ct:
39+
- max-age=0
40+
Expires:
41+
- '0'
42+
Pragma:
43+
- no-cache
44+
Referrer-Policy:
45+
- no-referrer
46+
Strict-Transport-Security:
47+
- max-age=15552000; includeSubDomains; preload
48+
Surrogate-Control:
49+
- no-store
50+
X-Content-Type-Options:
51+
- nosniff
52+
X-Dns-Prefetch-Control:
53+
- 'off'
54+
X-Download-Options:
55+
- noopen
56+
X-Frame-Options:
57+
- DENY
58+
X-Permitted-Cross-Domain-Policies:
59+
- none
60+
X-Request-Id:
61+
- 56dafc49-6548-4cb2-8be3-497d15d36645
62+
X-Xss-Protection:
63+
- '1'
64+
status:
65+
code: 200
66+
message: OK
67+
- request:
68+
body: null
69+
headers:
70+
Accept:
71+
- '*/*'
72+
Accept-Encoding:
73+
- gzip, deflate
74+
Connection:
75+
- keep-alive
76+
User-Agent:
77+
- mati-python/2.0.1.dev1
78+
method: GET
79+
uri: https://api.getmati.com/v2/verifications/634870763768f1001cac7591
80+
response:
81+
body:
82+
string: '{"expired": false, "identity": {"status": "verified"}, "flow": {"id":
83+
"some_flow", "name": "Default flow"}, "documents": [{"country": "MX", "region":
84+
"", "type": "national-id", "photos": ["https://media.getmati.com/media/xxx",
85+
"https://media.getmati.com/media/yyy"], "steps": [{"error": null, "status":
86+
200, "id": "template-matching"}, {"error": null, "status": 200, "id": "mexican-curp-validation",
87+
"data": {"curp": "CURP", "fullName": "LAST FIRST", "birthDate": "01/01/1980",
88+
"gender": "HOMBRE", "nationality": "MEXICO", "surname": "LAST", "secondSurname":
89+
"", "name": "FIRST"}}, {"error": null, "status": 200, "id": "document-reading",
90+
"data": {"fullName": {"value": "FIRST LAST", "label": "Name", "sensitive":
91+
true}, "documentNumber": {"value": "111", "label": "Document Number"}, "dateOfBirth":
92+
{"value": "1980-01-01", "label": "Day of Birth", "format": "date"}, "expirationDate":
93+
{"value": "2030-12-31", "label": "Date of Expiration", "format": "date"},
94+
"curp": {"value": "CURP", "label": "CURP"}, "address": {"value": "Varsovia
95+
36, 06600 CDMX", "label": "Address"}, "emissionDate": {"value": "2010-01-01",
96+
"label": "Emission Date", "format": "date"}}}, {"error": null, "status": 200,
97+
"id": "alteration-detection"}, {"error": null, "status": 200, "id": "watchlists"}],
98+
"fields": {"fullName": {"value": "FIRST LAST", "label": "Name", "sensitive":
99+
true}, "documentNumber": {"value": "111", "label": "Document Number"}, "dateOfBirth":
100+
{"value": "1980-01-01", "label": "Day of Birth", "format": "date"}, "expirationDate":
101+
{"value": "2030-12-31", "label": "Date of Expiration", "format": "date"},
102+
"curp": {"value": "CURP", "label": "CURP"}, "address": {"value": "Varsovia
103+
36, 06600 CDMX", "label": "Address"}, "emissionDate": {"value": "2010-01-01",
104+
"label": "Emission Date", "format": "date"}}}, {"country": "MX", "region":
105+
null, "type": "proof-of-residency", "steps": [{"status": 200, "id": "document-reading",
106+
"data": {"fullName": {"required": true, "label": "Name", "value": "FIRST NAME"},
107+
"address": {"label": "Address", "value": "Varsovia 36, 06600 CDMX"}, "emissionDate":
108+
{"format": "date", "label": "Emission Date", "value": "1880-01-01"}}, "error":
109+
null}, {"status": 200, "id": "watchlists", "error": null}], "fields": {"address":
110+
{"value": "Varsovia 36, 06600 CDMX"}, "emissionDate": {"value": "1880-01-01"},
111+
"fullName": {"value": "FIRST LASTNAME"}}, "photos": ["https://media.getmati.com/file?location=xyc"]}],
112+
"steps": [{"status": 200, "id": "liveness", "data": {"videoUrl": "https://media.getmati.com/file?location=abc",
113+
"spriteUrl": "https://media.getmati.com/file?location=def", "selfieUrl": "https://media.getmati.com/file?location=hij"},
114+
"error": null}], "hasProblem": false, "computed": {"age": {"data": 100}, "isDocumentExpired":
115+
{"data": {"national-id": false, "proof-of-residency": false}}}, "id": "5d9fb1f5bfbfac001a349bfb",
116+
"metadata": {"name": "First Last", "dob": "1980-01-01"}}'
117+
headers:
118+
Cache-Control:
119+
- no-store, no-cache, must-revalidate, proxy-revalidate
120+
Connection:
121+
- keep-alive
122+
Content-Length:
123+
- '4288'
124+
Content-Security-Policy:
125+
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
126+
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
127+
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
128+
Content-Type:
129+
- application/json; charset=utf-8
130+
Date:
131+
- Fri, 14 Oct 2022 19:18:06 GMT
132+
Expect-Ct:
133+
- max-age=0
134+
Expires:
135+
- '0'
136+
Pragma:
137+
- no-cache
138+
Referrer-Policy:
139+
- no-referrer
140+
Strict-Transport-Security:
141+
- max-age=15552000; includeSubDomains; preload
142+
Surrogate-Control:
143+
- no-store
144+
X-Content-Type-Options:
145+
- nosniff
146+
X-Dns-Prefetch-Control:
147+
- 'off'
148+
X-Download-Options:
149+
- noopen
150+
X-Frame-Options:
151+
- DENY
152+
X-Permitted-Cross-Domain-Policies:
153+
- none
154+
X-Request-Id:
155+
- 2a5d765d-f1f6-42b8-8de9-0343691d4a4f
156+
X-Xss-Protection:
157+
- '1'
158+
status:
159+
code: 200
160+
message: OK
161+
version: 1

tests/resources/test_verifications.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ def test_retrieve_full_verification(client: Client):
2121
assert verification.govt_id_validation.is_valid
2222
assert verification.proof_of_life_validation.is_valid
2323
assert verification.proof_of_residency_validation.is_valid
24+
assert not verification.govt_id_document.errors
25+
assert not verification.proof_of_residency_document.errors
26+
assert not verification.proof_of_life_errors
2427
assert (
2528
verification.proof_of_residency_document.address
2629
== 'Varsovia 36, 06600 CDMX'
@@ -67,3 +70,10 @@ def test_create_verification(client: Client):
6770
assert verification.flow['id'] == FAKE_FLOW_ID
6871
assert verification.metadata['user'] == 'some_id'
6972
assert verification.identity
73+
74+
75+
@pytest.mark.vcr
76+
def test_retrieve_dni_verification(verification_without_pol):
77+
verification = verification_without_pol
78+
assert not verification.proof_of_life_errors
79+
assert not verification.proof_of_life_document

0 commit comments

Comments
 (0)