Commit ea6006d8 authored by Yusei Tahara's avatar Yusei Tahara Committed by Arnaud Fontaine

Fix an inventory bug. When there are more than 300 inventories which are...

Fix an inventory bug. When there are more than 300 inventories which are cancelled by inventory document, inventory document creates wrong stock records.
parent 18a02672
......@@ -198,6 +198,13 @@ class Inventory(Delivery):
inventory_id = self.getId()
list_method = inventory_calculation_dict['list_method']
method = getattr(self, list_method)
__order_id_counter_list = [0]
def getOrderIdCounter():
value = __order_id_counter_list[0]
__order_id_counter_list[0] = value + 1
return value
for movement in method():
if movement.getResourceValue() is not None and \
movement.getInventoriatedQuantity() not in (None, ''):
......@@ -240,7 +247,10 @@ class Inventory(Delivery):
# Create tmp movement
kwd = {'uid': movement.getUid(),
'start_date': stop_date}
'start_date': stop_date,
'order_id': getOrderIdCounter(),
'mirror_order_id':getOrderIdCounter()
}
temp_delivery_line = temp_constructor(self,
inventory_id)
......@@ -284,7 +294,10 @@ class Inventory(Delivery):
diff_quantity = - inventory_value[tuple(second_level_key)]
kwd = {'uid': inventory_uid,
'start_date': stop_date}
'start_date': stop_date,
'order_id': getOrderIdCounter(),
'mirror_order_id':getOrderIdCounter()
}
# create the tmp line and set category on it
temp_delivery_line = temp_constructor(self,
......@@ -320,8 +333,15 @@ class Inventory(Delivery):
immediate_reindex_archive=immediate_reindex_archive)
if stock_object_list:
# Delete existing records first.
self.portal_catalog.catalogObjectList(
stock_object_list[:], method_id_list=('z0_uncatalog_stock', ),
sql_catalog_id = sql_catalog_id,
disable_cache=1, check_uid=0, disable_archive=disable_archive,
immediate_reindex_archive=immediate_reindex_archive)
# Then insert new records without delete.
self.portal_catalog.catalogObjectList(
stock_object_list, method_id_list=('z_catalog_stock_list', ),
stock_object_list[:], method_id_list=('z_catalog_stock_list_without_delete_for_inventory_virtual_movement', ),
sql_catalog_id = sql_catalog_id,
disable_cache=1, check_uid=0, disable_archive=disable_archive,
immediate_reindex_archive=immediate_reindex_archive)
......@@ -54,7 +54,7 @@
<key> <string>src</string> </key>
<value> <string encoding="cdata"><![CDATA[
DELETE FROM stock WHERE <dtml-sqltest uid op=eq type=int>
DELETE FROM stock WHERE <dtml-sqltest uid op=eq type=int multiple>
]]></string> </value>
</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>arguments_src</string> </key>
<value> <string>uid\r\n
order_id\r\n
mirror_order_id\r\n
getExplanationUid\r\n
getResourceUid\r\n
getInventoriatedQuantity\r\n
getSourceUid\r\n
getDestinationUid\r\n
getSourceSectionUid\r\n
getDestinationSectionUid\r\n
isMovement\r\n
isCancellationAmount\r\n
isInventoryMovement\r\n
getSourcePaymentUid\r\n
getDestinationPaymentUid\r\n
getSourceFunctionUid\r\n
getDestinationFunctionUid\r\n
getSourceProjectUid\r\n
getDestinationProjectUid\r\n
getSourceFundingUid\r\n
getDestinationFundingUid\r\n
getSourcePaymentRequestUid\r\n
getDestinationPaymentRequestUid\r\n
getSimulationState\r\n
getSourceInventoriatedTotalAssetPrice\r\n
getDestinationInventoriatedTotalAssetPrice\r\n
getStartDate\r\n
getStopDate\r\n
isAccountable\r\n
getPortalType\r\n
getVariationText\r\n
getSubVariationText</string> </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>z_catalog_stock_list_without_delete_for_inventory_virtual_movement</string> </value>
</item>
<item>
<key> <string>src</string> </key>
<value> <string encoding="cdata"><![CDATA[
<dtml-let row_list="[]">\n
<dtml-in prefix="loop" expr="_.range(_.len(uid))">\n
<dtml-if "not(isInventoryMovement[loop_item]) and isMovement[loop_item] and getResourceUid[loop_item]">\n
<dtml-if "getDestinationUid[loop_item]">\n
<dtml-call expr="row_list.append([\n
uid[loop_item], \n
order_id[loop_item],\n
getExplanationUid[loop_item],\n
getDestinationUid[loop_item],\n
getDestinationSectionUid[loop_item],\n
getDestinationPaymentUid[loop_item],\n
getDestinationFunctionUid[loop_item],\n
getDestinationProjectUid[loop_item], \n
getDestinationFundingUid[loop_item], \n
getDestinationPaymentRequestUid[loop_item], \n
getSourceSectionUid[loop_item], \n
getSourceUid[loop_item], \n
getResourceUid[loop_item],\n
getInventoriatedQuantity[loop_item],\n
isCancellationAmount[loop_item],\n
isAccountable[loop_item],\n
getStopDate[loop_item], \n
getStartDate[loop_item], \n
getDestinationInventoriatedTotalAssetPrice[loop_item], \n
getPortalType[loop_item], \n
getSimulationState[loop_item], \n
getVariationText[loop_item],\n
getSubVariationText[loop_item]])">\n
</dtml-if>\n
<dtml-if "getSourceUid[loop_item]">\n
<dtml-call expr="row_list.append([\n
uid[loop_item], \n
mirror_order_id[loop_item],\n
getExplanationUid[loop_item],\n
getSourceUid[loop_item],\n
getSourceSectionUid[loop_item],\n
getSourcePaymentUid[loop_item],\n
getSourceFunctionUid[loop_item],\n
getSourceProjectUid[loop_item], \n
getSourceFundingUid[loop_item], \n
getSourcePaymentRequestUid[loop_item], \n
getDestinationSectionUid[loop_item], \n
getDestinationUid[loop_item], \n
getResourceUid[loop_item],\n
-(getInventoriatedQuantity[loop_item] or 0), \n
isCancellationAmount[loop_item],\n
isAccountable[loop_item],\n
getStartDate[loop_item], \n
getStopDate[loop_item],\n
getSourceInventoriatedTotalAssetPrice[loop_item], \n
getPortalType[loop_item], \n
getSimulationState[loop_item], \n
getVariationText[loop_item],\n
getSubVariationText[loop_item]])">\n
</dtml-if>\n
</dtml-if>\n
</dtml-in> \n
<dtml-if "row_list">\n
INSERT INTO\n
stock\n
VALUES\n
<dtml-in prefix="row" expr="row_list">\n
(\n
<dtml-sqlvar expr="row_item[0]" type="int">,\n
<dtml-sqlvar expr="row_item[1]" type="int">,\n
<dtml-sqlvar expr="row_item[2]" type="int" optional>,\n
<dtml-sqlvar expr="row_item[3]" type="int">,\n
<dtml-sqlvar expr="row_item[4]" type="int" optional>, \n
<dtml-sqlvar expr="row_item[5]" type="int" optional>, \n
<dtml-sqlvar expr="row_item[6]" type="int" optional>,\n
<dtml-sqlvar expr="row_item[7]" type="int" optional>,\n
<dtml-sqlvar expr="row_item[8]" type="int" optional>,\n
<dtml-sqlvar expr="row_item[9]" type="int" optional>,\n
<dtml-sqlvar expr="row_item[10]" type="int" optional>,\n
<dtml-sqlvar expr="row_item[11]" type="int" optional>,\n
<dtml-sqlvar expr="row_item[12]" type="int">, \n
<dtml-sqlvar expr="row_item[13]" type="float" optional>,\n
<dtml-sqlvar expr="row_item[14]" type="int">, \n
<dtml-sqlvar expr="row_item[15]" type="int">,\n
<dtml-sqlvar expr="row_item[16]" type="datetime" optional>,\n
<dtml-sqlvar expr="row_item[17]" type="datetime" optional>,\n
<dtml-sqlvar expr="row_item[18]" type="float" optional>,\n
<dtml-sqlvar expr="row_item[19]" type="string" optional>,\n
<dtml-sqlvar expr="row_item[20]" type="string" optional>,\n
<dtml-sqlvar expr="row_item[21]" type="string" optional>,\n
<dtml-sqlvar expr="row_item[22]" type="string" optional>\n
)\n
<dtml-if sequence-end><dtml-else>,</dtml-if>\n
</dtml-in>\n
</dtml-if>\n
</dtml-let>\n
]]></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -2078,56 +2078,6 @@ class TestInventory(TestOrderMixin, ERP5TypeTestCase):
inventory_list.append(inventory)
sequence.edit(inventory_list=inventory_list)
def stepCreateTwoResourceFullInventoryAtTheDate(self, sequence=None,
sequence_list=None, **kw):
""" Create Full Inventory at the date' """
inventory_list = sequence.get('inventory_list',[])
if kw.get('start_date', None) is not None:
start_date = kw['start_date']
else:
start_date = '2013/03/12 00:00:00 GMT+9'
if kw.get('inventory1', None) is not None:
inventory1 = kw['inventory1']
else:
inventory_1 = 10
if kw.get('inventory2', None) is not None:
inventory2 = kw['inventory2']
else:
inventory2 = 100
inventory = self.createInventory(sequence=sequence)
inventory_list = sequence.get('inventory_list',[])
inventory.edit(full_inventory=True,
start_date=start_date)
inventory_line = inventory.newContent(
portal_type = self.inventory_line_portal_type,
resource_value = sequence.get("resource"),
inventory = inventory1)
inventory_line = inventory.newContent(
portal_type = self.inventory_line_portal_type,
resource_value = sequence.get("second_resource"),
inventory = inventory2)
inventory.deliver()
inventory_list.append(inventory)
sequence.edit(inventory_list=inventory_list)
def stepCreateTwoResourceFullInventoryAtTheDate1(self, sequence=None,
sequence_list=None, **kw):
params = dict(start_date=self.two_resource_full_inventory1_start_date,
inventory1=self.two_resource_full_inventory1_inventory_1,
inventory2=self.two_resource_full_inventory1_inventory_2)
self.stepCreateTwoResourceFullInventoryAtTheDate(sequence, sequence_list,
**params)
def stepCreateTwoResourceFullInventoryAtTheDate2(self, sequence=None,
sequence_list=None, **kw):
params = dict(start_date=self.two_resource_full_inventory2_start_date,
inventory1=self.two_resource_full_inventory2_inventory_1,
inventory2=self.two_resource_full_inventory2_inventory_2)
self.stepCreateTwoResourceFullInventoryAtTheDate(sequence, sequence_list,
**params)
def stepTestFullInventoryWithResourceCategory(self,
sequence=None,
sequence_list=None,
......@@ -2580,20 +2530,6 @@ class TestInventory(TestOrderMixin, ERP5TypeTestCase):
node_uid=node_value.getUid(),
resource_uid=resource_value.getUid())
def stepCheckFullInventoryUpdateWithValidDateOrder(
self, sequence=None, sequence_list=None, **kw):
resource_value = sequence.get('resource')
second_resource_value = sequence.get('second_resource')
node_value = sequence.get('node')
section_value = sequence.get('section')
self._testGetInventory(expected=100,
section_uid=section_value.getUid(),
node_uid=node_value.getUid(),
resource_uid=resource_value.getUid())
self._testGetInventory(expected=0,
section_uid=section_value.getUid(),
node_uid=node_value.getUid(),
resource_uid=second_resource_value.getUid())
def test_01_getInventory(self, quiet=0, run=run_all_test):
"""
......@@ -3261,46 +3197,69 @@ class TestInventory(TestOrderMixin, ERP5TypeTestCase):
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
def test_15_FullInventoryUpdateWithValidDateOrder(
self, quiet=0, run=run_all_test):
"""
Confirm Full inventory update with a valid start_date order
def test_15_FullInventoryCanCreatesManyVirtualCompensationMovement(self, quiet=0, run=run_all_test):
organisation = self.portal.organisation_module.newContent(portal_type='Organisation')
resource_value_list = []
for i in range(2000):
resource_value_list.append(self.portal.product_module.newContent(portal_type='Product'))
The case is:
1) full inventory: 2013/02/01,section=A, node=B, resource=X, quantity=15
resource=Y, quantity=20
2) full inventory: 2013/02/02,section=A, node=B, resource=X, quantity=20
resource=Y, quantity=50
3) full inventory: 2013/02/10,section=A, node=B, resource=X, quantity=100
-> X:100
Y:0 # creates a dummy movement with quantity=-50
[test]
getInventory(resource=X, to_date=2013/02/15) should return 100
getInventory(resource=Y, to_date=2013/02/15) should return 0
"""
if not run: return
self.commit()
self.tic()
self.two_resource_full_inventory1_start_date = '2013/02/01 00:00:00 GMT+9'
self.two_resource_full_inventory1_inventory_1 = 15
self.two_resource_full_inventory1_inventory_2 = 20
self.two_resource_full_inventory2_start_date = '2013/02/02 00:00:00 GMT+9'
self.two_resource_full_inventory2_inventory_1 = 20
self.two_resource_full_inventory2_inventory_2 = 50
self.full_inventory_start_date_1 = '2013/02/10 00:00:00 GMT+9'
sequence_list = SequenceList()
sequence_string = 'CreateOrganisationsForModule \
CreateNotVariatedResource \
CreateNotVariatedSecondResource \
CreateTwoResourceFullInventoryAtTheDate1 \
Tic \
CreateTwoResourceFullInventoryAtTheDate2 \
Tic \
CreateFullInventoryAtTheDate1 \
Tic \
CheckFullInventoryUpdateWithValidDateOrder \
'
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
# Create initial inventory
date_1 = DateTime('2013/04/29 00:00:00 GMT+9')
result = self.portal.portal_simulation.getCurrentInventoryList(at_date=date_1,
section_uid=organisation.getUid(),
node_uid=organisation.getUid(),
group_by_resource=1)
self.assertEqual(len(result), 0)
full_inventory_1 = self.portal.inventory_module.newContent(portal_type='Inventory')
full_inventory_1.edit(destination_section_value=organisation,
destination_value=organisation,
start_date=date_1,
full_inventory=True)
for resource_value in resource_value_list:
full_inventory_1.newContent(portal_type='Inventory Line',
resource_value=resource_value,
quantity=123)
full_inventory_1.deliver()
self.commit()
self.tic()
result = self.portal.portal_simulation.getCurrentInventoryList(at_date=date_1,
section_uid=organisation.getUid(),
node_uid=organisation.getUid(),
group_by_resource=1)
self.assertEqual(sorted([(brain.resource_uid, brain.inventory)
for brain in result]),
sorted([(movement.getResourceUid(), movement.getQuantity())
for movement in full_inventory_1.getMovementList()]))
# Create second inventory which deletes inventories of many resources.
date_2 = DateTime('2013/05/03 00:00:00 GMT+9')
full_inventory_2 = self.portal.inventory_module.newContent(portal_type='Inventory')
full_inventory_2.edit(destination_section_value=organisation,
destination_value=organisation,
start_date=date_2,
full_inventory=True)
full_inventory_2.newContent(portal_type='Inventory Line',
resource_value=resource_value_list[0],
quantity=1)
full_inventory_2.deliver()
self.commit()
self.tic()
result = self.portal.portal_simulation.getCurrentInventoryList(at_date=date_2,
section_uid=organisation.getUid(),
node_uid=organisation.getUid(),
group_by_resource=1)
self.assertEqual(sorted([(brain.resource_uid, brain.inventory)
for brain in result if brain.inventory != 0]),
sorted([(movement.getResourceUid(), movement.getQuantity())
for movement in full_inventory_2.getMovementList()]))
def test_suite():
suite = unittest.TestSuite()
......
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