Commit d87b9db8 authored by Jérome Perrin's avatar Jérome Perrin

Reimplement fast=True for getTotalPrice/Quantity using inventory API

parent 5764dcc8
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>allow_simple_one_argument_traversal</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string>uid</string> </value>
</item>
<item>
<key> <string>cache_time_</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>class_file_</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>class_name_</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>connection_hook</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>DeliveryLine_zGetTotal</string> </value>
</item>
<item>
<key> <string>max_cache_</string> </key>
<value> <int>100</int> </value>
</item>
<item>
<key> <string>max_rows_</string> </key>
<value> <int>1000</int> </value>
</item>
<item>
<key> <string>src</string> </key>
<value> <string encoding="cdata"><![CDATA[
SELECT \n
\tSUM(quantity) AS total_quantity, \n
\tSUM(quantity * price) AS total_price, \n
\tAVG(price) AS average_price\n
FROM catalog, movement\n
WHERE \n
\tcatalog.parent_uid = <dtml-sqlvar uid type="int">\n
AND\t\n
\tcatalog.uid = movement.uid\n
]]></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>allow_simple_one_argument_traversal</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string>from_table_list:list\r\n
where_expression\r\n
order_by_expression</string> </value>
</item>
<item>
<key> <string>cache_time_</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>class_file_</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>class_name_</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>connection_hook</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_zGetTotal</string> </value>
</item>
<item>
<key> <string>max_cache_</string> </key>
<value> <int>100</int> </value>
</item>
<item>
<key> <string>max_rows_</string> </key>
<value> <int>1000</int> </value>
</item>
<item>
<key> <string>src</string> </key>
<value> <string encoding="cdata"><![CDATA[
SELECT\n
SUM(movement.quantity) AS inventory,\n
SUM(movement.quantity) AS total_quantity,\n
SUM(movement.price * movement.quantity) AS total_price,\n
AVG(movement.price) AS average_price\n
\n
FROM\n
<dtml-in from_table_list> <dtml-var sequence-item> AS <dtml-var sequence-key><dtml-if sequence-end><dtml-else>,</dtml-if></dtml-in>\n
\n
WHERE\n
1=1\n
<dtml-if where_expression>\n
AND <dtml-var where_expression> \n
</dtml-if>\n
AND catalog.has_cell_content = 0\n
AND catalog.portal_type NOT IN ("Container", "Container Line", "Container Cell", "Simulation Movement")\n
\n
<dtml-if order_by_expression>\n
ORDER BY <dtml-var order_by_expression>\n
</dtml-if>\n
]]></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -91,6 +91,7 @@ class Delivery(XMLObject, ImmobilisationDelivery, SimulableMixin,
'getTotalPrice')
def getTotalPrice(self, fast=0, src__=0, base_contribution=None, rounding=False, **kw):
""" Returns the total price for this order
if the `fast` argument is set to a true value, then it use
SQLCatalog to compute the price, otherwise it sums the total
price of objects one by one.
......@@ -98,49 +99,51 @@ class Delivery(XMLObject, ImmobilisationDelivery, SimulableMixin,
So if the order is not in the catalog, getTotalPrice(fast=1)
will return 0, this is not a bug.
base_contribution must be a relative url of a category.
base_contribution must be a relative url of a category. If passed, then
fast parameter is ignored.
"""
result = None
if not fast:
kw.setdefault( 'portal_type',
self.getPortalDeliveryMovementTypeList())
if base_contribution is None:
result = sum([ line.getTotalPrice(fast=0) for line in
self.objectValues(**kw) ])
kw.setdefault( 'portal_type',
self.getPortalDeliveryMovementTypeList())
if base_contribution is None:
if fast:
# XXX fast ignores base_contribution for now, but it should be possible
# to use a related key
kw['section_uid'] = self.getDestinationSectionUid()
kw['stock.explanation_uid'] = self.getUid()
return self.getPortalObject()\
.portal_simulation.getInventoryAssetPrice(**kw)
result = sum([ line.getTotalPrice(fast=0) for line in
self.objectValues(**kw) ])
else:
# Find amounts from movements in the delivery.
if isinstance(base_contribution, (tuple, list)):
base_contribution_list = base_contribution
else:
# Find amounts from movements in the delivery.
if isinstance(base_contribution, (tuple, list)):
base_contribution_list = base_contribution
else:
base_contribution_list = (base_contribution,)
base_contribution_value_list = []
portal_categories = self.portal_categories
for relative_url in base_contribution_list:
base_contribution_value = portal_categories.getCategoryValue(relative_url)
if base_contribution_value is not None:
base_contribution_value_list.append(base_contribution_value)
if not base_contribution_value_list:
# We cannot find any amount so that the result is 0.
result = 0
else:
base_contribution_list = (base_contribution,)
base_contribution_value_list = []
portal_categories = self.portal_categories
for relative_url in base_contribution_list:
base_contribution_value = portal_categories.getCategoryValue(relative_url)
if base_contribution_value is not None:
base_contribution_value_list.append(base_contribution_value)
if not base_contribution_value_list:
# We cannot find any amount so that the result is 0.
result = 0
else:
matched_movement_list = [
movement
for movement in self.getMovementList()
if set(movement.getBaseContributionValueList()).intersection(base_contribution_value_list)]
if rounding:
portal_roundings = self.portal_roundings
matched_movement_list = [
movement
for movement in self.getMovementList()
if set(movement.getBaseContributionValueList()).intersection(base_contribution_value_list)]
if rounding:
portal_roundings = self.portal_roundings
matched_movement_list = [
portal_roundings.getRoundingProxy(movement)
for movement in matched_movement_list]
result = sum([movement.getTotalPrice()
for movement in matched_movement_list])
else:
kw['explanation_uid'] = self.getUid()
kw.update(self.portal_catalog.buildSQLQuery(**kw))
if src__:
return self.Delivery_zGetTotal(src__=1, **kw)
aggregate = self.Delivery_zGetTotal(**kw)[0]
result = aggregate.total_price or 0
portal_roundings.getRoundingProxy(movement)
for movement in matched_movement_list]
result = sum([movement.getTotalPrice()
for movement in matched_movement_list])
method = self._getTypeBasedMethod('convertTotalPrice')
if method is not None:
return method(result)
......@@ -164,6 +167,7 @@ class Delivery(XMLObject, ImmobilisationDelivery, SimulableMixin,
'getTotalQuantity')
def getTotalQuantity(self, fast=0, src__=0, **kw):
""" Returns the total quantity of this order.
if the `fast` argument is set to a true value, then it use
SQLCatalog to compute the quantity, otherwise it sums the total
quantity of objects one by one.
......@@ -171,17 +175,14 @@ class Delivery(XMLObject, ImmobilisationDelivery, SimulableMixin,
So if the order is not in the catalog, getTotalQuantity(fast=1)
will return 0, this is not a bug.
"""
if not fast :
kw.setdefault('portal_type',
self.getPortalDeliveryMovementTypeList())
return sum([ line.getTotalQuantity(fast=0) for line in
self.objectValues(**kw) ])
kw['explanation_uid'] = self.getUid()
kw.update(self.portal_catalog.buildSQLQuery(**kw))
if src__:
return self.Delivery_zGetTotal(src__=1, **kw)
aggregate = self.Delivery_zGetTotal(**kw)[0]
return aggregate.total_quantity or 0
kw.setdefault('portal_type',
self.getPortalDeliveryMovementTypeList())
if fast:
kw['section_uid'] = self.getDestinationSectionUid()
kw['stock.explanation_uid'] = self.getUid()
return self.getPortalObject().portal_simulation.getInventory(**kw)
return sum([ line.getTotalQuantity(fast=0) for line in
self.objectValues(**kw) ])
security.declareProtected(Permissions.AccessContentsInformation,
'getDeliveryUid')
......
......@@ -116,16 +116,23 @@ class DeliveryLine(Movement, XMLObject, XMLMatrix, ImmobilisationMovement):
if hasLineContent: return sum of lines total price
if hasCellContent: return sum of cells total price
else: return quantity * price
if fast is argument true, then a SQL method will be used.
"""
if fast argument is true, inventory API will be used.
"""
if fast:
kw = {}
kw['section_uid'] = self.getDestinationSectionUid()
kw['stock.explanation_uid'] = self.getExplanationUid()
kw['relative_url'] = ( '%s/%%' % (
self.getRelativeUrl().replace('_', '\\_')),
self.getRelativeUrl() )
kw['only_accountable'] = False
return self.getPortalObject().portal_simulation.getInventoryAssetPrice(**kw)
if self.hasLineContent():
meta_type = self.meta_type
return sum(l.getTotalPrice(context=context)
for l in self.objectValues() if l.meta_type==meta_type)
elif not self.hasCellContent(base_id='movement'):
return Movement._getTotalPrice(self, default=default, context=context)
elif fast: # Use MySQL
return self.DeliveryLine_zGetTotal()[0].total_price or 0.0
return sum(cell.getTotalPrice(default=0.0, context=context)
for cell in self.getCellValueList())
......@@ -138,20 +145,27 @@ class DeliveryLine(Movement, XMLObject, XMLMatrix, ImmobilisationMovement):
if hasLineContent: return sum of lines total quantity
if hasCellContent: return sum of cells total quantity
else: return quantity
if fast argument is true, then a SQL method will be used.
if fast argument is true, inventory API will be used.
"""
if fast:
kw = {}
kw['section_uid'] = self.getDestinationSectionUid()
kw['stock.explanation_uid'] = self.getExplanationUid()
kw['relative_url'] = ( '%s/%%' % (
self.getRelativeUrl().replace('_', '\\_')),
self.getRelativeUrl() )
kw['only_accountable'] = False
return self.getPortalObject().portal_simulation.getInventory(**kw)
base_id = 'movement'
if self.hasLineContent():
meta_type = self.meta_type
return sum(l.getTotalQuantity() for l in
self.objectValues() if l.meta_type==meta_type)
elif self.hasCellContent(base_id=base_id):
if fast : # Use MySQL
aggregate = self.DeliveryLine_zGetTotal()[0]
return aggregate.total_quantity or 0.0
return sum([cell.getQuantity() for cell in self.getCellValueList()])
else:
return self.getQuantity()
return self.getQuantity()
security.declareProtected(Permissions.AccessContentsInformation,
'hasLineContent')
......
......@@ -72,6 +72,8 @@ class Order(Delivery):
If base_contribution is passed, the trade model lines will be used to
include movements that will be generated.
"""
if kw.get('fast'):
kw['only_accountable'] = False
rounding = kw.get('rounding')
if kw.get('base_contribution') is None:
kw.setdefault('portal_type', self.getPortalOrderMovementTypeList())
......@@ -118,6 +120,8 @@ class Order(Delivery):
def getTotalQuantity(self, **kw) :
"""Returns the total quantity for this Order. """
kw.setdefault('portal_type', self.getPortalOrderMovementTypeList())
if kw.get('fast'):
kw['only_accountable'] = False
return Delivery.getTotalQuantity(self, **kw)
@deprecated
......
......@@ -353,19 +353,30 @@ class TestOrderMixin(SubcontentReindexingWrapper):
def stepCheckOrder(self, sequence=None, sequence_list=None, **kw):
"""
Check if order was well created
"""
organisation = sequence.get('organisation')
project = sequence.get('project')
Check if order was well created, either by stepCreateOrder of
stepSetOrderProfile
"""
source_organisation = sequence.get('organisation1')
if source_organisation is None:
source_organisation = sequence.get('organisation')
destination_organisation = sequence.get('organisation2')
if destination_organisation is None:
destination_organisation = sequence.get('organisation')
source_project = sequence.get('project1')
if source_project is None:
source_project = sequence.get('project')
destination_project = sequence.get('project2')
if destination_project is None:
destination_project = sequence.get('project')
order = sequence.get('order')
self.assertEquals(self.datetime+10, order.getStartDate())
self.assertEquals(self.datetime+20, order.getStopDate())
self.assertEquals(organisation, order.getSourceValue())
self.assertEquals(organisation, order.getDestinationValue())
self.assertEquals(organisation, order.getSourceSectionValue())
self.assertEquals(organisation, order.getDestinationSectionValue())
self.assertEquals(project, order.getSourceProjectValue())
self.assertEquals(project, order.getDestinationProjectValue())
self.assertEquals(source_organisation, order.getSourceValue())
self.assertEquals(destination_organisation, order.getDestinationValue())
self.assertEquals(source_organisation, order.getSourceSectionValue())
self.assertEquals(destination_organisation, order.getDestinationSectionValue())
self.assertEquals(source_project, order.getSourceProjectValue())
self.assertEquals(destination_project, order.getDestinationProjectValue())
def stepCreateOrderLine(self,sequence=None, sequence_list=None, **kw):
......@@ -736,7 +747,7 @@ class TestOrderMixin(SubcontentReindexingWrapper):
order_line_list = map(lambda x: x.getObject(), order_line_list)
total_price = 0
for order_line in order_line_list:
total_price += order_line.getTotalPrice(fast=0)
total_price += order_line.getTotalPrice()
self.assertEquals(0, len(portal_catalog(relative_url=order.getRelativeUrl())))
self.assertEquals(total_price, order.getTotalPrice(fast=0))
self.assertNotEquals(total_price, 0)
......@@ -1148,7 +1159,12 @@ class TestOrderMixin(SubcontentReindexingWrapper):
'adopt_prevision_action')
non_variated_order_creation = '\
stepCreateOrganisation1 \
stepCreateOrganisation2 \
stepCreateProject1 \
stepCreateProject2 \
stepCreateOrder \
stepSetOrderProfile \
stepCreateNotVariatedResource \
stepCreateOrderLine \
stepCheckOrderLineEmptyMatrix \
......@@ -1158,7 +1174,12 @@ class TestOrderMixin(SubcontentReindexingWrapper):
'
variated_order_line_creation = '\
stepCreateOrganisation1 \
stepCreateOrganisation2 \
stepCreateProject1 \
stepCreateProject2 \
stepCreateOrder \
stepSetOrderProfile \
stepCreateVariatedResource \
stepCreateOrderLine \
'
......@@ -1590,7 +1611,12 @@ class TestOrder(TestOrderMixin, ERP5TypeTestCase):
sequence_list = SequenceList()
# Test with positive price order line and negative price order line.
sequence_string = '\
stepCreateOrganisation1 \
stepCreateOrganisation2 \
stepCreateProject1 \
stepCreateProject2 \
stepCreateOrder \
stepSetOrderProfile \
stepCheckOrderTotalQuantity \
stepCreateNotVariatedResource \
stepCreateOrderLine \
......@@ -2250,11 +2276,15 @@ class TestOrder(TestOrderMixin, ERP5TypeTestCase):
"""
if not run: return
portal = self.getPortal()
portal = self.portal
base_id = 'movement'
order_line_vcl=['size/Baby']
section = portal.organisation_module.newContent(
portal_type='Organisation')
order_module = portal.getDefaultModule(portal_type=self.order_portal_type)
order = order_module.newContent(portal_type=self.order_portal_type,
destination_section_value=section,
destination_value=section,
specialise=self.business_process)
# No line, no movement
self.assertEquals(order.getTotalQuantity(fast=0), 0)
......
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