attime-star-api-python-sdk 1.3.2__tar.gz → 1.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {attime_star_api_python_sdk-1.3.2/src/attime_star_api_python_sdk.egg-info → attime_star_api_python_sdk-1.4.0}/PKG-INFO +1 -1
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/pyproject.toml +1 -1
- attime_star_api_python_sdk-1.4.0/src/attime/star/apis/attime001.py +76 -0
- attime_star_api_python_sdk-1.4.0/src/attime/star/dtos/attime001.py +92 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0/src/attime_star_api_python_sdk.egg-info}/PKG-INFO +1 -1
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime_star_api_python_sdk.egg-info/SOURCES.txt +4 -1
- attime_star_api_python_sdk-1.4.0/tests/test_attime001_cancelamento.py +87 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/LICENSE +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/README.md +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/setup.cfg +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime/star/api.py +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime/star/apis/__init__.py +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime/star/apis/bvix.py +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime/star/apis/infocar.py +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime/star/dtos/__init__.py +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime/star/dtos/bvix.py +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime/star/dtos/infocar.py +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime_star_api_python_sdk.egg-info/dependency_links.txt +0 -0
- {attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime_star_api_python_sdk.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Cliente HTTP ApiAttime001 (ABTP0004)."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
import jsonpickle
|
|
8
|
+
from fmconsult.utils.url import UrlUtil
|
|
9
|
+
from http import HTTPMethod
|
|
10
|
+
|
|
11
|
+
from attime.star.api import ATTimeStarApi
|
|
12
|
+
from attime.star.dtos.attime001 import ApiAttime001CancelamentoDTO
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Attime001Api(ATTimeStarApi):
|
|
16
|
+
"""Rotinas ApiAttime001 — cancelamento de contrato/item/cobertura/serviço/beneficiário."""
|
|
17
|
+
|
|
18
|
+
def cancelamento(
|
|
19
|
+
self, item: ApiAttime001CancelamentoDTO | dict
|
|
20
|
+
) -> list[ApiAttime001CancelamentoDTO]:
|
|
21
|
+
"""POST /btc/ABTP0004/ApiAttime001/Cancelamento."""
|
|
22
|
+
logging.info('cancelling via ApiAttime001 Cancelamento...')
|
|
23
|
+
try:
|
|
24
|
+
if isinstance(item, ApiAttime001CancelamentoDTO):
|
|
25
|
+
payload = item.to_dict()
|
|
26
|
+
else:
|
|
27
|
+
payload = dict(item)
|
|
28
|
+
|
|
29
|
+
escopo = payload.get('escopoOperacao')
|
|
30
|
+
numero = payload.get('numeroContrato')
|
|
31
|
+
if escopo in (None, ''):
|
|
32
|
+
raise ValueError('escopoOperacao é obrigatório')
|
|
33
|
+
if numero in (None, ''):
|
|
34
|
+
raise ValueError('numeroContrato é obrigatório')
|
|
35
|
+
|
|
36
|
+
url = UrlUtil().make_url(
|
|
37
|
+
self.base_url,
|
|
38
|
+
['btc', 'ABTP0004', 'ApiAttime001', 'Cancelamento'],
|
|
39
|
+
)
|
|
40
|
+
res = self.call_request(
|
|
41
|
+
http_method=HTTPMethod.POST,
|
|
42
|
+
request_url=url,
|
|
43
|
+
payload=payload,
|
|
44
|
+
)
|
|
45
|
+
res = jsonpickle.decode(res)
|
|
46
|
+
|
|
47
|
+
if isinstance(res, list):
|
|
48
|
+
return [
|
|
49
|
+
row
|
|
50
|
+
for row in (ApiAttime001CancelamentoDTO.from_dict(r) for r in res)
|
|
51
|
+
if row is not None
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
if isinstance(res, dict):
|
|
55
|
+
if 'dados' in res:
|
|
56
|
+
dados = res['dados']
|
|
57
|
+
if isinstance(dados, list):
|
|
58
|
+
return [
|
|
59
|
+
row
|
|
60
|
+
for row in (ApiAttime001CancelamentoDTO.from_dict(r) for r in dados)
|
|
61
|
+
if row is not None
|
|
62
|
+
]
|
|
63
|
+
if isinstance(dados, dict):
|
|
64
|
+
parsed = ApiAttime001CancelamentoDTO.from_dict(dados)
|
|
65
|
+
return [parsed] if parsed is not None else []
|
|
66
|
+
raise Exception(res.get('mensagem', 'Resposta inesperada em dados'))
|
|
67
|
+
|
|
68
|
+
if 'codigo' in res:
|
|
69
|
+
raise Exception(res.get('mensagem', 'Erro desconhecido'))
|
|
70
|
+
|
|
71
|
+
parsed = ApiAttime001CancelamentoDTO.from_dict(res)
|
|
72
|
+
return [parsed] if parsed is not None else []
|
|
73
|
+
|
|
74
|
+
raise Exception('Resposta inesperada da API Attime001 Cancelamento')
|
|
75
|
+
except Exception:
|
|
76
|
+
raise
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""DTOs ApiAttime001 (ABTP0004).
|
|
3
|
+
|
|
4
|
+
Cancelamento: POST /btc/ABTP0004/ApiAttime001/Cancelamento
|
|
5
|
+
Doc: cancelamentos de contrato / item / cobertura / serviço / beneficiário.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import asdict, dataclass
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class EscopoOperacao:
|
|
14
|
+
"""Valores sugeridos de ``escopoOperacao`` (OpenAPI tipa como string livre).
|
|
15
|
+
|
|
16
|
+
Alinhados à descrição do endpoint (contrato/item/cobertura/serviço/beneficiário).
|
|
17
|
+
Confirmar no homolog se a STAR exigir código diferente.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
CONTRATO = 'CONTRATO'
|
|
21
|
+
ITEM = 'ITEM'
|
|
22
|
+
COBERTURA = 'COBERTURA'
|
|
23
|
+
SERVICO = 'SERVICO'
|
|
24
|
+
BENEFICIARIO = 'BENEFICIARIO'
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class ApiAttime001CancelamentoDTO:
|
|
29
|
+
"""Payload/resposta de Cancelamento (ApiAttime001CancelamentoDTO)."""
|
|
30
|
+
|
|
31
|
+
escopoOperacao: str
|
|
32
|
+
numeroContrato: str
|
|
33
|
+
manutencaoUsuarioCpf: Optional[str] = None
|
|
34
|
+
manutencaoUsuarioDataHora: Optional[str] = None # ISO date-time
|
|
35
|
+
identificadorItem: Optional[str] = None
|
|
36
|
+
caracteristicaCodigo: Optional[int] = None
|
|
37
|
+
coberturaCodigo: Optional[int] = None
|
|
38
|
+
servicoCodigo: Optional[int] = None
|
|
39
|
+
beneficiarioCodigo: Optional[int] = None
|
|
40
|
+
|
|
41
|
+
def to_dict(self) -> dict:
|
|
42
|
+
return {k: v for k, v in asdict(self).items() if v is not None}
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def from_dict(
|
|
46
|
+
cls, data: dict | ApiAttime001CancelamentoDTO | None
|
|
47
|
+
) -> ApiAttime001CancelamentoDTO | None:
|
|
48
|
+
if data is None:
|
|
49
|
+
return None
|
|
50
|
+
if isinstance(data, cls):
|
|
51
|
+
return data
|
|
52
|
+
if not isinstance(data, dict):
|
|
53
|
+
raise TypeError(
|
|
54
|
+
f'ApiAttime001CancelamentoDTO.from_dict espera dict, recebeu {type(data)!r}'
|
|
55
|
+
)
|
|
56
|
+
return cls(**{k: data.get(k) for k in cls.__dataclass_fields__})
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def for_item(
|
|
60
|
+
cls,
|
|
61
|
+
*,
|
|
62
|
+
numeroContrato: str,
|
|
63
|
+
identificadorItem: str,
|
|
64
|
+
manutencaoUsuarioCpf: Optional[str] = None,
|
|
65
|
+
manutencaoUsuarioDataHora: Optional[str] = None,
|
|
66
|
+
escopoOperacao: str = EscopoOperacao.ITEM,
|
|
67
|
+
) -> ApiAttime001CancelamentoDTO:
|
|
68
|
+
"""Atalho para cancelar um item do contrato (caso típico de saída de vida)."""
|
|
69
|
+
return cls(
|
|
70
|
+
escopoOperacao=escopoOperacao,
|
|
71
|
+
numeroContrato=numeroContrato,
|
|
72
|
+
identificadorItem=identificadorItem,
|
|
73
|
+
manutencaoUsuarioCpf=manutencaoUsuarioCpf,
|
|
74
|
+
manutencaoUsuarioDataHora=manutencaoUsuarioDataHora,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
@classmethod
|
|
78
|
+
def for_contrato(
|
|
79
|
+
cls,
|
|
80
|
+
*,
|
|
81
|
+
numeroContrato: str,
|
|
82
|
+
manutencaoUsuarioCpf: Optional[str] = None,
|
|
83
|
+
manutencaoUsuarioDataHora: Optional[str] = None,
|
|
84
|
+
escopoOperacao: str = EscopoOperacao.CONTRATO,
|
|
85
|
+
) -> ApiAttime001CancelamentoDTO:
|
|
86
|
+
"""Atalho para cancelar o contrato inteiro."""
|
|
87
|
+
return cls(
|
|
88
|
+
escopoOperacao=escopoOperacao,
|
|
89
|
+
numeroContrato=numeroContrato,
|
|
90
|
+
manutencaoUsuarioCpf=manutencaoUsuarioCpf,
|
|
91
|
+
manutencaoUsuarioDataHora=manutencaoUsuarioDataHora,
|
|
92
|
+
)
|
|
@@ -3,12 +3,15 @@ README.md
|
|
|
3
3
|
pyproject.toml
|
|
4
4
|
src/attime/star/api.py
|
|
5
5
|
src/attime/star/apis/__init__.py
|
|
6
|
+
src/attime/star/apis/attime001.py
|
|
6
7
|
src/attime/star/apis/bvix.py
|
|
7
8
|
src/attime/star/apis/infocar.py
|
|
8
9
|
src/attime/star/dtos/__init__.py
|
|
10
|
+
src/attime/star/dtos/attime001.py
|
|
9
11
|
src/attime/star/dtos/bvix.py
|
|
10
12
|
src/attime/star/dtos/infocar.py
|
|
11
13
|
src/attime_star_api_python_sdk.egg-info/PKG-INFO
|
|
12
14
|
src/attime_star_api_python_sdk.egg-info/SOURCES.txt
|
|
13
15
|
src/attime_star_api_python_sdk.egg-info/dependency_links.txt
|
|
14
|
-
src/attime_star_api_python_sdk.egg-info/top_level.txt
|
|
16
|
+
src/attime_star_api_python_sdk.egg-info/top_level.txt
|
|
17
|
+
tests/test_attime001_cancelamento.py
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Testes unitários ApiAttime001 Cancelamento (sem HTTP)."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import unittest
|
|
6
|
+
from unittest.mock import MagicMock, patch
|
|
7
|
+
|
|
8
|
+
from attime.star.dtos.attime001 import (
|
|
9
|
+
ApiAttime001CancelamentoDTO,
|
|
10
|
+
EscopoOperacao,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestApiAttime001CancelamentoDTO(unittest.TestCase):
|
|
15
|
+
def test_to_dict_omits_none(self):
|
|
16
|
+
dto = ApiAttime001CancelamentoDTO.for_item(
|
|
17
|
+
numeroContrato='002501000089',
|
|
18
|
+
identificadorItem='12345678901',
|
|
19
|
+
)
|
|
20
|
+
data = dto.to_dict()
|
|
21
|
+
self.assertEqual(data['escopoOperacao'], EscopoOperacao.ITEM)
|
|
22
|
+
self.assertEqual(data['numeroContrato'], '002501000089')
|
|
23
|
+
self.assertEqual(data['identificadorItem'], '12345678901')
|
|
24
|
+
self.assertNotIn('coberturaCodigo', data)
|
|
25
|
+
self.assertNotIn('manutencaoUsuarioCpf', data)
|
|
26
|
+
|
|
27
|
+
def test_from_dict_roundtrip(self):
|
|
28
|
+
raw = {
|
|
29
|
+
'escopoOperacao': 'ITEM',
|
|
30
|
+
'numeroContrato': '002501000089',
|
|
31
|
+
'identificadorItem': '999',
|
|
32
|
+
'coberturaCodigo': 81,
|
|
33
|
+
}
|
|
34
|
+
dto = ApiAttime001CancelamentoDTO.from_dict(raw)
|
|
35
|
+
self.assertIsNotNone(dto)
|
|
36
|
+
self.assertEqual(dto.coberturaCodigo, 81)
|
|
37
|
+
self.assertEqual(dto.to_dict()['coberturaCodigo'], 81)
|
|
38
|
+
|
|
39
|
+
def test_for_contrato(self):
|
|
40
|
+
dto = ApiAttime001CancelamentoDTO.for_contrato(numeroContrato='002501000001')
|
|
41
|
+
self.assertEqual(dto.escopoOperacao, EscopoOperacao.CONTRATO)
|
|
42
|
+
self.assertIsNone(dto.identificadorItem)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TestAttime001ApiCancelamento(unittest.TestCase):
|
|
46
|
+
def test_requires_escopo_and_numero(self):
|
|
47
|
+
from attime.star.apis.attime001 import Attime001Api
|
|
48
|
+
|
|
49
|
+
with patch.object(Attime001Api, '__init__', lambda self: None):
|
|
50
|
+
api = Attime001Api()
|
|
51
|
+
with self.assertRaises(ValueError):
|
|
52
|
+
api.cancelamento({'numeroContrato': '002501000001'})
|
|
53
|
+
with self.assertRaises(ValueError):
|
|
54
|
+
api.cancelamento({'escopoOperacao': 'ITEM'})
|
|
55
|
+
|
|
56
|
+
def test_posts_to_cancelamento_path(self):
|
|
57
|
+
from attime.star.apis.attime001 import Attime001Api
|
|
58
|
+
|
|
59
|
+
with patch.object(Attime001Api, '__init__', lambda self: None):
|
|
60
|
+
api = Attime001Api()
|
|
61
|
+
api.base_url = 'https://starbackhom.attime.inf.br'
|
|
62
|
+
api.call_request = MagicMock(
|
|
63
|
+
return_value='[{"escopoOperacao":"ITEM","numeroContrato":"002501000089","identificadorItem":"1"}]'
|
|
64
|
+
)
|
|
65
|
+
with patch('attime.star.apis.attime001.jsonpickle.decode') as decode:
|
|
66
|
+
decode.return_value = [
|
|
67
|
+
{
|
|
68
|
+
'escopoOperacao': 'ITEM',
|
|
69
|
+
'numeroContrato': '002501000089',
|
|
70
|
+
'identificadorItem': '1',
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
rows = api.cancelamento(
|
|
74
|
+
ApiAttime001CancelamentoDTO.for_item(
|
|
75
|
+
numeroContrato='002501000089',
|
|
76
|
+
identificadorItem='1',
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
self.assertEqual(len(rows), 1)
|
|
80
|
+
self.assertEqual(rows[0].identificadorItem, '1')
|
|
81
|
+
kwargs = api.call_request.call_args.kwargs
|
|
82
|
+
self.assertIn('/ABTP0004/ApiAttime001/Cancelamento', kwargs['request_url'])
|
|
83
|
+
self.assertEqual(kwargs['payload']['escopoOperacao'], 'ITEM')
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == '__main__':
|
|
87
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime/star/api.py
RENAMED
|
File without changes
|
|
File without changes
|
{attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime/star/apis/bvix.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{attime_star_api_python_sdk-1.3.2 → attime_star_api_python_sdk-1.4.0}/src/attime/star/dtos/bvix.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|