Skip to content

Commit

Permalink
Merge pull request #83 from datasciencebr/cuducos-same-day-data
Browse files Browse the repository at this point in the history
Add a “same day” API endpoint
  • Loading branch information
Irio committed Dec 22, 2016
2 parents d9f3124 + 4551050 commit 6a93fb8
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 12 deletions.
39 changes: 39 additions & 0 deletions jarbas/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,35 @@ class Meta:
)


class SameDayReimbursementSerializer(serializers.ModelSerializer):

city = serializers.SerializerMethodField()

def get_city(self, obj):
try:
company = Company.objects.get(cnpj=format_cnpj(obj.cnpj_cpf))
except Company.DoesNotExist:
return None

location = company.city, company.state
if not any(location):
return None

return ' - '.join(v for v in location if v)

class Meta:
model = Reimbursement
fields = (
'applicant_id',
'city',
'document_id',
'subquota_description',
'supplier',
'total_net_value',
'year'
)


class ReceiptSerializer(serializers.ModelSerializer):

reimbursement = serializers.SerializerMethodField()
Expand Down Expand Up @@ -114,3 +143,13 @@ class Meta:
model = Company
exclude = ('id',)
depth = 1


def format_cnpj(cnpj):
return '{}.{}.{}/{}-{}'.format(
cnpj[0:2],
cnpj[2:5],
cnpj[5:8],
cnpj[8:12],
cnpj[12:14]
)
92 changes: 92 additions & 0 deletions jarbas/api/tests/test_same_day_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from json import loads

from django.shortcuts import resolve_url
from django.test import TestCase

from jarbas.core.models import Company, Reimbursement
from jarbas.core.tests import sample_company_data, sample_reimbursement_data
from jarbas.api.serializers import format_cnpj


class TestSameDay(TestCase):

def setUp(self):
self.maxDiff = 2 ** 10
cnpj = '12345678901234'

company1 = sample_company_data.copy()
company1['cnpj'] = format_cnpj(cnpj)
company1['city'] = 'Atlantis'
company1['state'] = 'WE'
Company.objects.create(**company1)

company2 = sample_company_data.copy()
company2['cnpj'] = format_cnpj(cnpj[::-1])
Company.objects.create(**company2)

data1 = sample_reimbursement_data.copy()
data1['document_id'] = 42 * 2
data1['cnpj_cpf'] = cnpj
Reimbursement.objects.create(**data1)

data2 = sample_reimbursement_data.copy()
data2['document_id'] = 42 * 3
data2['cnpj_cpf'] = cnpj
Reimbursement.objects.create(**data2)

data3 = sample_reimbursement_data.copy()
data3['document_id'] = 42 * 4
data3['cnpj_cpf'] = cnpj[::-1]
Reimbursement.objects.create(**data3)

data4 = sample_reimbursement_data.copy()
data4['document_id'] = 42 * 5
data4['cnpj_cpf'] = '11111111111111'
Reimbursement.objects.create(**data4)

unique_id = dict(
year=1970,
applicant_id=13,
document_id=84
)
url = resolve_url('api:reimbursement-same-day', **unique_id)
self.resp = self.client.get(url)

def test_status_code(self):
self.assertEqual(200, self.resp.status_code)

def test_contents(self):
expected = (
{
'applicant_id': 13,
'city': 'Atlantis - WE',
'document_id': 126,
'subquota_description': 'Subquota description',
'supplier': 'Acme',
'total_net_value': '4.560',
'year': 1970
},
{
'applicant_id': 13,
'city': None,
'document_id': 168,
'subquota_description': 'Subquota description',
'supplier': 'Acme',
'total_net_value': '4.560',
'year': 1970
},
{
'applicant_id': 13,
'city': None,
'document_id': 210,
'subquota_description': 'Subquota description',
'supplier': 'Acme',
'total_net_value': '4.560',
'year': 1970
}
)
content = loads(self.resp.content.decode('utf-8'))
self.assertEqual(3, int(content['count']))
for reimbursement in expected:
with self.subTest():
self.assertIn(reimbursement, content['results'])
6 changes: 6 additions & 0 deletions jarbas/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
ReceiptDetailView,
ReimbursementDetailView,
ReimbursementListView,
SameDayReimbursementListView,
SubquotaListView,
)

