Skip to content
Snippets Groups Projects
Commit d987abc4 authored by Andreas Ellewsen's avatar Andreas Ellewsen
Browse files

Refactor models and methods for batches

Instead of mixing the Batch model for batches sent *to* with batches
received *from* SETRA, we switch to using an InputBatch and an
OutputBatch. The InputBatch contains the fields that can be used when
sending a Batch (with Vouchers and Transactions), and the OutputBatch
contains all the information one receives from SETRA when fetching a
single batch from the batch/ endpoint, or multiple using the search
functionality.

The get_batch method is reduced to only fetch a single batch, while the
new search_batches method takes the role of searching based on creation
date and interface. In addition, the return_list_of_obj parameter is
removed in favor of the return_objects class attribute.

This commit expects that SETRA includes the id field in Batches.
parent 36aa752f
No related branches found
No related tags found
1 merge request!17Refactor models and methods for batches
Pipeline #79675 passed
......@@ -3,13 +3,17 @@ import logging
import urllib.parse
from datetime import date
from typing import Union, Optional, List
import requests
from setra_client.models import (Batch,
CompleteBatch,
Parameter,
BatchErrors,
BatchProgressEnum)
from setra_client.models import (
BatchErrors,
BatchProgressEnum,
CompleteBatch,
InputBatch,
OutputBatch,
Parameter,
)
logger = logging.getLogger(__name__)
......@@ -203,36 +207,52 @@ class SetraClient(object):
return [cls.from_dict(i) for i in data]
raise TypeError(f"Expected list or dict, got {type(data)}")
def get_batch(self,
batch_id: Optional[int] = None,
min_created_date: Optional[date] = None,
max_created_date: Optional[date] = None,
batch_progress: Optional[BatchProgressEnum] = None,
interface: Optional[str] = None,
return_list_of_obj: Optional[bool] = False):
def search_batches(
self,
min_created_date: Optional[date] = None,
max_created_date: Optional[date] = None,
batch_progress: Optional[BatchProgressEnum] = None,
interface: Optional[str] = None,
) -> Union[List[dict], dict, List[OutputBatch]]:
"""
GETs one or all batches from SETRA.
Dates (maximal and minimal creation dates) should
Search batches in SETRA.
Dates (maximal and minimal creation dates) should
be defined like ISO strings - like "2020-01-01".
Batch Progress and interface - like strings exactly
as the values that can be found in the corresponding
fields of Setra.
"""
params = None
if batch_id is not None:
batch_id = str(batch_id)
else:
params = {'min_created_date': min_created_date,
'max_created_date': max_created_date,
'batch_progress': batch_progress,
'interface': interface}
url = self.urls.batch(batch_id)
params = {
'min_created_date': min_created_date,
'max_created_date': max_created_date,
'batch_progress': batch_progress,
'interface': interface,
}
url = self.urls.batch()
response = self.get(url, params=params)
data = response.json()
if return_list_of_obj:
return [Batch(**item) for item in data]
response.raise_for_status()
if self.return_objects:
if isinstance(data, list):
return [OutputBatch(**item) for item in data]
elif isinstance(data, dict):
return [OutputBatch(**data)]
else:
return data
def get_batch(self, batch_id: str) -> Union[OutputBatch, dict]:
"""
GETs a batch from SETRA.
"""
url = self.urls.batch(str(batch_id))
response = self.get(url)
data = response.json()
response.raise_for_status()
if self.return_objects:
return OutputBatch(**data)
else:
return data
......@@ -258,7 +278,7 @@ class SetraClient(object):
response = self.get(url)
return response.json()
def post_new_batch(self, batchdata: Batch):
def post_new_batch(self, batchdata: InputBatch):
"""
POST combination of batch, vouchers and transactions
"""
......@@ -274,7 +294,7 @@ class SetraClient(object):
response.raise_for_status()
return response
def put_update_batch(self, batchdata: Batch):
def put_update_batch(self, batchdata: InputBatch):
"""
PUT updates an existing batch with vouchers and transactions,
if the batch exists in setra, and has status=created, or validation failed.
......
......@@ -58,7 +58,7 @@ class Transaction(BaseModel):
dim5: Optional[str]
dim6: Optional[str]
dim7: Optional[str]
sequenceno: Optional[int]
sequenceno: int
taxcode: Optional[str]
transtype: Optional[str]
extinvref: Optional[str]
......@@ -71,18 +71,45 @@ class Voucher(BaseModel):
transactions: List[Transaction]
class Batch(BaseModel):
class InputBatch(BaseModel):
"""
Model representing a batch, with a list of vouchers (and each
voucher has a list of transactions)
voucher has a list of transactions.)
"""
client: str
batchid: str
period: Optional[str]
period: int
interface: str
vouchertype: str
vouchers: List[Voucher]
class OutputBatch(BaseModel):
"""
Model representing a batch, with a list of voucher ids connected to that batch.
"""
id: int
created: str
batchid: str
period: Optional[int]
interface: str
client: str
vouchertype: Optional[str]
batch_validated_ok_date: Optional[str]
batch_rejected_code: Optional[str]
sent_date: Optional[str]
http_response_content: Optional[str]
http_response_code: Optional[int]
orderno: Optional[int]
polling_statuscode: Optional[str]
polling_statuscode_date: Optional[str]
getresult_date: Optional[str]
getresult_statuscode: Optional[str]
getresult_logg: Optional[str]
getresult_report: Optional[str]
batch_progress: Optional[str]
vouchers: Optional[List[Voucher]]
vouchers: Optional[List[int]]
class ErrorTransaction(BaseModel):
......
{
"id": 1,
"created": "2020-01-05 03:45",
"client": 1,
"batchid": 2,
"period": 3,
......
{
"id": 1,
"created":"2020-08-20 00:00",
"client": 10,
"batchid": 20,
"period": 30,
......
......@@ -7,7 +7,8 @@ from requests import HTTPError
from setra_client.client import SetraClient
from setra_client.client import SetraEndpoints
from setra_client.models import Batch, CompleteBatch, BatchErrors, Parameter
from setra_client.models import CompleteBatch, BatchErrors, Parameter, InputBatch, \
OutputBatch
@pytest.fixture
......@@ -184,48 +185,43 @@ def test_header_replacement2(client_with_a_header, batch_url, requests_mock, bas
# Test get_batches method
def test_successful_get_all_batches(client, requests_mock, baseurl):
def test_successful_get_all_batches(client, requests_mock, baseurl, batch_fixture):
"""A working GET call should return HTTP 200, with json content"""
url = SetraEndpoints(baseurl).batch()
requests_mock.get(url, json={'foo': 'bar'}, status_code=200)
requests_mock.get(url, json=[batch_fixture], status_code=200)
response = client.get_batch()
assert response == {'foo': 'bar'}
response = client.search_batches()
assert response == [OutputBatch(**batch_fixture)]
def test_successful_get_batches_filtered_by_status(client, requests_mock, baseurl):
def test_successful_get_batches_filtered_by_status(
client, requests_mock, baseurl, batch_fixture
):
"""A working GET call should return HTTP 200, with json content"""
url = SetraEndpoints(baseurl).batch()
requests_mock.get(url, json={'foo': 'bar'}, status_code=200)
requests_mock.get(url, json=[batch_fixture], status_code=200)
response = client.get_batch(batch_progress="ubw_import_ok")
assert response == {'foo': 'bar'}
response = client.search_batches(batch_progress="ubw_import_ok")
assert response == [OutputBatch(**batch_fixture)]
def test_successfully_getting_single_batch(client, requests_mock, baseurl):
def test_successfully_getting_single_batch(
client, requests_mock, baseurl, batch_fixture
):
"""A working GET call should return HTTP 200, with json content"""
url = SetraEndpoints(baseurl).batch(batch_id='3')
requests_mock.get(url, json={'foo': 'bar'}, status_code=200)
requests_mock.get(url, json=batch_fixture, status_code=200)
response = client.get_batch(3)
assert response == {'foo': 'bar'}
assert response == OutputBatch(**batch_fixture)
def test_failing_to_get_all_batches(client, batch_url, requests_mock, baseurl):
"""A failing GET batches call should still return json"""
requests_mock.get(batch_url, json={'error': 'some json error message'}, status_code=404)
response = client.get_batch()
assert response == {'error': 'some json error message'}
def test_failing_to_get_all_batches_with_text(client, batch_url, requests_mock, baseurl):
"""A failing GET batches call that return text instead of json,
will raise JSONDecodeError in setra client"""
requests_mock.get(batch_url, text='some json error message', status_code=404)
"""Searching for batches with no matches returns empty list"""
requests_mock.get(batch_url, json=[], status_code=200)
with pytest.raises(JSONDecodeError):
client.get_batch()
response = client.search_batches()
assert response == []
# Test get_voucher method
......@@ -295,7 +291,7 @@ def test_failing_to_get_all_transactions(client, requests_mock, baseurl):
def test_successfully_post_batch_with_voucher(client, batch_with_voucher_fixture, requests_mock, baseurl):
"""A working GET call should return HTTP 200, with json content"""
url = SetraEndpoints(baseurl).post_new_batch()
batch = Batch.from_dict(batch_with_voucher_fixture)
batch = InputBatch.from_dict(batch_with_voucher_fixture)
requests_mock.post(url, json={'somestatus': 'ok'}, status_code=200, request_headers={"Content-Type": "application/json"})
response = client.post_new_batch(batch) # we get a response object back
......@@ -308,7 +304,7 @@ def test_successfully_post_batch_with_voucher_and_response(client, batch_with_vo
url = SetraEndpoints(baseurl).post_new_batch()
requests_mock.post(url, json={'somestatus': 'ok'}, status_code=200, request_headers={"Content-Type": "application/json"}) #expect json content
batch = Batch.from_dict(batch_with_voucher_fixture)
batch = InputBatch.from_dict(batch_with_voucher_fixture)
response = client.post_new_batch(batch) # we get a response object back
assert response.json() == {'somestatus': 'ok'}
assert response.status_code == 200
......
......@@ -4,22 +4,21 @@ import pytest
from pydantic import ValidationError
from setra_client.models import (
Batch,
BatchErrors,
CompleteBatch,
ErrorBatch,
Parameter,
Transaction,
Voucher,
Voucher, InputBatch, OutputBatch,
)
def test_batch(batch_fixture):
assert Batch(**batch_fixture)
assert InputBatch(**batch_fixture)
def test_batch(batch_without_voucher_field):
assert Batch(**batch_without_voucher_field)
def test_batch2(batch_without_voucher_field):
assert OutputBatch(**batch_without_voucher_field)
def test_voucher(voucher_fixture):
......@@ -44,13 +43,13 @@ def test_transaction_fail(trans_fail_fixture):
def test_batch_with_voucher(batch_with_voucher_fixture):
assert Batch(**batch_with_voucher_fixture)
assert InputBatch(**batch_with_voucher_fixture)
def test_batch_fail(batch_fail_fixture):
# Using wrong data format, should fail:
with pytest.raises(ValidationError):
Batch(**batch_fail_fixture)
OutputBatch(**batch_fail_fixture)
def test_error_batch(error_batch):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment