Commit 92bf8075 authored by Jérome Perrin's avatar Jérome Perrin

group_by_time_sequence_list

parent d810b3ef
......@@ -1633,6 +1633,216 @@ class TestInventoryList(InventoryAPITestCase):
self.assertEqual([r for r in inventory_list
if r.getObject().getUse() == 'use2'][0].inventory, 11)
def test_group_by_time_sequence(self):
getInventoryList = self.getSimulationTool().getInventoryList
# Create 3 groups of movements:
self._makeMovement(quantity=1, start_date=DateTime('2016/01/01'))
self._makeMovement(quantity=3, start_date=DateTime('2016/02/01'))
self._makeMovement(quantity=5, start_date=DateTime('2016/02/02'))
self._makeMovement(quantity=7, start_date=DateTime('2016/03/01'))
# Create "noise" movement that we should not select
self._makeMovement(
quantity=10,
start_date=DateTime('2016/02/01'),
destination_value=self.portal.organisation_module.newContent())
inventory_list = getInventoryList(
node_uid=self.node.getUid(),
group_by_time_sequence_list=(
{'at_date': DateTime('2016/01/01').latestTime()},
{'from_date': DateTime('2016/02/01'), 'to_date': DateTime('2016/03/01')},
{'from_date': DateTime('2016/03/01')},
)
)
self.assertEqual(3, len(inventory_list))
self.assertEqual(1, inventory_list[0].total_quantity)
self.assertEqual(0, inventory_list[0].slot_index)
self.assertEqual(3 + 5, inventory_list[1].total_quantity)
self.assertEqual(1, inventory_list[1].slot_index)
self.assertEqual(7, inventory_list[2].total_quantity)
self.assertEqual(2, inventory_list[2].slot_index)
# now using all combinasion of from_date, at_date & to_date
inventory_list = getInventoryList(
node_uid=self.node.getUid(),
group_by_time_sequence_list=(
{'at_date': DateTime('2016/01/01').latestTime()},
{'to_date': DateTime('2016/01/02')}, # equivalent to above
{'from_date': DateTime('2016/02/01'), 'at_date': DateTime('2016/02/29').latestTime()},
{'from_date': DateTime('2016/02/01'), 'to_date': DateTime('2016/03/01')},
{'from_date': DateTime('2016/03/01')},
)
)
self.assertEqual([1, 1, 3+5, 3+5, 7], [x.inventory for x in inventory_list])
def test_group_by_time_sequence_empty_slots_are_returned(self):
getInventoryList = self.getSimulationTool().getInventoryList
self._makeMovement(title="M1", quantity=3, start_date=DateTime('2016/01/01'))
self._makeMovement(title="M2", quantity=5, start_date=DateTime('2016/02/01'))
inventory_list = getInventoryList(
node_uid=self.node.getUid(),
group_by_time_sequence_list=(
# before M1 -> empty
{'at_date': DateTime('2001/01/01').latestTime()},
{'to_date': DateTime('2001/01/01')},
{'from_date': DateTime('1999/01/01'), 'to_date': DateTime('2001/01/01')},
{'from_date': DateTime('1999/01/01'), 'at_date': DateTime('2001/01/01')},
# selecting M1
{'from_date': DateTime('2016/01/01'), 'to_date': DateTime('2016/01/02')},
# between M1 & M2 -> empty
{'from_date': DateTime('2016/01/02'), 'at_date': DateTime('2001/01/03')},
{'from_date': DateTime('2016/01/02'), 'to_date': DateTime('2001/01/03')},
# selecting M2
{'from_date': DateTime('2016/02/01'), 'to_date': DateTime('2016/02/03')},
# after M2 -> empty
{'from_date': DateTime('2016/02/03'), 'to_date': DateTime('2016/02/04')},
{'from_date': DateTime('2016/02/03'), 'at_date': DateTime('2001/02/04')},
{'from_date': DateTime('2016/02/03')},
)
)
self.assertEqual(
[
0, 0, 0, 0,
3,
0, 0,
5,
0, 0, 0
], [x.inventory for x in inventory_list])
def test_group_by_time_sequence_invalid_inputs(self):
getInventoryList = self.getSimulationTool().getInventoryList
self._makeMovement(title="M1", quantity=3, start_date=DateTime('2016/01/02'))
# no from_date, at_date or to_date on a slot raise a ValueError
with self.assertRaises(ValueError):
getInventoryList(
node_uid=self.node.getUid(),
group_by_time_sequence_list=(
{},
)
)
# slots where start_date > stop_date are valid, but select nothing
self.assertEqual(
[0],
[x.inventory for x in
getInventoryList(
node_uid=self.node.getUid(),
group_by_time_sequence_list=(
{ 'from_date': DateTime('2016/01/03'),
'at_date': DateTime('2016/01/01') }
)
)
]
)
self.assertEqual(
[0],
[x.inventory for x in
getInventoryList(
node_uid=self.node.getUid(),
group_by_time_sequence_list=(
{ 'from_date': DateTime('2016/01/03'),
'to_date': DateTime('2016/01/01') }
)
)
]
)
def test_group_by_time_sequence_with_interpolation_method(self):
getInventoryList = self.getSimulationTool().getInventoryList
self._makeMovement(
quantity=10,
title="M1",
start_date=DateTime('2016/01/01 01:00:00'),
stop_date=DateTime('2016/01/01 11:00:00'),
)
self._makeMovement(
quantity=5,
title="M2",
start_date=DateTime('2016/01/01 10:00:00'),
stop_date=DateTime('2016/01/01 15:00:00'),
)
self._makeMovement(
title="M3",
quantity=10,
start_date=DateTime("2016/01/01 05:00:00"),
stop_date=DateTime("2016/01/01 15:00:00"),
)
self._makeMovement(
title="M4",
quantity=5,
start_date=DateTime("2016/01/01 18:00:00"),
stop_date=DateTime("2016/01/01 23:00:00"),
)
self._makeMovement(
title="M5",
destination_value=self.portal.organisation_module.newContent(),
quantity=10,
start_date=DateTime("2016/01/01 08:00:00"),
stop_date=DateTime("2016/01/01 17:00:00"),
)
# We have created these movements:
# 00:00 10:00 20:00
# | | |
# M1 XXXXXXXXXX
# M2 XXXXX
# M3 XXXXXXXXXX
# M4 XXXXX
# M5 YYYYYYYYYY (will not be counted because on another node)
# | | |
# We will query with this time sequence:
# 00:00 10:00 20:00
# | | | expected quantity:
# ... ] 1 ( M1 )
# [ ] 3 ( M1 )
# [] 5 ( M1 + M2 + M3)
# [ ... 2 ( M4 )
# M1 XXXXXXXXXX
# M2 XXXXX
# M3 XXXXXXXXXX
# M4 XXXXX
# M5 YYYYYYYYYY
# | | |
inventory_list = getInventoryList(
node_uid=self.node.getUid(),
interpolation_method='linear',
group_by_time_sequence_list=(
{'at_date': DateTime('2016/01/01 02:00:00')},
{'from_date': DateTime('2016/01/01 01:00:00'), 'to_date': DateTime('2016/01/01 04:00:00')},
{'from_date': DateTime('2016/01/01 09:00:00'), 'to_date': DateTime('2016/01/01 11:00:00')},
{'from_date': DateTime('2016/01/01 21:00:00'), },
)
)
self.assertEqual(
[1, 3, 5, 2],
[x.inventory for x in inventory_list])
def test_OmitInputOmitOutput(self):
getInventoryList = self.getSimulationTool().getInventoryList
self._makeMovement(quantity=1, price=1)
......
......@@ -594,6 +594,7 @@ class SimulationTool(BaseTool):
group_by_function_category=0,
group_by_function_category_strict_membership=0,
group_by_date=0,
group_by_time_sequence_list=None,
# sort_on
sort_on=None,
group_by=None,
......@@ -648,6 +649,7 @@ class SimulationTool(BaseTool):
if date_dict:
column_value_dict['date'] = date_dict
if interpolation_method != 'default':
if not group_by_time_sequence_list:
if not (from_date and (to_date or at_date)):
raise ValueError("date_range is required to use interpolation_method")
# if we consider flow, we also select movement whose mirror date is
......@@ -965,6 +967,8 @@ class SimulationTool(BaseTool):
new_kw['related_key_select_expression_list'] =\
related_key_select_expression_list
# XXX
sql_kw['group_by_time_sequence_list'] = group_by_time_sequence_list
return sql_kw, new_kw
#######################################################
......@@ -1186,6 +1190,7 @@ class SimulationTool(BaseTool):
group_by_section_category=0,
group_by_section_category_strict_membership=0,
group_by_resource=None,
group_by_time_sequence_list=(),
movement_list_mode=0,
group_by=None,
**ignored):
......@@ -1211,7 +1216,8 @@ class SimulationTool(BaseTool):
group_by_mirror_section or group_by_payment or \
group_by_sub_variation or group_by_variation or \
group_by_movement or group_by_date or group_by_section_category or\
group_by_section_category_strict_membership:
group_by_section_category_strict_membership or \
group_by_time_sequence_list:
if group_by_resource is None:
group_by_resource = 1
new_group_by_dict['group_by_resource'] = group_by_resource
......@@ -1329,7 +1335,8 @@ class SimulationTool(BaseTool):
# Get cached data
if getattr(self, "Resource_zGetInventoryCacheResult", None) is not None and \
optimisation__ and (not kw.get('from_date')) and \
'transformed_resource' not in kw:
'transformed_resource' not in kw \
and "group_by_time_sequence_list" not in kw:
# Here is the different kind of date
# from_date : >=
# to_date : <
......
......@@ -4,6 +4,7 @@
interpolation_method_from_date=interpolation_method_from_date,
interpolation_method_to_date=interpolation_method_to_date,
interpolation_method_at_date=interpolation_method_at_date,
group_by_time_sequence_list=group_by_time_sequence_list,
src__=1)">
SELECT
......@@ -75,6 +76,8 @@ SELECT
COUNT(DISTINCT <dtml-var stock_table_id>.uid) AS stock_uid,
MAX(<dtml-var stock_table_id>.date) AS date
</dtml-if>
<dtml-if group_by_time_sequence_list>, slot_index </dtml-if> <dtml-comment>XXX is this really needed? are empty slots returned ? </dtml-comment>
<dtml-if select_expression>, <dtml-var select_expression></dtml-if>
FROM
......@@ -88,6 +91,55 @@ FROM
</dtml-if>
</dtml-in>
, <dtml-var stock_table_id>
<dtml-if group_by_time_sequence_list>
RIGHT JOIN
( <dtml-in prefix="time_slot" expr="_.list(_.enumerate(group_by_time_sequence_list))">
SELECT
<dtml-sqlvar expr="time_slot_key" type="int"> slot_index,
<dtml-sqlvar expr="time_slot_item.get('from_date')" type="datetime" optional> slot_from_date,
<dtml-sqlvar expr="time_slot_item.get('at_date')" type="datetime" optional> slot_at_date,
<dtml-sqlvar expr="time_slot_item.get('to_date')" type="datetime" optional> slot_to_date
<dtml-unless time_slot_end>UNION ALL</dtml-unless>
</dtml-in> ) slots
ON
<dtml-if group_by_time_sequence_list>
(
( slot_from_date is not null AND
( slot_at_date is not null AND
GREATEST(`stock`.`date`, `stock`.`mirror_date`) >= slot_from_date AND
LEAST(`stock`.`date`, `stock`.`mirror_date`) <= slot_at_date
) OR (
(
slot_to_date is not null AND
GREATEST(`stock`.`date`, `stock`.`mirror_date`) >= slot_from_date AND
LEAST(`stock`.`date`, `stock`.`mirror_date`) < slot_to_date
) OR (
GREATEST(`stock`.`date`, `stock`.`mirror_date`) >= slot_from_date AND
slot_at_date is null AND slot_to_date is null
)
)
) OR (
slot_from_date is null AND (
( slot_at_date is not null AND
( LEAST(`stock`.`date`, `stock`.`mirror_date`) <= slot_at_date )
) OR LEAST(`stock`.`date`, `stock`.`mirror_date`) < slot_to_date
)
)
)
<dtml-else>
(
( slot_from_date is null OR stock.date >= slot_from_date )
AND ( slot_at_date is null OR stock.date <= slot_at_date )
AND ( slot_to_date is null OR stock.date < slot_to_date )
)
</dtml-if>
</dtml-if>
</dtml-if>
<dtml-if quantity_unit_uid> <dtml-comment>XXX quantity unit conversion will not work when using implict_join=False</dtml-comment>
LEFT JOIN quantity_unit_conversion ON
......@@ -135,10 +187,16 @@ WHERE
<dtml-if group_by_expression>
GROUP BY
<dtml-if transformed_uid>transformation.transformed_uid,</dtml-if>
<dtml-if group_by_time_sequence_list>slot_index,</dtml-if>
<dtml-var group_by_expression>
</dtml-if>
<dtml-if order_by_expression>
ORDER BY
<dtml-var order_by_expression>
<dtml-else>
<dtml-if group_by_time_sequence_list>
ORDER BY slot_index
</dtml-if>
</dtml-if>
</dtml-let>
\ No newline at end of file
......@@ -46,6 +46,7 @@ quantity_unit_uid\r\n
stock_table_id=stock\r\n
transformed_uid\r\n
transformed_variation_text\r\n
group_by_time_sequence_list:list\r\n
interpolation_method\r\n
interpolation_method_from_date=not_applicable\r\n
interpolation_method_to_date=not_applicable\r\n
......
<dtml-if expr="interpolation_method == 'linear'">
<dtml-if group_by_time_sequence_list>
CASE
WHEN <dtml-var stock_table_id>.mirror_date = <dtml-var stock_table_id>.date THEN 1
ELSE (
UNIX_TIMESTAMP(
IFNULL(
LEAST(
IFNULL(slot_at_date, slot_to_date),
GREATEST(<dtml-var stock_table_id>.date, <dtml-var stock_table_id>.mirror_date)
),
GREATEST(<dtml-var stock_table_id>.date, <dtml-var stock_table_id>.mirror_date)
)
)
- UNIX_TIMESTAMP(
GREATEST(
IFNULL(
slot_from_date, TIMESTAMP(0)
),
LEAST(<dtml-var stock_table_id>.date, <dtml-var stock_table_id>.mirror_date)
)
)
)
/ (
UNIX_TIMESTAMP(GREATEST(<dtml-var stock_table_id>.date, <dtml-var stock_table_id>.mirror_date)) -
UNIX_TIMESTAMP(LEAST(<dtml-var stock_table_id>.date, <dtml-var stock_table_id>.mirror_date)) ) END
<dtml-else>
CASE
WHEN <dtml-var stock_table_id>.mirror_date = <dtml-var stock_table_id>.date THEN 1
ELSE (
......@@ -13,6 +39,7 @@
LEAST(<dtml-var stock_table_id>.date, <dtml-var stock_table_id>.mirror_date))))
/ ( UNIX_TIMESTAMP(GREATEST(<dtml-var stock_table_id>.date, <dtml-var stock_table_id>.mirror_date)) -
UNIX_TIMESTAMP(LEAST(<dtml-var stock_table_id>.date, <dtml-var stock_table_id>.mirror_date)) ) END
</dtml-if>
<dtml-elif expr="interpolation_method == 'all_or_nothing'">
CASE
WHEN (
......
......@@ -12,7 +12,8 @@
interpolation_method\r\n
interpolation_method_from_date\r\n
interpolation_method_to_date\r\n
interpolation_method_at_date</string> </value>
interpolation_method_at_date\r\n
group_by_time_sequence_list:list</string> </value>
</item>
<item>
<key> <string>connection_id</string> </key>
......
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