Expand All @@ -26,6 +27,11 @@
ReceiptDetailView.as_view(),
name='reimbursement-receipt'
),
url(
r'^reimbursement/(?P<year>\d{4})/(?P<applicant_id>\d+)/(?P<document_id>\d+)/same_day/$',
SameDayReimbursementListView.as_view(),
name='reimbursement-same-day'
),
url(r'^applicant/$', ApplicantListView.as_view(), name='applicant-list'),
url(r'^company/(?P<cnpj>\d{14})/$', CompanyDetailView.as_view(), name='company-detail'),
url(r'^subquota/$', SubquotaListView.as_view(), name='subquota-list'),
Expand Down
21 changes: 12 additions & 9 deletions jarbas/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
ApplicantSerializer,
ReceiptSerializer,
ReimbursementSerializer,
SameDayReimbursementSerializer,
SubquotaSerializer,
CompanySerializer
CompanySerializer,
format_cnpj
)
from jarbas.core.models import Reimbursement, Company

Expand Down Expand Up @@ -89,6 +91,14 @@ def get_object(self):
return obj


class SameDayReimbursementListView(ListAPIView):

serializer_class = SameDayReimbursementSerializer

def get_queryset(self):
return Reimbursement.objects.same_day(**self.kwargs)


class ApplicantListView(ListAPIView):

serializer_class = ApplicantSerializer
Expand All @@ -115,11 +125,4 @@ class CompanyDetailView(RetrieveAPIView):

def get_object(self):
cnpj = self.kwargs.get(self.lookup_field, '00000000000000')
formatted = '{}.{}.{}/{}-{}'.format(
cnpj[0:2],
cnpj[2:5],
cnpj[5:8],
cnpj[8:12],
cnpj[12:14]
)
return get_object_or_404(Company, cnpj=formatted)
return get_object_or_404(Company, cnpj=format_cnpj(cnpj))
20 changes: 20 additions & 0 deletions jarbas/core/migrations/0021_make_reciept_fetched_a_db_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2016-12-22 18:22
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0020_rename_supplier_to_company'),
]

operations = [
migrations.AlterField(
model_name='reimbursement',
name='receipt_fetched',
field=models.BooleanField(db_index=True, default=False, verbose_name='Was the receipt URL fetched?'),
),
]
8 changes: 5 additions & 3 deletions jarbas/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from django.db import models
from requests import head

from jarbas.core.querysets import SameDayQuerySet


class Receipt:

Expand All @@ -21,9 +23,7 @@ def get_url(self):
@property
def exists(self):
status = head(self.get_url()).status_code
if 200 <= status < 400:
return True
return False
return 200 <= status < 400


class Reimbursement(models.Model):
Expand Down Expand Up @@ -74,6 +74,8 @@ class Reimbursement(models.Model):
receipt_fetched = models.BooleanField('Was the receipt URL fetched?', default=False, db_index=True)
receipt_url = models.CharField('Receipt URL', max_length=140, blank=True, null=True)

objects = models.Manager.from_queryset(SameDayQuerySet)()

class Meta:
ordering = ['-issue_date']
unique_together = ('year', 'applicant_id', 'document_id')
Expand Down
17 changes: 17 additions & 0 deletions jarbas/core/querysets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from django.db import models


class SameDayQuerySet(models.QuerySet):

def same_day(self, **kwargs):
keys = ('year', 'applicant_id', 'document_id')
unique_id = {k: v for k, v in kwargs.items()}
if not all(map(unique_id.get, keys)):
msg = 'A same_day queryset requires the kwargs: ' + ', '.join(keys)
raise TypeError(msg)

reference = self.get(**unique_id)
return self.exclude(**unique_id).filter(
issue_date=reference.issue_date,
applicant_id=reference.applicant_id
)
31 changes: 31 additions & 0 deletions jarbas/core/tests/test_reimbursement_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,37 @@ def test_optional_fields(self):
self.assertEqual(1, Reimbursement.objects.count())


class TestManager(TestReimbursement):

def test_same_day(self):
data1 = sample_reimbursement_data.copy()
data1['document_id'] = 42 * 2
data1['issue_date'] = '1970-12-31'
Reimbursement.objects.create(**data1)

data2 = sample_reimbursement_data.copy()
data2['document_id'] = 42 * 3
data2['issue_date'] = '1970-12-31'
Reimbursement.objects.create(**data2)

data3 = sample_reimbursement_data.copy()
data3['document_id'] = 42 * 4
data3['issue_date'] = '1970-12-31'
Reimbursement.objects.create(**data3)

unique_id = dict(
year=1970,
applicant_id=13,
document_id=84
)
qs = Reimbursement.objects.same_day(**unique_id)
self.assertEqual(2, qs.count())

def test_same_day_error(self):
with self.assertRaises(TypeError):
Reimbursement.objects.same_day(year=2016, document_id=42)


class TestCustomMethods(TestReimbursement):

def test_as_list(self):
Expand Down

0 comments on commit 6a93fb8

Please sign in to comment.