544180783bd48f0e4f748b21f05132933bc520f9
[insider.git] / insider / views.py
1 from decimal import Decimal, ROUND_DOWN
2 from datetime import datetime, timedelta
3 import re
4
5 from django.core.urlresolvers import reverse
6 from django.shortcuts import render_to_response
7 from django.template import RequestContext
8 from django.utils.safestring import mark_safe
9 from django.views.generic import ListView
10
11 from django_tables2 import Table, Column, LinkColumn
12 from django_tables2.utils import A
13 from django_tables2.views import SingleTableMixin
14
15 from .models import Company, Person, Ticker, Transaction
16
17
18 class NumberColumn(Column):
19     @staticmethod
20     def _format_integer(integer, sep=','):
21         """Pretty-print an integer at thousands, millions, etc.
22
23         >>> NumberColumn._format_integer(1234567)
24         '1,234,567'
25         >>> NumberColumn._format_integer(-123456)
26         '-123,456'
27         >>> NumberColumn._format_integer(1234567, sep=' ')
28         '1 234 567'
29         """
30         sign = ''
31         if integer < 0:
32             sign = '-'
33         string = '{:d}'.format(abs(integer))
34         return sign + sep.join(re.findall('(.{1,3})', string[::-1]))[::-1]
35
36     def render(self, value):
37         classes = ['number']
38         if value < 0:
39             classes.append('negative')
40         if value > 0:
41             classes.append('positive')
42         if isinstance(value, Decimal):
43             integer = int(value.quantize(Decimal('1.'), rounding=ROUND_DOWN))
44             decimal = int(abs(value - integer) * 100)
45             print value
46             value = '{}.{:02d}'.format(self._format_integer(integer), decimal)
47             print value
48         elif isinstance(value, int):
49             value = self._format_integer(value)
50         else:
51             raise NotImplementedError(type(value))
52         return mark_safe(u'<span class="{}">{}</span>'.format(
53                 u' '.join(classes), value))
54
55
56 class TransactionTable(Table):
57     id = LinkColumn('transaction', args=[A('pk')])
58     person = LinkColumn('person', args=[A('person.pk')])
59     date = LinkColumn(
60         'date', kwargs=dict((x, A('date.{}'.format(x)))
61                             for x in ['year', 'month', 'day']))
62     ticker = LinkColumn('ticker', args=[A('ticker.pk')])
63     shares = NumberColumn()
64     value = NumberColumn()
65
66     class Meta:
67         model = Transaction
68         order_by = '-date'
69
70     def render_source(self, value):
71         return mark_safe(u'<a href="{}">source</a>'.format(value))
72
73
74 class TransactionTableView(SingleTableMixin, ListView):
75     model = Transaction
76     table_class = TransactionTable
77
78
79 def _detail(request, title, transactions):
80     table = TransactionTable(transactions, order_by=request.GET.get('sort'))
81     table.paginate(page=request.GET.get('page', 1))
82     return render_to_response(
83         'table.html', {'title': title, 'table': table},
84         context_instance=RequestContext(request))
85
86 def company(request, pk):
87     tickers = Ticker.objects.filter(company__id=pk)
88     #tks = [ticker.pk for ticker in tickers]
89     return _detail(request, Company.objects.get(pk=pk),
90                    Transaction.objects.filter(ticker__in=tickers))
91
92 def person(request, pk):
93     return _detail(request, Person.objects.get(pk=pk),
94                    Transaction.objects.filter(person__id=pk))
95
96 def ticker(request, pk):
97     ticker = Ticker.objects.get(pk=pk)
98     company = ticker.company
99     url = reverse('company', args=[company.id])
100     title = mark_safe(u'{} (<a href="{}">{}</a>)'.format(
101             ticker, url, company))
102     return _detail(request, title, Transaction.objects.filter(ticker__id=pk))
103
104 def date(request, **kwargs):
105     for k,v in kwargs.items():
106         kwargs[k] = int(v)
107     date = datetime(**kwargs)
108     next_date = date.date() + timedelta(days=1)
109     return _detail(request, date.date().isoformat(),
110                    Transaction.objects.filter(date__range=(date,next_date)))