Commit 212bc99d authored by Rafael Monnerat's avatar Rafael Monnerat Committed by Łukasz Nowak

erp5_item: Item creation on delivery level

Found implementation with remarks:

 * test coverage is bootstrapped
 * destructive approach (abandoning Items) is considered as not
   implemented
 * documents and properties follow naming conventions
 * Delivery_createItemList is reused
 * support case when amount of items is less than quantity on line
 * support case when amount if items is more than quantity on line
parent 11e30046
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_fast_input</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_fast_input</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>item_creation</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>Modify portal content</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>10.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Create Items</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Delivery_viewCreateItemListDialog</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
"""
This script generates one Item per delivery line with
a title set to the product title, reference and variation,
Reference is setted via Item_setReference.
TODO:
- make title and variation handling generic
- consider generating description
- handle different Item types
"""
import random
def generateReference():
random_min = 100000000 # 9 digits
random_max = 1000000000 # 10 digits
new_id = context.portal_ids.generateNewLengthId(
id_group="item_reference", # XXX: isn't that id_group not too vauge?!
default=1)
return "%s-%s" % (new_id, random.randint(random_min,random_max))
# Make sure every movement has a reference and associated items
for movement in context.getMovementList():
# Make sure number of items is same as quantity
item_list = movement.getAggregateValueList(portal_type="Item")
quantity = movement.getQuantity()
remaining_quantity = quantity - len(item_list)
# Generate items
listbox = []
num = 0
while remaining_quantity > 0.:
# XXX: Shouldn't it be in Item_init script?
reference = generateReference()
title = "%s %s %s %s %s" % (movement.getResourceTitle(),
movement.getResourceReference(),
movement.getSizeTitle() or '',
movement.getVariationTitle() or '',
reference)
listbox.append({
'listbox_key': str(num),
'title': title,
'reference': reference,
'quantity': 1.0 # XXX: Hardcoded resource.base_quantity_unit
})
remaining_quantity -= 1
movement.DeliveryLine_createItemList(type='Item', listbox=listbox)
if not batch_mode:
message = context.Base_translateString('Items generated.')
return context.Base_redirect(form_id,
keep_items=dict(portal_status_message=message))
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>form_id=\'view\', batch_mode=0, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_createItemList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5 Form" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>Delivery_createItemList</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>bottom</string> </key>
<value>
<list>
<string>listbox</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list>
<string>listbox_item_len</string>
<string>listbox_item_remaining</string>
<string>listbox_variation_category_item_list</string>
</list>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_viewCreateItemListDialog</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Delivery_viewCreateItemListDialog</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_dialog</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Create Items</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>update_action_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="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>columns</string>
<string>editable_columns</string>
<string>list_method</string>
<string>report_root_list</string>
<string>selection_name</string>
<string>sort</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>resource_title</string>
<string>Product or Service</string>
</tuple>
<tuple>
<string>variation_category_item_list</string>
<string>Variation</string>
</tuple>
<tuple>
<string>quantity</string>
<string>Quantity</string>
</tuple>
<tuple>
<string>item_len</string>
<string>Item Amount</string>
</tuple>
<tuple>
<string>item_remaining</string>
<string>Difference</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>editable_columns</string> </key>
<value>
<list>
<tuple>
<string>reference</string>
<string>Reference</string>
</tuple>
<tuple>
<string>variation_category_item_list</string>
<string>Variation</string>
</tuple>
<tuple>
<string>item_len</string>
<string>Item Amount</string>
</tuple>
<tuple>
<string>item_remaing</string>
<string>Difference</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewTradeFieldLibrary</string> </value>
</item>
<item>
<key> <string>list_method</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>report_root_list</string> </key>
<value>
<list>
<tuple>
<string>parent_domain</string>
<string>Object Tree</string>
</tuple>
<tuple>
<string>resource</string>
<string>Resource</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>selection_name</string> </key>
<value> <string>purchase_packing_list_movement_selection</string> </value>
</item>
<item>
<key> <string>sort</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Item Report</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Method" module="Products.Formulator.MethodField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>method_name</string> </key>
<value> <string>getMovementList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_variation_category_item_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox_variation_category_item_list</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewTradeFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -12,6 +12,7 @@ Purchase Order Line | item_creation
Purchase Order | aggregate_item
Purchase Packing List Line | item_creation
Purchase Packing List | aggregate_item
Purchase Packing List | item_creation
Purchase Packing List | label_sheet_print
Returned Purchase Packing List Line | item_creation
Returned Purchase Packing List | aggregate_item
......
......@@ -969,6 +969,213 @@ class TestItem(TestItemMixin, ERP5TypeTestCase):
self.assertEqual([item], cell.getAggregateValueList())
def test_16_CreateItemsFromPackingListWithVariationDefined(self):
quantity = 2
organisation = self.createOrganisation()
self.tic()
resource = self.createVariatedResource()
resource_relative_url = resource.getRelativeUrl()
self.tic()
packing_list = self.createPackingList(organisation=organisation)
packing_list_line = self.createPackingListLine(
packing_list=packing_list,
resource=resource)
packing_list_line.setVariationCategoryList(
['size/%s/3' % (resource_relative_url,)])
# XXX: Setting cell quantity without any API
base_id = 'movement'
cell_key_list = list(packing_list_line.getCellKeyList(base_id=base_id))
self.assertEqual(1, len(cell_key_list))
cell_key = cell_key_list[0]
packing_list_cell = packing_list_line.newCell(
base_id=base_id, portal_type='Purchase Packing List Cell', *cell_key)
packing_list_cell.edit(mapped_value_property_list=['quantity'], quantity=quantity,
predicate_category_list=cell_key, variation_category_list=cell_key)
self.tic()
packing_list.Delivery_createItemList()
self.tic()
item_value_list = packing_list_cell.getAggregateValueList()
self.assertEqual(2, len(item_value_list))
item_1 = item_value_list[0]
item_2 = item_value_list[1]
item_1_title = item_1.getTitle()
item_2_title = item_2.getTitle()
self.assertTrue(item_1_title.startswith(resource.getTitle()))
self.assertTrue(item_2_title.startswith(resource.getTitle()))
self.assertTrue('SizeVariation2' in item_1_title)
self.assertTrue('SizeVariation2' in item_2_title)
self.assertNotEqual(item_1.getTitle(), item_2.getTitle())
self.assertNotEqual(item_1.getReference(), item_2.getReference())
self.assertEqual(packing_list_line.getTotalQuantity(), quantity)
def test_17_CreateItemsFromPackingListWithNotVariatedResource(self):
quantity = 2
organisation = self.createOrganisation()
self.tic()
resource = self.createNotVariatedResource()
self.tic()
packing_list = self.createPackingList(resource=resource,
organisation=organisation)
packing_list_line = self.createPackingListLine(packing_list=packing_list,
resource=resource)
packing_list_line.setQuantity(quantity)
self.tic()
# make sure we can render the dialog
packing_list.Delivery_viewCreateItemListDialog()
# generate items
packing_list.Delivery_createItemList()
self.tic()
item_value_list = packing_list_line.getAggregateValueList()
self.assertEqual(2, len(item_value_list))
item_1 = item_value_list[0]
item_2 = item_value_list[1]
self.assertTrue(item_1.getTitle().startswith(resource.getTitle()))
self.assertTrue(item_2.getTitle().startswith(resource.getTitle()))
self.assertEqual(packing_list_line.getVariationCategoryList(), [])
movement_cell_list = packing_list_line.contentValues(
portal_type='Purchase Packing List Cell')
self.assertEqual(movement_cell_list,[])
self.assertNotEqual(item_1.getTitle(), item_2.getTitle())
self.assertNotEqual(item_1.getReference(), item_2.getReference())
self.assertEqual(packing_list_line.getTotalQuantity(), quantity)
def test_18_CreateItemsFromPackingListWithExistingItem(self):
quantity = 2
title = self.id()
reference = self.id()
organisation = self.createOrganisation()
self.tic()
resource = self.createNotVariatedResource()
self.tic()
packing_list = self.createPackingList(resource=resource,
organisation=organisation)
packing_list_line = self.createPackingListLine(packing_list=packing_list,
resource=resource)
packing_list_line.setQuantity(quantity)
self.tic()
# Associate Item with delivery line
packing_list_line.DeliveryLine_createItemList(
type=self.item_portal_type,
listbox=[
{
'listbox_key': '001',
'reference': reference,
'title': title,
'quantity': 1.0
}
]
)
self.tic()
# Reset quantity to 2
packing_list_line.setQuantity(quantity)
# generate items
packing_list.Delivery_createItemList()
self.tic()
item_by_hand_value_list = [q for q in
packing_list_line.getAggregateValueList()
if q.getReference() == reference]
item_by_dialog_value_list = [q for q in
packing_list_line.getAggregateValueList()
if q.getReference() != reference]
self.assertEqual(1, len(item_by_hand_value_list))
self.assertEqual(1, len(item_by_dialog_value_list))
item_by_hand = item_by_hand_value_list[0]
item_by_dialog = item_by_dialog_value_list[0]
self.assertTrue(item_by_dialog.getTitle().startswith(resource.getTitle()))
self.assertEqual(packing_list_line.getVariationCategoryList(), [])
movement_cell_list = packing_list_line.contentValues(
portal_type='Purchase Packing List Cell')
self.assertEqual(movement_cell_list,[])
self.assertEqual(packing_list_line.getTotalQuantity(), quantity)
def test_19_CreateItemsFromPackingListWithMoreItemThanQuantity(self):
quantity = 1
title = self.id()
reference = self.id()
organisation = self.createOrganisation()
self.tic()
resource = self.createNotVariatedResource()
self.tic()
packing_list = self.createPackingList(resource=resource,
organisation=organisation)
packing_list_line = self.createPackingListLine(packing_list=packing_list,
resource=resource)
packing_list_line.setQuantity(quantity)
self.tic()
# Associate Items with delivery line
packing_list_line.DeliveryLine_createItemList(
type=self.item_portal_type,
listbox=[
{
'listbox_key': '001',
'reference': reference,
'title': title,
'quantity': 1.0
},
{
'listbox_key': '002',
'reference': reference+'B',
'title': title+'B',
'quantity': 1.0
}
]
)
self.tic()
# Reset quantity to 1
packing_list_line.setQuantity(quantity)
self.tic()
# generate items, expect no-op
packing_list.Delivery_createItemList()
self.tic()
item_value_list = [q for q in
packing_list_line.getAggregateValueList()
if q.getReference() == reference]
item_2_value_list = [q for q in
packing_list_line.getAggregateValueList()
if q.getReference() == reference+'B']
self.assertEqual(1, len(item_value_list))
self.assertEqual(1, len(item_2_value_list))
self.assertEqual(packing_list_line.getTotalQuantity(), quantity)
class TestItemScripts(ERP5TypeTestCase):
"""Test scripts from erp5_item.
"""
......
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