Skip to content

Instantly share code, notes, and snippets.

@hashlash
Last active June 19, 2019 15:21
Show Gist options
  • Save hashlash/4ba03673c8c659e7a08087e57e8dd218 to your computer and use it in GitHub Desktop.
Save hashlash/4ba03673c8c659e7a08087e57e8dd218 to your computer and use it in GitHub Desktop.
from abc import ABCMeta, abstractmethod
from collections import defaultdict
from typing import Iterable
from waste.models import WasteType
class TransactionUnit:
amount = 0
unit = None
def __init__(self, amount, unit):
self.amount += amount
self.unit = self.unit or unit
def __add__(self, other):
return TransactionUnit(self.amount + other.amount, self.unit or other.unit)
class WasteTransactionUnit:
def __init__(self, waste: WasteType = None,
waste_unit_obj: TransactionUnit = None,
price_unit_obj: TransactionUnit = None,
data_dict: dict = None):
self._waste = waste
if isinstance(data_dict, dict):
self._waste_unit = TransactionUnit(data_dict['amount'], data_dict['unit'])
self._price_unit = TransactionUnit(data_dict['price'], data_dict['currency'])
elif (isinstance(waste_unit_obj, TransactionUnit) and
isinstance(price_unit_obj, TransactionUnit)):
self._waste_unit = waste_unit_obj
self._price_unit = price_unit_obj
else:
self._waste_unit = TransactionUnit(0, None)
self._price_unit = TransactionUnit(0, None)
def __add__(self, other):
return WasteTransactionUnit(waste=self.waste or other.waste,
waste_unit_obj=self.waste_unit + other.waste_unit,
price_unit_obj=self.price_unit + other.price_unit)
@property
def waste_unit(self):
return self._waste_unit
@property
def price_unit(self):
return self._price_unit
@property
def waste(self):
return self._waste
@property
def amount(self):
return self._waste_unit.amount
@property
def unit(self):
return self._waste_unit.unit
@property
def price(self):
return self._price_unit.amount
@property
def currency(self):
return self._price_unit.unit
class AbstractSummary(defaultdict, metaclass=ABCMeta):
def __init__(self, *args, **kwargs):
transactions = kwargs.pop('transactions', None)
super().__init__(*args, **kwargs)
if transactions:
for tx in transactions:
self.add_tx(tx)
def __getitem__(self, key):
try:
key_attr = getattr(self, key)
try:
return key_attr()
except TypeError:
return key_attr
except (TypeError, AttributeError):
return self.setdefault(key, self.default_factory())
@abstractmethod
def add_tx(self, tx):
pass
@property
def total(self):
pass
class CategoryTransactionUnit(AbstractSummary):
def __init__(self, transactions: Iterable[WasteTransactionUnit] = None):
super().__init__(WasteTransactionUnit, transactions=transactions)
def add_tx(self, tx):
self[tx.waste] += tx
@property
def total(self):
return sum(self.values(), WasteTransactionUnit())
class TransactionSummary(AbstractSummary):
def __init__(self, transactions: Iterable[WasteTransactionUnit] = None):
super().__init__(CategoryTransactionUnit, transactions=transactions)
def add_tx(self, tx):
self[tx.waste.category].add_tx(tx)
@property
def total(self):
return sum((tx.total for tx in self.values()), WasteTransactionUnit())
def deposit_detail(request, date_str):
user = request.user
bsu = BankSampahUnit.objects.get(user=user)
date = parse_date(date_str)
tx_groups = TransactionDetail.objects \
.filter(timestamp__date=date, account=bsu) \
.exclude(obj=None).exclude(debit=None) \
.values_list('transaction_id', flat=True) \
.distinct()
transactions_dicts = TransactionDetail.objects \
.filter(transaction_id__in=tx_groups) \
.exclude(account=bsu).exclude(obj=None).exclude(credit=None) \
.values('account', 'obj') \
.annotate(amount=Sum('credit'),
unit=F('unit'),
price=Sum(F('credit') * F('curr_rate')),
currency=F('side__unit'))
nasabah_dict = {n.id: n for n in Nasabah.objects.filter(pk__in={tx['account'] for tx in transactions_dicts})}
waste_dict = {w.id: w for w in WasteType.objects.filter(pk__in={tx['obj'] for tx in transactions_dicts})}
transactions_units = []
for tx in transactions_dicts:
tx['nasabah'] = nasabah_dict[tx['account']]
tx['waste'] = waste_dict[tx['obj']]
transactions_units.append(WasteTransactionUnit(waste=tx['waste'], data_dict=tx))
summary = TransactionSummary(transactions_units)
summary_nasabah = defaultdict(TransactionSummary)
for tx in transactions_dicts:
summary_nasabah[tx['nasabah']].add_tx(WasteTransactionUnit(waste=tx['waste'], data_dict=tx))
summary_nasabah.default_factory = None
return render(request, 'transaction/deposit/deposit-detail.html', {
'section': 'setoran',
'summary': summary,
'summary_nasabah': summary_nasabah,
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment