Commit 0434841f authored by Julien Muchembled's avatar Julien Muchembled

amount_generator: make GeneratedAmountList really reusable

parent 7317246e
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
# #
############################################################################## ##############################################################################
from collections import defaultdict
import zope.interface import zope.interface
from AccessControl import allow_class from AccessControl import allow_class
from Products.ERP5Type import interfaces from Products.ERP5Type import interfaces
...@@ -35,6 +36,13 @@ class GeneratedAmountList(list): ...@@ -35,6 +36,13 @@ class GeneratedAmountList(list):
""" """
Temporary object needed to aggregate Amount value Temporary object needed to aggregate Amount value
And to calculate some report or total value And to calculate some report or total value
For example, delivery.getGeneratedAmountList() returns an object of this
type, with amounts for each movement and/or for the delivery. This result
can be used to get:
1. totals for the delivery, by first using aggregate()
2. detailed information on each movement with split(), which would be
equivalent to call getGeneratedAmountList() on each movement
""" """
zope.interface.implements(interfaces.IAmountList) zope.interface.implements(interfaces.IAmountList)
...@@ -61,6 +69,12 @@ class GeneratedAmountList(list): ...@@ -61,6 +69,12 @@ class GeneratedAmountList(list):
return result return result
def aggregate(self): def aggregate(self):
"""Return a list of aggregated amounts
Groups amounts with same price, efficiency, reference and categories, merge
them by summing their quantities, and return the new amounts in a new list.
"""
from Products.ERP5Type.Document import newTempAmount
# XXX: Do we handle rounding correctly ? # XXX: Do we handle rounding correctly ?
# What to do if only total price is rounded ?? # What to do if only total price is rounded ??
aggregate_dict = {} aggregate_dict = {}
...@@ -71,14 +85,33 @@ class GeneratedAmountList(list): ...@@ -71,14 +85,33 @@ class GeneratedAmountList(list):
aggregate = aggregate_dict.get(key) aggregate = aggregate_dict.get(key)
if aggregate is None: if aggregate is None:
aggregate_dict[key] = [amount, amount.getQuantity()] aggregate_dict[key] = [amount, amount.getQuantity()]
result_list.append(amount)
else: else:
aggregate[1] += amount.getQuantity() aggregate[1] += amount.getQuantity()
for amount, quantity in aggregate_dict.itervalues(): for amount, quantity in aggregate_dict.itervalues():
# Before we ignore 'quantity==0' amount here for better performance, # Before we ignore 'quantity==0' amount here for better performance,
# but it is not a good idea, especially when the first expand causes # but it is not a good idea, especially when the first expand causes
# non-zero quantity and then quantity becomes zero. # non-zero quantity and then quantity becomes zero.
amount._setQuantity(quantity) aggregate = newTempAmount(amount.aq_parent, '', notify_workflow=False)
result_list.append(aggregate)
aggregate.__dict__.update(amount.__dict__)
aggregate._setQuantity(quantity)
del aggregate._base
return result_list return result_list
def split(self):
"""Return a dictionary with all amounts grouped by base amount
Return {amount: amount_list} where
- amount is the Amount instance (e.g. movement, delivery)
that generated amounts
- amount_list is an instance of this class
This is the opposite of aggregate(), which merges amounts that only differ
by their base amounts.
"""
result = defaultdict(self.__class__)
for amount in self:
result[amount._base].append(amount)
return result
allow_class(GeneratedAmountList) allow_class(GeneratedAmountList)
...@@ -474,6 +474,7 @@ class AmountGeneratorMixin: ...@@ -474,6 +474,7 @@ class AmountGeneratorMixin:
property_dict['causality_value_list'][-1] property_dict['causality_value_list'][-1]
.getRelativeUrl().replace('/', '_'), .getRelativeUrl().replace('/', '_'),
notify_workflow=False) notify_workflow=False)
amount._base = delivery_amount
amount._setCategoryList(property_dict.pop('category_list', ())) amount._setCategoryList(property_dict.pop('category_list', ()))
if amount.getQuantityUnit(): if amount.getQuantityUnit():
del property_dict['quantity_unit'] del property_dict['quantity_unit']
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment