Commit 880e6be6 authored by Jérome Perrin's avatar Jérome Perrin

Merge remote-tracking branch 'nexedi/master' into fix/pickles

parents 53616d78 c45c2295
Pipeline #25402 failed with stage
in 0 seconds
erp5_full_text_mroonga_catalog
\ No newline at end of file
"""Check consistency of an accounting transaction.
This verifies the constraints defined in constraints and also "temporary" constraints,
such as "client is validated" or "accounting period is open" that are currently defined
in workflow script.
This is intentded to be used in custom scripts creating accounting transactions and
validating them.
"""
context.Base_checkConsistency()
accounting_workflow = context.getPortalObject().portal_workflow.accounting_workflow
accounting_workflow.script_validateTransactionLines(
{
'object': context,
'kwargs': {},
'transition': accounting_workflow.transition_deliver_action
})
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>WebSite_getJSONSchema</string> </value> <value> <string>AccountingTransaction_checkConsistency</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -4,18 +4,28 @@ If accounting_transaction_line_uid_list is not passed, this script assumes that ...@@ -4,18 +4,28 @@ If accounting_transaction_line_uid_list is not passed, this script assumes that
it's called on the context of an accounting transaction and it guess the grouping it's called on the context of an accounting transaction and it guess the grouping
of related accounting transactions using causality. of related accounting transactions using causality.
""" """
import collections
from Products.ERP5Type.Utils import int2letter from Products.ERP5Type.Utils import int2letter
# this dict associates (node, section, mirror_section, extra_grouping_parameter) to a list of # this dict associates (node, section, mirror_section, extra_grouping_parameter) to a list of
# accounting lines info (total_price, date and path) # accounting lines info (total_price, date and path)
lines_per_node = {} lines_per_node = {}
portal = context.getPortalObject() # this counter associates the lines to the count of entities that are
# impacted by this accounting line.
# Typically it is 1 if the line is only for source/destination like in
# "normal" invoices and it can be 2 for Internal Invoices.
# When we found a match that can be grouped, we decrement this counter for
# this line. If all lines of the group have a 0 count, we can set grouping
# reference. This is a way to set grouping reference when the group is only
# valid for one side, it has to be valid for both side.
non_grouped_section_count = collections.Counter()
allow_grouping_with_different_quantity = portal.portal_preferences.getPreference( portal = context.getPortalObject()
'preferred_grouping_with_different_quantities', 0)
if portal.portal_preferences.getPreference(
'preferred_grouping_with_different_quantities', False):
return
accounting_transaction_line_value_list = [] accounting_transaction_line_value_list = []
if accounting_transaction_line_uid_list is None: if accounting_transaction_line_uid_list is None:
...@@ -25,18 +35,21 @@ if accounting_transaction_line_uid_list is None: ...@@ -25,18 +35,21 @@ if accounting_transaction_line_uid_list is None:
accounting_transaction.getUid() != context.getUid(): accounting_transaction.getUid() != context.getUid():
continue continue
for line in accounting_transaction.getMovementList( for line in accounting_transaction.getMovementList(
portal.getPortalAccountingMovementTypeList()): portal.getPortalAccountingMovementTypeList()):
if line.getGroupingReference(): if line.getGroupingReference():
continue continue
accounting_transaction_line_value_list.append(line) accounting_transaction_line_value_list.append(line)
else: else:
if accounting_transaction_line_uid_list: if accounting_transaction_line_uid_list:
accounting_transaction_line_value_list = [ accounting_transaction_line_value_list = [
brain.getObject() for brain in portal.portal_catalog(uid=accounting_transaction_line_uid_list)] brain.getObject() for brain in portal.portal_catalog(
uid=accounting_transaction_line_uid_list)
]
for line in accounting_transaction_line_value_list: for line in accounting_transaction_line_value_list:
accounting_transaction = line.getParentValue() # source
if accounting_transaction.AccountingTransaction_isSourceView(): node_relative_url = line.getSource(portal_type='Account')
if node_relative_url:
section_relative_url = None section_relative_url = None
source_section = line.getSourceSectionValue(portal_type='Organisation') source_section = line.getSourceSectionValue(portal_type='Organisation')
if source_section is not None: if source_section is not None:
...@@ -44,51 +57,88 @@ for line in accounting_transaction_line_value_list: ...@@ -44,51 +57,88 @@ for line in accounting_transaction_line_value_list:
source_section.Organisation_getMappingRelatedOrganisation() source_section.Organisation_getMappingRelatedOrganisation()
section_relative_url = source_section.getRelativeUrl() section_relative_url = source_section.getRelativeUrl()
line_relative_url = line.getRelativeUrl()
non_grouped_section_count.update({line_relative_url: 1})
lines_per_node.setdefault( lines_per_node.setdefault(
(line.getSource(portal_type='Account'), (
section_relative_url, node_relative_url,
line.getDestinationSection(), section_relative_url,
line.AccountingTransactionLine_getGroupingExtraParameterList(source=True), line.getDestinationSection(),
), []).append( line.AccountingTransactionLine_getGroupingExtraParameterList(
dict(total_price=line.getSourceInventoriatedTotalAssetPrice() or 0, source=True),
date=line.getStartDate(), ), []).append(
path=line.getRelativeUrl())) dict(
else: total_price=line.getSourceInventoriatedTotalAssetPrice() or 0,
date=line.getStartDate(),
path=line_relative_url))
# destination
node_relative_url = line.getDestination(portal_type='Account')
if node_relative_url:
section_relative_url = None section_relative_url = None
destination_section = line.getDestinationSectionValue( destination_section = line.getDestinationSectionValue(
portal_type='Organisation') portal_type='Organisation')
if destination_section is not None: if destination_section is not None:
destination_section = \ destination_section = \
destination_section.Organisation_getMappingRelatedOrganisation() destination_section.Organisation_getMappingRelatedOrganisation()
section_relative_url = destination_section.getRelativeUrl() section_relative_url = destination_section.getRelativeUrl()
line_relative_url = line.getRelativeUrl()
non_grouped_section_count.update({line_relative_url: 1})
lines_per_node.setdefault( lines_per_node.setdefault(
(line.getDestination(portal_type='Account'), (
section_relative_url, node_relative_url,
line.getSourceSection(), section_relative_url,
line.AccountingTransactionLine_getGroupingExtraParameterList(source=False), line.getSourceSection(),
), []).append( line.AccountingTransactionLine_getGroupingExtraParameterList(
dict(total_price=line.getDestinationInventoriatedTotalAssetPrice() or 0, source=False),
date=line.getStopDate(), ), []).append(
path=line.getRelativeUrl())) dict(
total_price=line.getDestinationInventoriatedTotalAssetPrice() or 0,
date=line.getStopDate(),
path=line_relative_url))
changed_line_list = [] # We do two passes, a first pass to check if lines are groupable from both
for (node, section, mirror_section, _), line_info_list in lines_per_node.items(): # sides in case of internal invoices - then a second path to actually set
if node is None: # grouping references on groups that were groupable from both sides.
continue for (
total_price = sum([l['total_price'] for l in line_info_list]) node,
# get the currency rounding for this section section,
mirror_section,
_,
), line_info_list in list(lines_per_node.items()):
# get the currency rounding for this section, with a fallback that something that would
# allow grouping in case precision is not defined.
currency_precision = 5
if section: if section:
default_currency = portal.restrictedTraverse(section).getPriceCurrencyValue() default_currency = portal.restrictedTraverse(
section).getPriceCurrencyValue()
if default_currency is not None: if default_currency is not None:
total_price = round(total_price, default_currency.getQuantityPrecision()) currency_precision = default_currency.getQuantityPrecision()
if total_price == 0 or allow_grouping_with_different_quantity: total_price = round(
sum([l['total_price'] for l in line_info_list]), currency_precision)
if total_price == 0:
for line in line_info_list:
non_grouped_section_count.subtract({line['path']: 1})
else:
# this group is not valid, remove it for second path
del lines_per_node[node, section, mirror_section, _]
changed_line_set = set()
for (
node,
section,
mirror_section,
_,
), line_info_list in lines_per_node.items():
if sum(non_grouped_section_count[line['path']] for line in line_info_list) == 0:
# we should include mirror node in the id_group, but this would reset # we should include mirror node in the id_group, but this would reset
# id generators and generate grouping references that were already used. # id generators and generate grouping references that were already used.
id_group = ('grouping_reference', node, section, mirror_section) id_group = ('grouping_reference', node, section, mirror_section)
previous_default = context.portal_ids.getLastGeneratedId(id_group=id_group, default=0) previous_default = context.portal_ids.getLastGeneratedId(
grouping_reference = portal.portal_ids.generateNewId(id_generator='uid', id_group=id_group, default=0)
id_group=id_group, grouping_reference = portal.portal_ids.generateNewId(
default=previous_default + 1) id_generator='uid', id_group=id_group, default=previous_default + 1)
# convert from int to letters # convert from int to letters
string_reference = int2letter(grouping_reference) string_reference = int2letter(grouping_reference)
...@@ -97,11 +147,14 @@ for (node, section, mirror_section, _), line_info_list in lines_per_node.items() ...@@ -97,11 +147,14 @@ for (node, section, mirror_section, _), line_info_list in lines_per_node.items()
date = max([line['date'] for line in line_info_list]) date = max([line['date'] for line in line_info_list])
for line in line_info_list: for line in line_info_list:
if line['path'] in changed_line_set:
continue
line_obj = portal.restrictedTraverse(line['path']) line_obj = portal.restrictedTraverse(line['path'])
assert not line_obj.getGroupingReference(), line assert not line_obj.getGroupingReference(), line
line_obj.setGroupingReference(string_reference) line_obj.setGroupingReference(string_reference)
line_obj.setGroupingDate(date) line_obj.setGroupingDate(date)
line_obj.reindexObject(activate_kw=dict(tag='accounting_grouping_reference')) line_obj.reindexObject(
changed_line_list.append(line['path']) activate_kw=dict(tag='accounting_grouping_reference'))
changed_line_set.add(line['path'])
return changed_line_list return changed_line_set
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
because only validated accounts are displayed in the cache. because only validated accounts are displayed in the cache.
""" """
if sci['object'].getValidationState() == 'validated': if sci['object'].getValidationState() == 'validated':
container.Account_flushAccountListCache(sci) container.script_Account_flushAccountListCache(sci)
...@@ -28,7 +28,7 @@ transaction.Base_checkConsistency() ...@@ -28,7 +28,7 @@ transaction.Base_checkConsistency()
skip_period_validation = state_change['kwargs'].get( skip_period_validation = state_change['kwargs'].get(
'skip_period_validation', 0) 'skip_period_validation', 0)
transition = state_change['transition'] transition = state_change['transition']
if transition.id in ('plan_action', 'confirm_action') : if transition.getReference() in ('plan_action', 'confirm_action') :
skip_period_validation = 1 skip_period_validation = 1
source_section = transaction.getSourceSectionValue( source_section = transaction.getSourceSectionValue(
......
...@@ -13,7 +13,7 @@ section_portal_type_list = ['Person', 'Organisation'] ...@@ -13,7 +13,7 @@ section_portal_type_list = ['Person', 'Organisation']
invalid_state_list = ['invalidated', 'deleted'] invalid_state_list = ['invalidated', 'deleted']
# first of all, validate the transaction itself # first of all, validate the transaction itself
container.validateTransaction(state_change) container.script_validateTransaction(state_change)
# Check that all lines uses open accounts, and doesn't use invalid third # Check that all lines uses open accounts, and doesn't use invalid third
......
...@@ -42,15 +42,18 @@ ...@@ -42,15 +42,18 @@
<item> <item>
<key> <string>guard_permission</string> </key> <key> <string>guard_permission</string> </key>
<value> <value>
<tuple> <tuple/>
<string>Modify portal content</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>guard_role</string> </key> <key> <string>guard_role</string> </key>
<value> <value>
<tuple/> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Owner</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
<value> <value>
<tuple> <tuple>
<string>Assignor</string> <string>Assignor</string>
<string>Associate</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
...@@ -40,15 +40,18 @@ ...@@ -40,15 +40,18 @@
<item> <item>
<key> <string>guard_permission</string> </key> <key> <string>guard_permission</string> </key>
<value> <value>
<tuple> <tuple/>
<string>Modify portal content</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>guard_role</string> </key> <key> <string>guard_role</string> </key>
<value> <value>
<tuple/> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Owner</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
<tuple> <tuple>
<string>Assignee</string> <string>Assignee</string>
<string>Assignor</string> <string>Assignor</string>
<string>Associate</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
...@@ -41,15 +41,17 @@ ...@@ -41,15 +41,17 @@
<item> <item>
<key> <string>guard_permission</string> </key> <key> <string>guard_permission</string> </key>
<value> <value>
<tuple> <tuple/>
<string>Modify portal content</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>guard_role</string> </key> <key> <string>guard_role</string> </key>
<value> <value>
<tuple/> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
<tuple> <tuple>
<string>Assignor</string> <string>Assignor</string>
<string>Assignee</string> <string>Assignee</string>
<string>Associate</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
return sci.getPortal().portal_workflow.accounting_workflow.scripts[script.getId()](sci) return sci.getPortal().portal_workflow.accounting_workflow[script.getId()](sci)
state_change['object'].AccountingTransaction_setDefaultMirrorAccountList() state_change['object'].AccountingTransaction_setDefaultMirrorAccountList()
return container.setReferences(state_change) return container.script_setReferences(state_change)
return sci.getPortal().portal_workflow.accounting_workflow.scripts[script.getId()](sci) return sci.getPortal().portal_workflow.accounting_workflow[script.getId()](sci)
return state_change.getPortal().portal_workflow.accounting_workflow.scripts[script.getId()](state_change) return state_change.getPortal().portal_workflow.accounting_workflow[script.getId()](state_change)
return state_change.getPortal().portal_workflow.accounting_workflow.scripts[script.getId()](state_change) return state_change.getPortal().portal_workflow.accounting_workflow[script.getId()](state_change)
...@@ -7,4 +7,4 @@ if old_state.getId() == 'draft': ...@@ -7,4 +7,4 @@ if old_state.getId() == 'draft':
if internal_invoice.InternalInvoiceTransaction_getAuthenticatedUserSection() == internal_invoice.getDestinationSection(): if internal_invoice.InternalInvoiceTransaction_getAuthenticatedUserSection() == internal_invoice.getDestinationSection():
raise ValidationFailed(translateString("Your entity should not be destination.")) raise ValidationFailed(translateString("Your entity should not be destination."))
return state_change.getPortal().portal_workflow.accounting_workflow.scripts[script.getId()](state_change) return state_change.getPortal().portal_workflow.accounting_workflow[script.getId()](state_change)
...@@ -48,9 +48,10 @@ ...@@ -48,9 +48,10 @@
<key> <string>guard_role</string> </key> <key> <string>guard_role</string> </key>
<value> <value>
<tuple> <tuple>
<string>Assignor</string>
<string>Assignee</string> <string>Assignee</string>
<string>Assignor</string>
<string>Associate</string> <string>Associate</string>
<string>Owner</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
...@@ -41,15 +41,18 @@ ...@@ -41,15 +41,18 @@
<item> <item>
<key> <string>guard_permission</string> </key> <key> <string>guard_permission</string> </key>
<value> <value>
<tuple> <tuple/>
<string>Modify portal content</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>guard_role</string> </key> <key> <string>guard_role</string> </key>
<value> <value>
<tuple/> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Owner</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
<value> <value>
<tuple> <tuple>
<string>Assignor</string> <string>Assignor</string>
<string>Associate</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
...@@ -40,15 +40,18 @@ ...@@ -40,15 +40,18 @@
<item> <item>
<key> <string>guard_permission</string> </key> <key> <string>guard_permission</string> </key>
<value> <value>
<tuple> <tuple/>
<string>Modify portal content</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>guard_role</string> </key> <key> <string>guard_role</string> </key>
<value> <value>
<tuple/> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Owner</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
......
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
<tuple> <tuple>
<string>Assignee</string> <string>Assignee</string>
<string>Assignor</string> <string>Assignor</string>
<string>Associate</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
...@@ -59,15 +59,17 @@ ...@@ -59,15 +59,17 @@
<item> <item>
<key> <string>guard_permission</string> </key> <key> <string>guard_permission</string> </key>
<value> <value>
<tuple> <tuple/>
<string>Modify portal content</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>guard_role</string> </key> <key> <string>guard_role</string> </key>
<value> <value>
<tuple/> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
<tuple> <tuple>
<string>Assignee</string> <string>Assignee</string>
<string>Assignor</string> <string>Assignor</string>
<string>Associate</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_base erp5_base
erp5_pdm erp5_pdm
......
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_base erp5_base
erp5_pdm erp5_pdm
......
erp5_full_text_mroonga_catalog
erp5_dummy_movement erp5_dummy_movement
\ No newline at end of file
erp5_full_text_mroonga_catalog
erp5_base erp5_base
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_pdm erp5_pdm
......
...@@ -46,7 +46,7 @@ class TestERP5Administration(InventoryAPITestCase): ...@@ -46,7 +46,7 @@ class TestERP5Administration(InventoryAPITestCase):
""" """
Same list as for Inventory API and add erp5_administration Same list as for Inventory API and add erp5_administration
""" """
return InventoryAPITestCase.getBusinessTemplateList(self) + ('erp5_administration', ) return InventoryAPITestCase.getBusinessTemplateList(self) + ('erp5_full_text_mroonga_catalog', 'erp5_administration')
def test_01_RunCheckStockTableAlarm(self): def test_01_RunCheckStockTableAlarm(self):
""" """
......
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_base erp5_base
erp5_pdm erp5_pdm
......
erp5_full_text_mroonga_catalog
\ No newline at end of file
...@@ -55,10 +55,6 @@ ...@@ -55,10 +55,6 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Delivery</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -82,10 +82,6 @@ ...@@ -82,10 +82,6 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>Delivery</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_base erp5_base
erp5_simulation erp5_simulation
......
erp5_full_text_mroonga_catalog
\ No newline at end of file
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
############################################################################## ##############################################################################
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.CMFCore.WorkflowCore import WorkflowAction from Products.ERP5Type.Base import WorkflowMethod
from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
...@@ -64,7 +64,7 @@ class ApparelMeasurement(XMLObject, XMLMatrix, Image): ...@@ -64,7 +64,7 @@ class ApparelMeasurement(XMLObject, XMLMatrix, Image):
# Inheritance # Inheritance
_edit = Image._edit _edit = Image._edit
security.declareProtected(Permissions.ModifyPortalContent, 'edit' ) security.declareProtected(Permissions.ModifyPortalContent, 'edit' )
edit = WorkflowAction( _edit ) edit = WorkflowMethod( _edit )
security.declareProtected(Permissions.View, 'index_html') security.declareProtected(Permissions.View, 'index_html')
index_html = Image.index_html index_html = Image.index_html
......
erp5_full_text_myisam_catalog
erp5_mrp erp5_mrp
\ No newline at end of file
...@@ -51,6 +51,7 @@ class TestArchive(InventoryAPITestCase): ...@@ -51,6 +51,7 @@ class TestArchive(InventoryAPITestCase):
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return InventoryAPITestCase.getBusinessTemplateList(self) + ( return InventoryAPITestCase.getBusinessTemplateList(self) + (
'erp5_archive', 'erp5_archive',
'erp5_full_text_mroonga_catalog',
) )
# Different variables used for this test # Different variables used for this test
......
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_base erp5_base
erp5_pdm erp5_pdm
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
""" """
from DateTime import DateTime from DateTime import DateTime
from Products.ZSQLCatalog.SQLCatalog import Query from Products.ZSQLCatalog.SQLCatalog import Query
from erp5.component.module.Log import log
request = context.REQUEST request = context.REQUEST
portal = context.getPortalObject() portal = context.getPortalObject()
...@@ -17,6 +18,13 @@ one_second = 1/24.0/60.0/60.0 ...@@ -17,6 +18,13 @@ one_second = 1/24.0/60.0/60.0
check_duration = portal_preferences.getPreferredAuthenticationFailureCheckDuration() check_duration = portal_preferences.getPreferredAuthenticationFailureCheckDuration()
block_duration = portal_preferences.getPreferredAuthenticationFailureBlockDuration() block_duration = portal_preferences.getPreferredAuthenticationFailureBlockDuration()
max_authentication_failures = portal_preferences.getPreferredMaxAuthenticationFailure() max_authentication_failures = portal_preferences.getPreferredMaxAuthenticationFailure()
if None in (check_duration,
block_duration,
max_authentication_failures):
log('Login block is not working because authentication policy in system preference is not set properly.')
return 0
check_time = now - check_duration*one_second check_time = now - check_duration*one_second
# some failures might be still unindexed # some failures might be still unindexed
......
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_base erp5_base
erp5_web erp5_web
......
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_base erp5_base
erp5_pdm erp5_pdm
......
erp5_full_text_mroonga_catalog
\ No newline at end of file
<?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_jio_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_jio_action</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>change_function</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>Modify portal content</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>2.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Change Function</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}/Base_viewChangeIdDialog</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -50,14 +50,7 @@ else: ...@@ -50,14 +50,7 @@ else:
from Products.ERP5Security.ERP5LoginUserManager import ERP5LoginUserManager from Products.ERP5Security.ERP5LoginUserManager import ERP5LoginUserManager
class UserExistsError( class UserExistsError(ValidationFailed):
ValidationFailed,
# to workaround pylint's false positive:
# Exception doesn't inherit from standard "Exception" class (nonstandard-exception)
# because it cannot import ValidationFailed (which is set by a monkey patch), we also
# inherit from Exception.
Exception,
):
def __init__(self, user_id): def __init__(self, user_id):
super(UserExistsError, self).__init__('user id %s already exists' % (user_id, )) super(UserExistsError, self).__init__('user id %s already exists' % (user_id, ))
......
...@@ -24,4 +24,4 @@ for simulation_movement in simulation_movement_list: ...@@ -24,4 +24,4 @@ for simulation_movement in simulation_movement_list:
if simulation_movement.getOrder() == delivery_movement.getRelativeUrl(): if simulation_movement.getOrder() == delivery_movement.getRelativeUrl():
simulation_movement.setOrder(None) simulation_movement.setOrder(None)
context.DeliveryMovement_updateSimulation(state_change) container.script_DeliveryMovement_updateSimulation(state_change)
...@@ -44,6 +44,7 @@ Embedded File | fullsize_view ...@@ -44,6 +44,7 @@ Embedded File | fullsize_view
Embedded File | view Embedded File | view
Embedded File | web_view Embedded File | web_view
Embedded Folder | view Embedded Folder | view
External Identifier | change_function
External Identifier | view External Identifier | view
Fax | change_function Fax | change_function
Fax | view Fax | view
......
erp5_full_text_mroonga_catalog
\ No newline at end of file
erp5_full_text_mroonga_catalog
\ No newline at end of file
erp5_full_text_myisam_catalog
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_pdm erp5_pdm
erp5_simulation erp5_simulation
......
erp5_full_text_myisam_catalog
\ No newline at end of file
...@@ -31,7 +31,7 @@ import os ...@@ -31,7 +31,7 @@ import os
import random import random
import unittest import unittest
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.DCWorkflow.DCWorkflow import ValidationFailed from Products.ERP5Type.Core.Workflow import ValidationFailed
from AccessControl import Unauthorized from AccessControl import Unauthorized
class TestCertificateAuthority(ERP5TypeTestCase): class TestCertificateAuthority(ERP5TypeTestCase):
......
erp5_full_text_mroonga_catalog
\ No newline at end of file
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_base erp5_base
erp5_simulation erp5_simulation
......
...@@ -145,28 +145,22 @@ ...@@ -145,28 +145,22 @@
<key> <string>data</string> </key> <key> <string>data</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>content_translation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAY=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>edit_workflow</string> </key> <key> <string>edit_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAc=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAY=</string> </persistent>
</value> </value>
</item> </item>
<item> <item>
<key> <string>user_account_workflow</string> </key> <key> <string>user_account_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAg=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAc=</string> </persistent>
</value> </value>
</item> </item>
<item> <item>
<key> <string>validation_workflow</string> </key> <key> <string>validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAk=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAg=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -176,63 +170,6 @@ ...@@ -176,63 +170,6 @@
</pickle> </pickle>
</record> </record>
<record id="6" aka="AAAAAAAAAAY="> <record id="6" aka="AAAAAAAAAAY=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate_content_translation</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>System Processes</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>content_translation_state</string> </key>
<value> <string>latest</string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1664349798.66</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="7" aka="AAAAAAAAAAc=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
...@@ -295,7 +232,7 @@ ...@@ -295,7 +232,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="8" aka="AAAAAAAAAAg="> <record id="7" aka="AAAAAAAAAAc=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
...@@ -354,7 +291,7 @@ ...@@ -354,7 +291,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="9" aka="AAAAAAAAAAk="> <record id="8" aka="AAAAAAAAAAg=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
erp5_full_text_mroonga_catalog
\ No newline at end of file
erp5_full_text_myisam_catalog
erp5_base erp5_base
\ No newline at end of file
...@@ -86,7 +86,7 @@ class TestLiveConfiguratorWorkflowMixin(SecurityTestCase): ...@@ -86,7 +86,7 @@ class TestLiveConfiguratorWorkflowMixin(SecurityTestCase):
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return ('erp5_core_proxy_field_legacy', return ('erp5_core_proxy_field_legacy',
'erp5_full_text_catalog', 'erp5_full_text_mroonga_catalog',
'erp5_base', 'erp5_base',
'erp5_configurator', 'erp5_configurator',
'erp5_configurator_standard',) 'erp5_configurator_standard',)
......
...@@ -41,6 +41,7 @@ class TestConfiguratorItem(TestLiveConfiguratorWorkflowMixin): ...@@ -41,6 +41,7 @@ class TestConfiguratorItem(TestLiveConfiguratorWorkflowMixin):
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return ('erp5_core_proxy_field_legacy', return ('erp5_core_proxy_field_legacy',
'erp5_full_text_mroonga_catalog',
'erp5_base', 'erp5_base',
'erp5_configurator', 'erp5_configurator',
'erp5_simulation', 'erp5_simulation',
......
...@@ -38,6 +38,7 @@ class TestConfiguratorTool(TestLiveConfiguratorWorkflowMixin): ...@@ -38,6 +38,7 @@ class TestConfiguratorTool(TestLiveConfiguratorWorkflowMixin):
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return ('erp5_core_proxy_field_legacy', return ('erp5_core_proxy_field_legacy',
'erp5_full_text_mroonga_catalog',
'erp5_base', 'erp5_base',
'erp5_configurator', 'erp5_configurator',
'erp5_configurator_standard',) 'erp5_configurator_standard',)
......
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_full_text_mroonga_catalog
erp5_base erp5_base
erp5_configurator_standard erp5_configurator_standard
erp5_simulation erp5_simulation
......
erp5_full_text_mroonga_catalog
\ No newline at end of file
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_full_text_mroonga_catalog
erp5_base erp5_base
\ No newline at end of file
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
erp5_full_text_mroonga_catalog
erp5_base erp5_base
\ No newline at end of file
...@@ -197,6 +197,7 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase): ...@@ -197,6 +197,7 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase):
'erp5_dms_ui_test', 'erp5_dms_ui_test',
'erp5_font', 'erp5_font',
'erp5_forge', 'erp5_forge',
'erp5_full_text_mroonga_catalog',
'erp5_gadget_interface_validator', 'erp5_gadget_interface_validator',
'erp5_hal_json_style', 'erp5_hal_json_style',
'erp5_hr', 'erp5_hr',
......
erp5_full_text_mroonga_catalog
erp5_administration erp5_administration
\ No newline at end of file
erp5_configurator_standard erp5_configurator_standard
\ No newline at end of file erp5_full_text_mroonga_catalog
\ No newline at end of file
...@@ -75,10 +75,6 @@ ...@@ -75,10 +75,6 @@
<key> <string>solver_action_title</string> </key> <key> <string>solver_action_title</string> </key>
<value> <string>First In, First Out</string> </value> <value> <string>First In, First Out</string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>FIFODeliverySolver</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -75,10 +75,6 @@ ...@@ -75,10 +75,6 @@
<key> <string>solver_action_title</string> </key> <key> <string>solver_action_title</string> </key>
<value> <string>Last In, First Out</string> </value> <value> <string>Last In, First Out</string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>LIFODeliverySolver</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -75,10 +75,6 @@ ...@@ -75,10 +75,6 @@
<key> <string>solver_action_title</string> </key> <key> <string>solver_action_title</string> </key>
<value> <string>Minimise Price</string> </value> <value> <string>Minimise Price</string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>MinimisePriceDeliverySolver</string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -146,10 +146,6 @@ ...@@ -146,10 +146,6 @@
<key> <string>solver_action_title</string> </key> <key> <string>solver_action_title</string> </key>
<value> <string>Cancel Quantity</string> </value> <value> <string>Cancel Quantity</string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>QuantityCancelSolver</string> </value>
</item>
<item> <item>
<key> <string>workflow_list</string> </key> <key> <string>workflow_list</string> </key>
<value> <value>
......
...@@ -189,10 +189,6 @@ ...@@ -189,10 +189,6 @@
</tuple> </tuple>
</value> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>TradeModelSolver</string> </value>
</item>
<item> <item>
<key> <string>workflow_list</string> </key> <key> <string>workflow_list</string> </key>
<value> <value>
......
...@@ -185,10 +185,6 @@ ...@@ -185,10 +185,6 @@
<key> <string>solver_action_title</string> </key> <key> <string>solver_action_title</string> </key>
<value> <string>Unify value</string> </value> <value> <string>Unify value</string> </value>
</item> </item>
<item>
<key> <string>type_class</string> </key>
<value> <string>UnifySolver</string> </value>
</item>
<item> <item>
<key> <string>workflow_list</string> </key> <key> <string>workflow_list</string> </key>
<value> <value>
......
erp5_full_text_mroonga_catalog
\ No newline at end of file
...@@ -39,7 +39,7 @@ class TestContentTranslation(ERP5TypeTestCase): ...@@ -39,7 +39,7 @@ class TestContentTranslation(ERP5TypeTestCase):
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return ( return ('erp5_full_text_mroonga_catalog',
'erp5_base', 'erp5_base',
'erp5_content_translation', 'erp5_content_translation',
) )
......
erp5_full_text_mroonga_catalog
erp5_l10n_fr erp5_l10n_fr
erp5_l10n_ja erp5_l10n_ja
\ No newline at end of file
...@@ -966,19 +966,23 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -966,19 +966,23 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
# Add a non-existent workflow. # Add a non-existent workflow.
pw = self.getWorkflowTool() pw = self.getWorkflowTool()
dummy_simulation_worlflow_id = 'fake_simulation_workflow' dummy_simulation_workflow_id = 'fake_simulation_workflow'
dummy_validation_worlflow_id = 'fake_validation_workflow' dummy_validation_workflow_id = 'fake_validation_workflow'
#Assume that erp5_styles workflow Manage permissions with acquired Role by default #Assume that erp5_styles workflow Manage permissions with acquired Role by default
addWorkflowByType(pw, 'erp5_workflow', dummy_simulation_worlflow_id) dummy_simulation_workflow = pw.newContent(
addWorkflowByType(pw, 'erp5_workflow', dummy_validation_worlflow_id) portal_type='Workflow',
dummy_simulation_worlflow = pw[dummy_simulation_worlflow_id] reference=dummy_simulation_workflow_id,
dummy_validation_worlflow = pw[dummy_validation_worlflow_id] )
dummy_validation_worlflow.variables.setStateVar('validation_state') dummy_validation_workflow = pw.newContent(
portal_type='Workflow',
reference=dummy_validation_workflow_id,
state_variable='validation_state',
)
organisation_type = portal.portal_types.getTypeInfo(portal_type) organisation_type = portal.portal_types.getTypeInfo(portal_type)
organisation_initial_workflow_list = organisation_type.getTypeWorkflowList() organisation_initial_workflow_list = organisation_type.getTypeWorkflowList()
organisation_type.setTypeWorkflowList([dummy_validation_worlflow_id, organisation_type.setTypeWorkflowList([dummy_validation_workflow_id,
dummy_simulation_worlflow_id]) dummy_simulation_workflow_id])
permission_list = list(dummy_simulation_worlflow.permissions) permission_list = dummy_simulation_workflow.getWorkflowManagedPermissionList()
manager_has_permission = {} manager_has_permission = {}
for permission in permission_list: for permission in permission_list:
manager_has_permission[permission] = ('Manager',) manager_has_permission[permission] = ('Manager',)
...@@ -989,7 +993,7 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -989,7 +993,7 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
user = getSecurityManager().getUser() user = getSecurityManager().getUser()
try: try:
self.assertTrue(permission_list) self.assertTrue(permission_list)
self.assertFalse(dummy_simulation_worlflow.states.draft.permission_roles) self.assertFalse(dummy_simulation_workflow['state_draft'].getStatePermissionRoleListDict())
#1 #1
obj = module.newContent(portal_type=portal_type) obj = module.newContent(portal_type=portal_type)
#No role is defined by default on workflow #No role is defined by default on workflow
...@@ -999,28 +1003,28 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -999,28 +1003,28 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
for permission in permission_list: for permission in permission_list:
self.assertTrue(user.has_permission(permission, obj)) self.assertTrue(user.has_permission(permission, obj))
#2 Now configure both workflow with same configuration #2 Now configure both workflow with same configuration
dummy_simulation_worlflow.states.draft.permission_roles = manager_has_permission.copy() dummy_simulation_workflow['state_draft'].setStatePermissionRoleListDict(manager_has_permission.copy())
dummy_validation_worlflow.states.draft.permission_roles = manager_has_permission.copy() dummy_validation_workflow['state_draft'].setStatePermissionRoleListDict(manager_has_permission.copy())
dummy_simulation_worlflow.updateRoleMappingsFor(obj) dummy_simulation_workflow.updateRoleMappingsFor(obj)
dummy_validation_worlflow.updateRoleMappingsFor(obj) dummy_validation_workflow.updateRoleMappingsFor(obj)
for permission in permission_list: for permission in permission_list:
self.assertTrue(user.has_permission(permission, obj)) self.assertTrue(user.has_permission(permission, obj))
#3 change only dummy_simulation_worlflow #3 change only dummy_simulation_workflow
dummy_simulation_worlflow.states.draft.permission_roles = manager_has_no_permission.copy() dummy_simulation_workflow['state_draft'].setStatePermissionRoleListDict(manager_has_no_permission.copy())
dummy_simulation_worlflow.updateRoleMappingsFor(obj) dummy_simulation_workflow.updateRoleMappingsFor(obj)
for permission in permission_list: for permission in permission_list:
self.assertFalse(user.has_permission(permission, obj)) self.assertFalse(user.has_permission(permission, obj))
#4 enable acquisition for dummy_simulation_worlflow #4 enable acquisition for dummy_simulation_workflow
dummy_simulation_worlflow.states.draft.permission_roles = None dummy_simulation_workflow['state_draft'].setAcquirePermissionList(permission_list)
dummy_simulation_worlflow.updateRoleMappingsFor(obj) dummy_simulation_workflow.updateRoleMappingsFor(obj)
for permission in permission_list: for permission in permission_list:
self.assertTrue(user.has_permission(permission, obj)) self.assertTrue(user.has_permission(permission, obj))
finally: finally:
# Make sure that the artificial workflow is not referred to any longer. # Make sure that the artificial workflow is not referred to any longer.
organisation_type.setTypeWorkflowList(organisation_initial_workflow_list) organisation_type.setTypeWorkflowList(organisation_initial_workflow_list)
pw.manage_delObjects([dummy_simulation_worlflow_id, dummy_validation_worlflow_id]) pw.manage_delObjects([dummy_simulation_workflow_id, dummy_validation_workflow_id])
def test_getViewPermissionOwnerDefault(self): def test_getViewPermissionOwnerDefault(self):
"""Test getViewPermissionOwner method behaviour""" """Test getViewPermissionOwner method behaviour"""
......
...@@ -39,7 +39,6 @@ from urllib import pathname2url ...@@ -39,7 +39,6 @@ from urllib import pathname2url
from Products.ERP5Type.Globals import PersistentMapping from Products.ERP5Type.Globals import PersistentMapping
from Products.ERP5Type.dynamic.lazy_class import ERP5BaseBroken from Products.ERP5Type.dynamic.lazy_class import ERP5BaseBroken
from Products.ERP5Type.tests.utils import LogInterceptor from Products.ERP5Type.tests.utils import LogInterceptor
from Products.ERP5Type.Workflow import addWorkflowByType
import shutil import shutil
import os import os
import random import random
...@@ -1315,8 +1314,11 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): ...@@ -1315,8 +1314,11 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
""" """
wf_id = 'geek_workflow' wf_id = 'geek_workflow'
pw = self.getWorkflowTool() pw = self.getWorkflowTool()
addWorkflowByType(pw, WORKFLOW_TYPE, wf_id) workflow = pw.newContent(
workflow = pw._getOb(wf_id, None) portal_type='Workflow',
reference=wf_id,
)
self.tic()
self.assertTrue(workflow is not None) self.assertTrue(workflow is not None)
sequence.edit(workflow_id=workflow.getId()) sequence.edit(workflow_id=workflow.getId())
...@@ -2886,8 +2888,11 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): ...@@ -2886,8 +2888,11 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
""" """
wf_id = 'custom_geek_workflow' wf_id = 'custom_geek_workflow'
pw = self.getWorkflowTool() pw = self.getWorkflowTool()
addWorkflowByType(pw, WORKFLOW_TYPE, wf_id) workflow = pw.newContent(
workflow = pw._getOb(wf_id, None) portal_type='Workflow',
reference=wf_id,
)
self.tic()
self.assertTrue(workflow is not None) self.assertTrue(workflow is not None)
sequence.edit(workflow_id=workflow.getId()) sequence.edit(workflow_id=workflow.getId())
...@@ -3295,6 +3300,16 @@ class TestBusinessTemplate(BusinessTemplateMixin): ...@@ -3295,6 +3300,16 @@ class TestBusinessTemplate(BusinessTemplateMixin):
"""Tests the Title of the Template Tool.""" """Tests the Title of the Template Tool."""
self.assertEqual('Business Templates', self.getTemplateTool().Title()) self.assertEqual('Business Templates', self.getTemplateTool().Title())
def test_business_template_properties_sorted(self):
bt = self.portal.portal_templates.newContent(
portal_type='Business Template')
bt.edit(template_path_list=['b', 'c', 'a'])
self.assertEqual(bt.getTemplatePathList(), ['a', 'b', 'c'])
bt.edit(template_keep_workflow_path_list=['b', 'c', 'a'])
self.assertEqual(bt.getTemplateKeepWorkflowPathList(), ['a', 'b', 'c'])
bt.edit(template_keep_last_workflow_history_only_path_list=['b', 'c', 'a'])
self.assertEqual(bt.getTemplateKeepLastWorkflowHistoryOnlyPathList(), ['a', 'b', 'c'])
def test_01_checkNewSite(self): def test_01_checkNewSite(self):
"""Test Check New Site""" """Test Check New Site"""
sequence_list = SequenceList() sequence_list = SequenceList()
...@@ -6812,7 +6827,7 @@ class TestBusinessTemplate(BusinessTemplateMixin): ...@@ -6812,7 +6827,7 @@ class TestBusinessTemplate(BusinessTemplateMixin):
portal_type='Business Template', portal_type='Business Template',
title=self.id(), title=self.id(),
template_path_list=( template_path_list=(
'portal_categories/test_category/**' 'portal_categories/test_category/**',
), ),
template_base_category_list=['test_category'], template_base_category_list=['test_category'],
) )
...@@ -6883,7 +6898,7 @@ class TestBusinessTemplate(BusinessTemplateMixin): ...@@ -6883,7 +6898,7 @@ class TestBusinessTemplate(BusinessTemplateMixin):
portal_type='Business Template', portal_type='Business Template',
title=self.id(), title=self.id(),
template_path_list=( template_path_list=(
'portal_categories/test_category/**' 'portal_categories/test_category/**',
), ),
template_base_category_list=['test_category'], template_base_category_list=['test_category'],
) )
......
...@@ -202,7 +202,7 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor): ...@@ -202,7 +202,7 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor):
return "ERP5Catalog" return "ERP5Catalog"
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return ('erp5_base',) return ('erp5_full_text_mroonga_catalog', 'erp5_base',)
# Different variables used for this test # Different variables used for this test
username = 'seb' username = 'seb'
...@@ -4123,6 +4123,9 @@ class CatalogToolUpgradeSchemaTestCase(ERP5TypeTestCase): ...@@ -4123,6 +4123,9 @@ class CatalogToolUpgradeSchemaTestCase(ERP5TypeTestCase):
"""Tests for "upgrade schema" feature of ERP5 Catalog. """Tests for "upgrade schema" feature of ERP5 Catalog.
""" """
def getBusinessTemplateList(self):
return ("erp5_full_text_mroonga_catalog",)
def afterSetUp(self): def afterSetUp(self):
# Add two connections # Add two connections
db1, db2 = getExtraSqlConnectionStringList()[:2] db1, db2 = getExtraSqlConnectionStringList()[:2]
......
...@@ -46,6 +46,7 @@ class TestERP5Coordinate(ERP5TypeTestCase): ...@@ -46,6 +46,7 @@ class TestERP5Coordinate(ERP5TypeTestCase):
Return the list of required business templates. Return the list of required business templates.
""" """
return ('erp5_core_proxy_field_legacy', return ('erp5_core_proxy_field_legacy',
'erp5_full_text_mroonga_catalog',
'erp5_base',) 'erp5_base',)
def afterSetUp(self): def afterSetUp(self):
......
...@@ -31,10 +31,51 @@ from Products.Formulator.TALESField import TALESMethod ...@@ -31,10 +31,51 @@ from Products.Formulator.TALESField import TALESMethod
from Products.ERP5Type.Core.Folder import Folder from Products.ERP5Type.Core.Folder import Folder
from Products.ERP5Form.Form import field_value_cache from Products.ERP5Form.Form import field_value_cache
class TestProxify(ERP5TypeTestCase):
def getTitle(self): class TestERP5Form(ERP5TypeTestCase):
return "Proxify" def afterSetUp(self):
self.portal.portal_skins.custom.manage_addProduct[
'PageTemplates'].manage_addPageTemplate(
'Base_viewTestRenderer', 'Base_viewTestRenderer')
self.page_template = self.portal.portal_skins.custom.Base_viewTestRenderer
self.page_template.write('''
<html>
<form>
<tal:block tal:repeat="field form/get_fields">
<tal:block tal:replace="structure field/render" />
</tal:block>
</form>
</html>
''')
self.portal.portal_skins.custom.manage_addProduct['ERP5Form'].addERP5Form(
'Base_viewTest', 'Test')
self.form = self.portal.portal_skins.custom.Base_viewTest
self.form.manage_addField('my_string_field', 'String Field', 'StringField')
self.form.my_string_field.values['default'] = "test string field"
self.form.pt = self.page_template.getId()
def beforeTearDown(self):
self.abort()
for custom_skin in (self.form.getId(), self.page_template.getId(),):
if custom_skin in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects([custom_skin])
self.commit()
def test_call(self):
html = self.form()
self.assertIn("test string field", html)
def test_zmi(self):
# minimal tests for custom ZMI views
self.assertTrue(self.form.formProxify())
self.assertTrue(self.form.formUnProxify())
self.assertTrue(self.form.formShowRelatedProxyFields())
class TestProxify(ERP5TypeTestCase):
def afterSetUp(self): def afterSetUp(self):
# base field library # base field library
......
...@@ -8,15 +8,21 @@ ...@@ -8,15 +8,21 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>testProxify</string> </value> <value> <string>testERP5Form</string> </value>
</item> </item>
<item> <item>
<key> <string>default_source_reference</string> </key> <key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5Form.tests.testProxify</string> </value> <value> <string>Products.ERP5Form.tests.testProxify</string> </value>
</item> </item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>test.erp5.testProxify</string> </value> <value> <string>test.erp5.testERP5Form</string> </value>
</item> </item>
<item> <item>
<key> <string>portal_type</string> </key> <key> <string>portal_type</string> </key>
......
...@@ -131,6 +131,22 @@ class TestERP5Workflow(ERP5TypeTestCase): ...@@ -131,6 +131,22 @@ class TestERP5Workflow(ERP5TypeTestCase):
history = doc.workflow_history['wf'] history = doc.workflow_history['wf']
self.assertEqual(len(history), 2)# create, transition1 self.assertEqual(len(history), 2)# create, transition1
transition_variable = transition1.newContent(
portal_type='Workflow Transition Variable',
causality_value=variable1,
variable_default_expression='string:Set by transition variable',
)
workflow._executeTransition(doc,transition1)
self.assertEqual(
workflow.getCurrentStatusDict(doc)['variable1'],
"Set by transition variable")
# Without an expression, the variable is set to None
transition_variable.setVariableDefaultExpression(None)
workflow._executeTransition(doc,transition1)
self.assertEqual(workflow.getCurrentStatusDict(doc)['variable1'], None)
def test_afterScript(self): def test_afterScript(self):
......
...@@ -35,7 +35,8 @@ class TestI18NSearch(ERP5TypeTestCase): ...@@ -35,7 +35,8 @@ class TestI18NSearch(ERP5TypeTestCase):
return "I18N Search" return "I18N Search"
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return ('erp5_base', ) return ('erp5_full_text_mroonga_catalog',
'erp5_base',)
def afterSetUp(self): def afterSetUp(self):
self.person_module = self.portal.person_module self.person_module = self.portal.person_module
......
...@@ -398,9 +398,9 @@ return printed ...@@ -398,9 +398,9 @@ return printed
'Base_viewGeek', 'Base_viewGeek',
'View') 'View')
form = skin_folder._getOb('Base_viewGeek', None) form = skin_folder._getOb('Base_viewGeek', None)
form.manage_addField('my_title', 'Title', 'ProxyField') form.manage_addField('my_proxy_field', 'Proxy', 'ProxyField')
field = form.my_title field = form.my_proxy_field
self.assertFalse(form.get_fields()) self.assertFalse(form.get_fields())
self.assertEqual([field], form.get_fields(include_disabled=True)) self.assertEqual([field], form.get_fields(include_disabled=True))
...@@ -409,10 +409,22 @@ return printed ...@@ -409,10 +409,22 @@ return printed
self.assertEqual('', field.get_tales('default')) self.assertEqual('', field.get_tales('default'))
regexp = '^%s$' % re.escape("Can't find the template field of" regexp = '^%s$' % re.escape("Can't find the template field of"
" <ProxyField at /%s/portal_skins/erp5_geek/Base_viewGeek/my_title>" " <ProxyField at /%s/portal_skins/erp5_geek/Base_viewGeek/my_proxy_field>"
% self.portal.getId()) % self.portal.getId())
for func in ( field.render for func in ( field.render
, partial(field.get_value, 'default') , partial(field.get_value, 'default')
, partial(field.get_recursive_tales, 'default') , partial(field.get_recursive_tales, 'default')
): ):
self.assertRaisesRegexp(BrokenProxyField, regexp, func) self.assertRaisesRegexp(BrokenProxyField, regexp, func)
# we can still view the field in ZMI
form.manage_main()
field.manage_main()
# and repair it
form.manage_addField('my_field', 'Title', 'StringField')
field.manage_edit(
{
'field_form_id': 'Base_viewGeek',
'field_field_id': 'my_field',
})
self.assertEqual(field.getTemplateField(), form.my_field)
...@@ -43,7 +43,7 @@ class TestVanillaERP5Catalog(ERP5TypeTestCase, LogInterceptor): ...@@ -43,7 +43,7 @@ class TestVanillaERP5Catalog(ERP5TypeTestCase, LogInterceptor):
return "VanillaERP5Catalog" return "VanillaERP5Catalog"
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return ('erp5_base', ) return ('erp5_full_text_mroonga_catalog', 'erp5_base')
# Different variables used for this test # Different variables used for this test
username = 'seb' username = 'seb'
......
...@@ -84,7 +84,6 @@ class TestZODBHistory(ERP5TypeTestCase): ...@@ -84,7 +84,6 @@ class TestZODBHistory(ERP5TypeTestCase):
self.assertTrue(len(history_list) > 0) self.assertTrue(len(history_list) > 0)
d = history_list[0] d = history_list[0]
changes = d['changes'] changes = d['changes']
self.assertEqual(changes['portal_type'], 'Organisation')
self.assertEqual(changes['id'], 'org') self.assertEqual(changes['id'], 'org')
self.assertTrue(changes['uid'] is not None) self.assertTrue(changes['uid'] is not None)
...@@ -134,6 +133,17 @@ class TestZODBHistory(ERP5TypeTestCase): ...@@ -134,6 +133,17 @@ class TestZODBHistory(ERP5TypeTestCase):
from zExceptions import Unauthorized from zExceptions import Unauthorized
self.assertRaises(Unauthorized, document.Base_viewZODBHistory) self.assertRaises(Unauthorized, document.Base_viewZODBHistory)
def test_ZODBHistoryNonAsciiProperty(self):
self.loginByUserName('tatuya')
document = self.addOrganisation(self.id())
document.edit(title='ネクセディ', default_address_city='千代田区')
self.commit()
_, change, = document.Base_getZODBHistoryList()
self.assertIn('title: ネクセディ', change.getProperty('changes'))
# no encoding error
document.Base_viewZODBHistory()
def test_ZODBHistoryBinaryData(self): def test_ZODBHistoryBinaryData(self):
""" """
Make sure ZODB History view works with binary content Make sure ZODB History view works with binary content
...@@ -156,9 +166,9 @@ class TestZODBHistory(ERP5TypeTestCase): ...@@ -156,9 +166,9 @@ class TestZODBHistory(ERP5TypeTestCase):
document.Base_viewZODBHistory() document.Base_viewZODBHistory()
change, = document.Base_getZODBHistoryList() change, = document.Base_getZODBHistoryList()
self.assertIn('data:(binary)', change.getProperty('changes')) self.assertIn('data: (binary)', change.getProperty('changes'))
self.assertIn('content_type:image/png', change.getProperty('changes')) self.assertIn('content_type: image/png', change.getProperty('changes'))
self.assertIn('title:ロゴ', change.getProperty('changes')) self.assertIn('title: ロゴ', change.getProperty('changes'))
def test_suite(): def test_suite():
......
erp5_full_text_mroonga_catalog
erp5_base erp5_base
erp5_csv_style erp5_csv_style
erp5_core_proxy_field_legacy erp5_core_proxy_field_legacy
\ No newline at end of file
test.erp5.testAccessTab test.erp5.testAccessTab
test.erp5.testSequence
test.erp5.testActivityTool test.erp5.testActivityTool
test.erp5.testAlarm test.erp5.testAlarm
test.erp5.testArrow test.erp5.testArrow
...@@ -8,8 +7,8 @@ test.erp5.testAutoLogout ...@@ -8,8 +7,8 @@ test.erp5.testAutoLogout
test.erp5.testBase test.erp5.testBase
test.erp5.testBusinessTemplate test.erp5.testBusinessTemplate
test.erp5.testCache test.erp5.testCache
test.erp5.testCacheTool
test.erp5.testCachedSkinsTool test.erp5.testCachedSkinsTool
test.erp5.testCacheTool
test.erp5.testConstraint test.erp5.testConstraint
test.erp5.testContributionRegistryTool test.erp5.testContributionRegistryTool
test.erp5.testCookieCrumbler test.erp5.testCookieCrumbler
...@@ -20,6 +19,7 @@ test.erp5.testERP5Catalog ...@@ -20,6 +19,7 @@ test.erp5.testERP5Catalog
test.erp5.testERP5Category test.erp5.testERP5Category
test.erp5.testERP5Coordinate test.erp5.testERP5Coordinate
test.erp5.testERP5Core test.erp5.testERP5Core
test.erp5.testERP5Form
test.erp5.testERP5Type test.erp5.testERP5Type
test.erp5.testERP5TypeInterfaces test.erp5.testERP5TypeInterfaces
test.erp5.testERP5Workflow test.erp5.testERP5Workflow
...@@ -42,11 +42,11 @@ test.erp5.testPerson ...@@ -42,11 +42,11 @@ test.erp5.testPerson
test.erp5.testPredicate test.erp5.testPredicate
test.erp5.testPreferences test.erp5.testPreferences
test.erp5.testPropertyRecordable test.erp5.testPropertyRecordable
test.erp5.testProxify
test.erp5.testProxyField test.erp5.testProxyField
test.erp5.testQueryModule test.erp5.testQueryModule
test.erp5.testRestrictedPythonSecurity test.erp5.testRestrictedPythonSecurity
test.erp5.testSelectionTool test.erp5.testSelectionTool
test.erp5.testSequence
test.erp5.testSessionTool test.erp5.testSessionTool
test.erp5.testTimeout test.erp5.testTimeout
test.erp5.testTimerService test.erp5.testTimerService
......
theme_used = context.Base_getThemeDict(css_path="template_css/book")
if theme:
return theme_used.get('theme', '')
document_description = context.REQUEST.get('override_document_description', '')
document_short_title = context.REQUEST.get('override_document_short_title', '')
document_title = context.REQUEST.get('override_document_title', '')
document_version = context.REQUEST.get('override_document_version', '')
document_reference = context.REQUEST.get('override_document_reference', '')
if title:
return document_title if document_title else context.getTitle()
if short_title:
return document_short_title if document_short_title else context.getShortTitle()
if reference:
book_reference = document_reference if document_reference else context.getReference()
if not book_reference:
book_title = document_title if document_title else context.getTitle()
book_prefix = context.portal_preferences.getPreferredCorporateIdentityTemplateBookDocumentPrefix() or "Book."
book_reference = book_prefix + book_title.replace(" ", ".")
return book_reference
if description:
return document_description if document_description else context.getDescription()
if version:
return document_version if document_version else context.getVersion()
source = context.Base_getSourceDict(
source = context.getSource(),
override_source_person_title = context.REQUEST.get('override_source_person_title', None),
override_source_organisation_title = context.REQUEST.get('override_source_organisation_title', None),
override_logo_reference=context.REQUEST.get('override_logo_reference', None),
theme_logo_url=theme_used.get("theme_logo_url", None)
)
if source_organisation:
return source.get("organisation_title", "")
if source_person:
return source.get("name", "")
if logo:
url = source.get('enhanced_logo_url', '')
return url.split('?')[0]
return ''
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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