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/189/head
ThomasBinsfeld 8 years ago
committed by Stéphane Bidoul
parent
commit
8e4e046aee
  1. 0
      mis_builder/__openerp__.py
  2. 136
      mis_builder/models/accounting_none.py
  3. 7
      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()

7
mis_builder/models/aep.py

@ -8,6 +8,8 @@ from collections import defaultdict
from openerp.exceptions import Warning as UserError
from openerp.models import expression
from openerp.tools.safe_eval import safe_eval
from openerp.tools.translate import _
from .accounting_none import AccountingNone
MODE_VARIATION = 'p'
MODE_INITIAL = 'i'
@ -228,12 +230,13 @@ class AccountingExpressionProcessor(object):
field, mode, account_codes, domain = self._parse_match_object(mo)
key = (domain, mode)
account_ids_data = self._data[key]
v = 0.0
v = AccountingNone
for account_code in account_codes:
account_ids = self._account_ids_by_code[account_code]
for account_id in account_ids:
debit, credit = \
account_ids_data.get(account_id, (0.0, 0.0))
account_ids_data.get(account_id,
(AccountingNone, AccountingNone))
if field == 'bal':
v += debit - credit
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 .aggregate import _sum, _avg, _min, _max
from .accounting_none import AccountingNone
_logger = logging.getLogger(__name__)
@ -142,8 +143,8 @@ class MisReportKpi(models.Model):
def render(self, lang_id, value):
""" render a KPI value as a unicode string, ready for display """
assert len(self) == 1
if value is None:
return '#N/A'
if value is None or value is AccountingNone:
return ''
elif self.type == 'num':
return self._render_num(lang_id, value, self.divider,
self.dp, self.prefix, self.suffix)
@ -469,6 +470,7 @@ class MisReportInstancePeriod(models.Model):
'max': _max,
'len': len,
'avg': _avg,
'AccountingNone': AccountingNone,
}
localdict.update(self._fetch_queries())
@ -515,7 +517,7 @@ class MisReportInstancePeriod(models.Model):
AEP.has_account_var(kpi.expression))
res[kpi.name] = {
'val': kpi_val,
'val': None if kpi_val is AccountingNone else kpi_val,
'val_r': kpi_val_rendered,
'val_c': kpi_val_comment,
'style': kpi_style,

Loading…
Cancel
Save