Commit a0f7e169 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 5b279571
......@@ -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>
2013-05-30 yusei
* Fix an inventory bug. When there are more than 300 inventories which are cancelled by inventory document, inventory document creates wrong stock records.
2013-05-08 arnaud.fontaine
* Prevent order_id column value to overflow following changes in Inventory (cf53db4).
......
260
\ No newline at end of file
261
\ No newline at end of file
......@@ -42,6 +42,7 @@ erp5_mysql_innodb/z_catalog_predicate_list
erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list
erp5_mysql_innodb/z_catalog_roles_and_users_list
erp5_mysql_innodb/z_catalog_stock_list
erp5_mysql_innodb/z_catalog_stock_list_without_delete_for_inventory_virtual_movement
erp5_mysql_innodb/z_catalog_subject_list
erp5_mysql_innodb/z_catalog_transformation_list
erp5_mysql_innodb/z_catalog_translation_list
......
......@@ -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