Source code for tendril.costing.breakup
#!/usr/bin/env python
# encoding: utf-8
# Copyright (C) 2016-2019 Chintalagiri Shashank
#
# This file is part of tendril.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Hierarchical Analysis of Costing Information
--------------------------------------------
"""
import json
from six import viewitems
from tendril.conventions.electronics import parse_ident
from tendril.utils.types.currency import native_currency_defn
from tendril.utils.types.currency import CurrencyValue
[docs]class CostingBreakupBase(object):
def __init__(self, name):
self._name = name
self._currency_symbol = native_currency_defn.symbol
@property
def name(self):
return self._name
@property
def currency_symbol(self):
return self._currency_symbol
@property
def total_cost(self):
raise NotImplementedError
@property
def sections(self):
raise NotImplementedError
@property
def content(self):
return [{'name': k, 'children': v} for k, v in self._content]
@property
def _content(self):
raise NotImplementedError
@property
def json(self):
return json.dumps(
{'name': self._name,
'children': self.content
}
)
[docs]class OBomCostingBreakup(CostingBreakupBase):
def __init__(self, name):
super(OBomCostingBreakup, self).__init__(name)
self._devices = {}
self._total_cost = CurrencyValue(0, native_currency_defn)
[docs] def insert(self, ident, cost):
d, v, f = parse_ident(ident)
if d not in self._devices.keys():
self._devices[d] = []
self._devices[d].append(
{'name': ident,
'size': cost.native_value}
)
self._total_cost += cost
[docs] def sort(self):
for d in self._devices.keys():
self._devices[d].sort(key=lambda x: x['size'], reverse=True)
@property
def sections(self):
return None
@property
def total_cost(self):
return self._total_cost
@property
def _content(self):
return sorted(viewitems(self._devices),
key=lambda x: sum(y['size'] for y in x[1]),
reverse=True)
[docs]class HierachicalCostingBreakup(CostingBreakupBase):
def __init__(self, name):
super(HierachicalCostingBreakup, self).__init__(name)
self._sections = {}
self._counters = {}
@property
def sections(self):
if self.total_cost == 0:
return []
seclist = [
(k, int((v.total_cost / self.total_cost) * 100), v.total_cost)
for k, v in viewitems(self._sections)
]
return sorted(seclist, key=lambda x: x[1], reverse=True)
@property
def total_cost(self):
return sum([v.total_cost for k, v in viewitems(self._sections)])
[docs] def insert(self, ident, breakup):
if ident not in self._sections.keys():
self._sections[ident] = breakup
else:
if ident in self._counters.keys():
self._counters[ident] += 1
else:
self._counters[ident] = 2
newname = '.'.join([ident, '1'])
self._sections[newname] = self._sections.pop(ident)
newname = '.'.join([ident, str(self._counters[ident])])
self._sections[newname] = breakup
@property
def _content(self):
return sorted(viewitems(self._sections),
key=lambda x: x[1].total_cost,
reverse=True)