Browse Source

[ADD] AccountingNone (singleton) to differentiate balances among which the debit and the credit are zero and balances among which debit and credit nullify

pull/169/head
ThomasBinsfeld 9 years ago
committed by Thomas Binsfeld
parent
commit
d91746bb91
  1. 0
      mis_builder/__openerp__.py
  2. 136
      mis_builder/models/accounting_none.py
  3. 6
      mis_builder/models/aep.py
  4. 8
      mis_builder/models/mis_builder.py

0
mis_builder/__openerp__.py

136
mis_builder/models/accounting_none.py

@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
"""
Provides the AccountingNone singleton
AccountingNone is a null value that dissolves in basic arithmetic operations,
as illustrated in the examples below
>>> 1 + 1
2
>>> 1 + AccountingNone
1
>>> AccountingNone + 1
1
>>> AccountingNone + None
AccountingNone
>>> +AccountingNone
AccountingNone
>>> -AccountingNone
AccountingNone
>>> -(AccountingNone)
AccountingNone
>>> AccountingNone - 1
-1
>>> 1 - AccountingNone
1
>>> AccountingNone - None
AccountingNone
>>> AccountingNone / 2
0.0
>>> 2 / AccountingNone
Traceback (most recent call last):
...
ZeroDivisionError
>>> AccountingNone / AccountingNone
AccountingNone
>>> AccountingNone // 2
0.0
>>> 2 // AccountingNone
Traceback (most recent call last):
...
ZeroDivisionError
>>> AccountingNone // AccountingNone
AccountingNone
>>> AccountingNone * 2
0.0
>>> 2 * AccountingNone
0.0
>>> AccountingNone * AccountingNone
AccountingNone
>>> AccountingNone * None
AccountingNone
"""
class AccountingNoneType(object):
def __add__(self, other):
if other is None:
return AccountingNone
return other
__radd__ = __add__
def __sub__(self, other):
if other is None:
return AccountingNone
return -other
def __rsub__(self, other):
if other is None:
return AccountingNone
return other
def __iadd__(self, other):
if other is None:
return AccountingNone
return other
def __isub__(self, other):
if other is None:
return AccountingNone
return -other
def __pos__(self):
return self
def __neg__(self):
return self
def __floordiv__(self, other):
"""
Overload of the // operator
"""
if other is AccountingNone:
return AccountingNone
return 0.0
def __rfloordiv__(self, other):
raise ZeroDivisionError
def __truediv__(self, other):
"""
Overload of the / operator
"""
if other is AccountingNone:
return AccountingNone
return 0.0
def __rtruediv__(self, other):
raise ZeroDivisionError
def __mul__(self, other):
if other is None or other is AccountingNone:
return AccountingNone
return 0.0
def __rmul__(self, other):
if other is None or other is AccountingNone:
return AccountingNone
return 0.0
def __repr__(self):
return 'AccountingNone'
def __unicode__(self):
return ''
AccountingNone = AccountingNoneType()
if __name__ == '__main__':
import doctest
doctest.testmod()

6
mis_builder/models/aep.py

@ -9,6 +9,7 @@ from openerp.exceptions import Warning as UserError
from openerp.models import expression from openerp.models import expression
from openerp.tools.safe_eval import safe_eval from openerp.tools.safe_eval import safe_eval
from openerp.tools.translate import _ from openerp.tools.translate import _
from .accounting_none import AccountingNone
MODE_VARIATION = 'p' MODE_VARIATION = 'p'
MODE_INITIAL = 'i' MODE_INITIAL = 'i'
@ -348,12 +349,13 @@ class AccountingExpressionProcessor(object):
field, mode, account_codes, domain = self._parse_match_object(mo) field, mode, account_codes, domain = self._parse_match_object(mo)
key = (domain, mode) key = (domain, mode)
account_ids_data = self._data[key] account_ids_data = self._data[key]
v = 0.0
v = AccountingNone
for account_code in account_codes: for account_code in account_codes:
account_ids = self._account_ids_by_code[account_code] account_ids = self._account_ids_by_code[account_code]
for account_id in account_ids: for account_id in account_ids:
debit, credit = \ debit, credit = \
account_ids_data.get(account_id, (0.0, 0.0))
account_ids_data.get(account_id,
(AccountingNone, AccountingNone))
if field == 'bal': if field == 'bal':
v += debit - credit v += debit - credit
elif field == 'deb': elif field == 'deb':

8
mis_builder/models/mis_builder.py

@ -16,6 +16,7 @@ from openerp.tools.safe_eval import safe_eval
from .aep import AccountingExpressionProcessor as AEP from .aep import AccountingExpressionProcessor as AEP
from .aggregate import _sum, _avg, _min, _max from .aggregate import _sum, _avg, _min, _max
from .accounting_none import AccountingNone
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -140,8 +141,8 @@ class MisReportKpi(models.Model):
def render(self, lang_id, value): def render(self, lang_id, value):
""" render a KPI value as a unicode string, ready for display """ """ render a KPI value as a unicode string, ready for display """
assert len(self) == 1 assert len(self) == 1
if value is None:
return '#N/A'
if value is None or value is AccountingNone:
return ''
elif self.type == 'num': elif self.type == 'num':
return self._render_num(lang_id, value, self.divider, return self._render_num(lang_id, value, self.divider,
self.dp, self.prefix, self.suffix) self.dp, self.prefix, self.suffix)
@ -497,6 +498,7 @@ class MisReportInstancePeriod(models.Model):
'max': _max, 'max': _max,
'len': len, 'len': len,
'avg': _avg, 'avg': _avg,
'AccountingNone': AccountingNone,
} }
localdict.update(self._fetch_queries()) localdict.update(self._fetch_queries())
@ -544,7 +546,7 @@ class MisReportInstancePeriod(models.Model):
AEP.has_account_var(kpi.expression)) AEP.has_account_var(kpi.expression))
res[kpi.name] = { res[kpi.name] = {
'val': kpi_val,
'val': None if kpi_val is AccountingNone else kpi_val,
'val_r': kpi_val_rendered, 'val_r': kpi_val_rendered,
'val_c': kpi_val_comment, 'val_c': kpi_val_comment,
'style': kpi_style, 'style': kpi_style,

Loading…
Cancel
Save