Commit dc26ced4 authored by Rafael Monnerat's avatar Rafael Monnerat

ERP5 Configurator Product initial commit.

ERP5 Configurator allows developer creates configuration wizards for configure an ERP5 Instance. 


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@41680 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent c12fa76d
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class AccountConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" Setup an Accounting Account. """
meta_type = 'ERP5 Account Configurator Item'
portal_type = 'Account Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Account )
def build(self, business_configuration):
portal = self.getPortalObject()
account_module = portal.account_module
extra_kw = {}
account_id = getattr(self, 'account_id', None)
if account_id:
# XXX FIXME This cause conflict when use configuration
# more then once.
#extra_kw['id'] = account_id
pass
account = account_module.newContent(
portal_type='Account',
title=self.getTitle(),
account_type=self.getAccountType(),
gap=self.getGap(),
financial_section=self.getFinancialSection(),
credit_account=self.isCreditAccount(),
description=self.getDescription(),
**extra_kw)
## add to customer template
self.install(account, business_configuration)
##############################################################################
#
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
# Jerome Perrin <jerome@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class AccountingPeriodConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" Setup an Accounting Period. """
meta_type = 'ERP5 Accounting Period Configurator Item'
portal_type = 'Accounting Period Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Task )
def build(self, business_configuration):
portal = self.getPortalObject()
organisation_id = business_configuration.\
getGlobalConfigurationAttr('organisation_id')
organisation = portal.organisation_module._getOb(organisation_id)
period = organisation.newContent(
portal_type='Accounting Period',
start_date=self.getStartDate(),
stop_date=self.getStopDate(),
short_title=self.getShortTitle(),
title=self.getTitle())
# no need to 'install' in the business template, because it's contain as
# subobject of an organisation we already added.
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import time
from AccessControl import ClassSecurityInfo
from Globals import PersistentMapping
from Acquisition import aq_base
from Products.ERP5Type import Permissions, PropertySheet
from zLOG import LOG, INFO
from cStringIO import StringIO
from Products.ERP5Configurator.Tool.ConfiguratorTool import _validateFormToRequest
from Products.ERP5.Document.Url import Url
from Products.ERP5.Document.Item import Item
## Workflow states definitions
INITIAL_STATE_TITLE = 'Start'
DOWNLOAD_STATE_TITLE = 'Download'
END_STATE_TITLE = 'End'
class BusinessConfiguration(Item, Url):
"""
BusinessConfiguration store the values enter by the wizard.
"""
meta_type = 'ERP5 Business Configuration'
portal_type = 'Business Configuration'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Item
, PropertySheet.Arrow
, PropertySheet.BusinessConfiguration
, PropertySheet.Comment
, PropertySheet.Url
, PropertySheet.Version
)
security.declareProtected(Permissions.View, 'isInitialConfigurationState')
def isInitialConfigurationState(self):
""" Check if the Business Configuration is on initial workflow state
"""
workflow = self.getResourceValue()
if workflow is not None:
return self.getCurrentState() == workflow.getSource()
return None
security.declareProtected(Permissions.View, 'isDownloadConfigurationState')
def isDownloadConfigurationState(self):
""" Check if the Business Configuration is on Download State
"""
return self.getCurrentStateTitle() == DOWNLOAD_STATE_TITLE
security.declareProtected(Permissions.View, 'isEndConfigurationState')
def isEndConfigurationState(self):
""" Check if the Business Configuration is on End State
"""
return self.getCurrentStateTitle() == END_STATE_TITLE
security.declareProtected(Permissions.View, 'getNextTransition')
def getNextTransition(self):
""" Return next transition. """
current_state = self.getCurrentStateValue()
if current_state is None:
return None
transition_list = current_state.getAvailableTransitionList(self)
transition_number = len(transition_list)
if transition_number > 1:
raise TypeError, "More than one transition is available."
elif transition_number == 0:
return None
return transition_list[0]
security.declarePrivate('_executeTransition')
def _executeTransition(self, \
form_kw=None,
request_kw=None):
""" Execute the transition. """
root_conf_save = None
if form_kw is None:
form_kw = {}
current_state = self.getCurrentStateValue()
transition = self.getNextTransition()
next_state = self.unrestrictedTraverse(transition.getDestination())
## it's possible that we have already saved a configuration save object
## in workflow_history for this state so we use it
root_conf_save = self._getConfSaveForStateFromWorkflowHistory()
if root_conf_save is None:
## we haven't saved any configuration save for this state so create new one
root_conf_save = self.newContent(portal_type='Configuration Save')
else:
## we have already created configuration save for this state
## so remove from it already existing configuration items
if root_conf_save!=self: ## don't delete ourselves
existing_conf_items = root_conf_save.objectIds()
existing_conf_items = map(None, existing_conf_items)
root_conf_save.manage_delObjects(existing_conf_items)
## save ...
root_conf_save.edit(**form_kw)
## Add some variables so we can get use them in workflow after scripts
form_kw['configuration_save_url'] = root_conf_save.getRelativeUrl()
form_kw['transition'] = transition.getRelativeUrl()
current_state.executeTransition(transition, self, form_kw=form_kw)
security.declarePrivate('_displayNextForm')
def _displayNextForm(self, \
validation_errors=None, \
context=None, \
transition=None):
""" Render next form. """
if transition is None:
transition = self.getNextTransition()
while transition is not None:
form_id = transition.getTransitionFormId()
current_state = self.getCurrentStateValue()
if self.isDownloadConfigurationState():
## exec next transition for this business configuration
self._executeTransition()
transition = self.getNextTransition()
return None, None, None, None, None
if form_id is None:
## go on until you find a form
self._executeTransition()
transition = self.getNextTransition()
else:
if context is None:
## examine workflow_history for already saved
## 'Configuration Save' objects for this state
context = self._getConfSaveForStateFromWorkflowHistory()
## get form object in a proper context
form_html, form_title = self._renderFormInContext(form_id, context, validation_errors)
## check if we've can shown 'Previous' button
previous = None
translate = self.Base_translateString
if self._isAlreadyConfSaveInWorkflowHistory(transition):
previous = translate("Previous")
return previous, form_html, form_title, \
translate(transition.getTitle()), self.getServerBuffer()
security.declarePrivate('_renderFormInContext')
def _renderFormInContext(self, form_id, context, validation_errors):
html = ""
html_forms = []
isMultiEntryTransition = self._isMultiEntryTransition()
forms_number = isMultiEntryTransition
if context is None:
form = getattr(self, form_id)
if not isMultiEntryTransition:
if validation_errors is not None:
self.REQUEST.set('field_errors', form.ErrorFields(validation_errors))
html = form()
else:
template_html = form()
for form_counter in range(0, forms_number):
form_html = self.Base_mainConfiguratorFormTemplate(
current_form_number = form_counter + 1,
max_form_numbers = forms_number,
form_title = form.title,
form_html = template_html)
html_forms.append(form_html)
else:
if not isMultiEntryTransition:
## only one form saved under this context
form = getattr(context, form_id)
if validation_errors is not None:
self.REQUEST.set('field_errors', form.ErrorFields(validation_errors))
html = form()
else:
## we have many forms saved under this context
form = getattr(self, form_id)
field_ids = form.get_fields()
for form_counter in range(0, forms_number):
## fill REQUEST with data as it will be used to render form
for field in field_ids:
field_value = getattr(context, "field_%s" %field.id, None)
if field_value is not None and len(field_value) > form_counter:
field_value = field_value[form_counter]
self.REQUEST.set(field.id, field_value)
else:
self.REQUEST.set(field.id, '')
form_html = self.Base_mainConfiguratorFormTemplate( \
current_form_number = form_counter +1, \
max_form_numbers = forms_number, \
form_html = getattr(context, form_id)())
html_forms.append(form_html)
if html_forms!=[]:
html = "\n".join(html_forms)
title = form.title
return html, title
security.declarePrivate('_displayPreviousForm')
def _displayPreviousForm(self):
""" Render previous form using workflow history. """
workflow_history = self.getCurrentStateValue().getWorkflowHistory(self, remove_undo=1)
workflow_history.reverse()
for wh in workflow_history:
## go one step back
current_state = self.getCurrentStateValue()
current_state.undoTransition(self)
transition = self.unrestrictedTraverse(wh['transition'])
conf_save = self.unrestrictedTraverse(wh['configuration_save_url'])
## check if this transition can be shown to user ...
if transition._checkPermission(self) and \
transition.getTransitionFormId() is not None:
return self._displayNextForm(context=conf_save, transition=transition)
security.declarePrivate('_validateNextForm')
def _validateNextForm(self, **kw):
""" Validate the form displayed to the user. """
REQUEST = self.REQUEST
form = getattr(self, self.getNextTransition().getTransitionFormId())
return _validateFormToRequest(form, REQUEST, **kw)
#############
## misc ##
#############
security.declarePrivate('_getConfigurationStack')
def _getConfigurationStack(self):
""" Return list of created by client configuration save objects
sort on id which is an integer. """
result = self.objectValues('ERP5 Configuration Save')
result = map(None, result)
result.sort(lambda x, y: cmp(x.getIntIndex(x.getIntId()),
y.getIntIndex(y.getIntId())))
return result
security.declarePrivate('_getConfSaveForStateFromWorkflowHistory')
def _getConfSaveForStateFromWorkflowHistory(self):
""" Get from workflow history configuration save for this state """
configuration_save = None
current_state = self.getCurrentStateValue()
transition = self.getNextTransition()
next_state = self.unrestrictedTraverse(transition.getDestination())
workflow_history = current_state.getWorkflowHistory(self)
for wh in workflow_history:
wh_state = self.unrestrictedTraverse(wh['current_state'])
if wh_state == next_state:
configuration_save = self.unrestrictedTraverse(wh['configuration_save_url'])
return configuration_save
security.declarePrivate('_isAlreadyConfSaveInWorkflowHistory')
def _isAlreadyConfSaveInWorkflowHistory(self, transition):
""" check if we have an entry in worklow history for this state """
workflow_history = self.getCurrentStateValue().getWorkflowHistory(self, remove_undo=1)
workflow_history.reverse()
for wh in workflow_history:
wh_state = self.unrestrictedTraverse(wh['current_state'])
for wh_transition in wh_state.getAvailableTransitionList(self):
if wh_transition.getTransitionFormId() is not None and wh_transition!=transition:
return True
return False
security.declarePrivate('_isMultiEntryTransition')
def _isMultiEntryTransition(self):
""" Return number of multiple forms to show for a transition. """
next_transition = self.getNextTransition()
if next_transition is not None:
if getattr(aq_base(self), '_multi_entry_transitions', None) is not None:
multi_forms = self._multi_entry_transitions.get(next_transition.getRelativeUrl(), 0)
if multi_forms == 1:
# we have set '1' which means show one form which is not multiple forms
multi_forms = 0
return multi_forms
else:
return 0
else:
## no transitions available
return 0
security.declareProtected(Permissions.ModifyPortalContent, 'setMultiEntryTransition')
def setMultiEntryTransition(self, transition_url, max_entry_number):
""" Set a transition as multiple - i.e max_entry_number of forms
which will be rendered. This method is called in after scripts
and usually this number is set by user in a web form. """
if getattr(aq_base(self), '_multi_entry_transitions', None) is None:
self._multi_entry_transitions = PersistentMapping()
self._multi_entry_transitions[transition_url] = max_entry_number
security.declareProtected(Permissions.ModifyPortalContent, 'setServerBuffer')
def setServerBuffer(self, **kw):
""" Set what we should return to client. """
if getattr(aq_base(self), '_server_buffer', None) is None:
self._server_buffer = {}
for item, value in kw.items():
self._server_buffer[item] = value
self._p_changed = 1
security.declareProtected(Permissions.View, 'getServerBuffer')
def getServerBuffer(self):
""" Get return buffer which will be sent to client and
afterwards deleted. """
server_buffer = getattr(aq_base(self), '_server_buffer', {})
self._server_buffer = {}
return server_buffer
security.declareProtected(Permissions.ModifyPortalContent, 'setGlobalConfigurationAttr')
def setGlobalConfigurationAttr(self, **kw):
""" Set global business configuration attribute. """
if getattr(aq_base(self),
'_global_configuration_attributes', None) is None:
self._global_configuration_attributes = PersistentMapping()
for key, value in kw.items():
self._global_configuration_attributes[key] = value
security.declareProtected(Permissions.View, 'getGlobalConfigurationAttr')
def getGlobalConfigurationAttr(self, key, default = None):
""" Get global business configuration attribute. """
global_configuration_attributes = getattr(self, '_global_configuration_attributes', {})
return global_configuration_attributes.get(key, default)
security.declareProtected(Permissions.View, 'getBuiltBusinessConfigurationBT5List')
def getBuiltBusinessConfigurationBT5List(self):
"""
Get list of built business templates in a Wizard format.
"""
bt5_file_list = []
portal = self.getPortalObject()
for bt_link in self.contentValues(portal_type="Link"):
bt5_item = dict(bt5_id = bt_link.getUrlString(),
bt5_filedata = "")
bt5_file_list.append(bt5_item)
for bt_file in self.contentValues(portal_type="File"):
bt5_item = dict(bt5_id = bt_file.getId(),
bt5_filedata = bt_file.getData())
bt5_file_list.append(bt5_item)
return bt5_file_list
############# Instance and Business Configuration ########################
security.declareProtected(Permissions.ModifyPortalContent, 'buildConfiguration')
def buildConfiguration(self):
"""
Build list of business templates according to already saved
Configuration Saves (i.e. user input).
This is the actual implementation which can be used from workflow
actions and Configurator requets
"""
bt5_file_list = []
start = time.time()
bc_id = self.getId()
LOG("CONFIGURATOR", INFO,
'Build process started for %s' % self.getRelativeUrl())
conf_item_list = []
# build
for conf_save in self._getConfigurationStack():
# XXX: check which items are configure-able
conf_item_list = [x for x in conf_save.contentValues()]
conf_item_list.sort(lambda x,y: cmp(x.getIntId(), y.getIntId()))
for conf_item in conf_item_list:
conf_save_id = conf_save.getId()
configuration_item_object = conf_item
LOG('CONFIGURATOR', INFO, 'Building --> %s' % conf_item)
start_build = time.time()
build_result = conf_item.build(self)
LOG('CONFIGURATOR', INFO, 'Built --> %s (%.02fs)' \
% (conf_item, time.time()-start_build))
# save list of generated or reused bt5 ids in bc
LOG('CONFIGURATOR', INFO,
'Build process started for %s ended after %.02fs'
%(self.getRelativeUrl(), time.time()-start))
return bt5_file_list
security.declareProtected(Permissions.ModifyPortalContent, 'resetBusinessConfiguration')
def resetBusinessConfiguration(self):
"""
Reset Business Confiration at server side.
Remove all traces from user input (i.e. Configuration Saves, workflow history).
"""
object_ids = []
for obj in self.contentValues(filter = {'portal_type': ['Configuration Save', 'File', 'Link']}):
object_ids.append(obj.getId())
self.manage_delObjects(object_ids)
del self.workflow_history
# ERP5 Workflow initialization
erp5_workflow = self.getResourceValue()
erp5_workflow.initializeDocument(self)
def isStandardBT5(self, bt5_id):
"""Is bt5_id standard gzipped bt5 id?
Use ERP5 site portal_templates to get list of bt5_ids from configured
repository. This relies on the fact that the host site have a
configured repository.
"""
# XXX This should be one API from portal_templates
bt5_title_list = []
bt5_title = bt5_id.split('.')[0]
for bt5 in self.getPortalObject().portal_templates\
.getRepositoryBusinessTemplateList():
bt5_title_list.append(bt5.getTitle())
return bt5_title in bt5_title_list
def getPublicUrlForBT5Id(self, bt5_id):
""" Generate publicly accessible URL for business template """
portal = self.getPortalObject()
return portal.portal_templates.getBusinessTemplateUrl(None, bt5_id)
security.declareProtected(Permissions.ModifyPortalContent, 'installConfiguration')
def installConfiguration(self, execute_after_setup_script = 1):
"""
Install in remote instance already built list of business templates
which are saved in the Business Configuration.
"""
kw = dict(tag="start")
bt5_file_list = []
portal = self.getPortalObject()
for bt_link in self.contentValues(portal_type="Link"):
portal.portal_templates.activate(**kw).updateBusinessTemplateFromUrl(
bt_link.getUrlString())
LOG("Business COnfiguration", INFO,
"Install %s to %s" % (bt_link.getUrlString(), self.getRelativeUrl()))
kw["after_tag"] = kw["tag"]
kw["tag"] = bt_link.getTitle()
for bt_file in self.contentValues(portal_type="File"):
if bt_file.getTitle("").replace(".bt5", "") == self.getSpecialiseTitle():
bt5_io = StringIO(str(bt_file.getData()))
# XXX FIXME (lucas): Why FAIL on the log message?
LOG("Business Configuration", INFO,
"[FAIL] Import of bt5 file (%s - %s)" % \
(bt_file.getId(), bt_file.getTitle()))
bc = portal.portal_templates.importFile(import_file=bt5_io,
batch_mode=1)
bc.activate(**kw).install()
kw["after_tag"] = kw["tag"]
kw["tag"] = bt_file.getTitle()
if execute_after_setup_script:
customer_template = self.getSpecialiseValue()
customer_template_relative_url = customer_template.getRelativeUrl()
self.activate(**kw).ERP5Site_afterConfigurationSetup(
customer_template_relative_url=customer_template_relative_url,
alter_preferences=True)
LOG("Business Configuration", INFO,
"After setup script called (force) for %s : %s" %
(self.getRelativeUrl(), self.getSpecialise()))
##############################################################################
#
# Copyright (c) 2008 Nexedi SARL and Contributors. All Rights Reserved.
# Yoshinori Okuji <yo@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class CatalogKeywordKeyConfiguratorItem(ConfiguratorItemMixin, XMLObject):
"""Set up catalog keyword keys."""
meta_type = 'ERP5 Catalog Keyword Key Configurator Item'
portal_type = 'Catalog Keyword Key Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore )
def build(self, business_configuration):
portal = self.getPortalObject()
catalog = portal.portal_catalog.getSQLCatalog()
key_list = list(catalog.getProperty('sql_catalog_keyword_search_keys', ()))
for k in self.key_list:
if k not in key_list:
key_list.append(k)
key_list = tuple(key_list)
catalog._setPropValue('sql_catalog_keyword_search_keys', key_list)
bt = business_configuration.getSpecialiseValue()
bt.edit(template_catalog_keyword_key_list=key_list)
##############################################################################
#
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
# Jerome Perrin <jerome@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from StringIO import StringIO
from Acquisition import aq_base
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class UnrestrictedStringIO(StringIO):
__allow_access_to_unprotected_subobjects__ = 1
class CategoriesSpreadsheetConfiguratorItem(ConfiguratorItemMixin, XMLObject):
"""Import a categories spreadsheet.
"""
meta_type = 'ERP5 Categories Spreadsheet Configurator Item'
portal_type = 'Categories Spreadsheet Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.CategoriesSpreadsheetConfiguratorItem
)
def build(self, business_configuration):
portal = self.getPortalObject()
ctool = portal.portal_categories
self._readSpreadSheet()
cache = self._category_cache
for bc_id, category_list in cache.items():
if bc_id in ctool.objectIds():
bc = ctool._getOb(bc_id)
else:
# TODO: test bc creation
# the bc should be added as base category in bt5 ?
bc = ctool.newContent(id=bc_id)
for category_info in category_list:
path = bc
for cat in category_info['path'].split("/")[1:]:
if not cat in path.objectIds():
path = path.newContent(
portal_type='Category',
id=cat,)
else:
path = path[cat]
edit_dict = category_info.copy()
edit_dict.pop('path')
path.edit(**edit_dict)
## add to customer template
self.install(path, business_configuration)
def _readSpreadSheet(self):
"""Read the spreadsheet and prepare internal category cache.
"""
aq_self = aq_base(self)
if getattr(aq_self, '_category_cache', None) is None:
# TODO use a invalid_spreadsheet_error_handler to report invalid
# spreadsheet messages (see http://svn.erp5.org?rev=24908&view=rev )
aq_self._category_cache = self.Base_getCategoriesSpreadSheetMapping(
UnrestrictedStringIO(self.getDefaultCategoriesSpreadsheetData()))
security.declareProtected(Permissions.ModifyPortalContent,
'setDefaultCategoriesSpreadsheetFile')
def setDefaultCategoriesSpreadsheetFile(self, *args, **kw):
"""Reset the spreadsheet cache."""
self._setDefaultCategoriesSpreadsheetFile(*args, **kw)
self._category_cache = None
self.reindexObject()
security.declareProtected(Permissions.ModifyPortalContent,
'setCategoriesSpreadsheetFile')
setCategoriesSpreadsheetFile = setDefaultCategoriesSpreadsheetFile
security.declareProtected(Permissions.AccessContentsInformation,
'getCategoryTitleItemList')
def getCategoryTitleItemList(self, base_category_id, base=0):
"""Returns title item list for a base category contained in this
spreadsheet.
"""
self._readSpreadSheet()
cache = self._category_cache
result = [('', '')]
if base_category_id not in cache:
return result # TODO: return some kind of default. Where is this
# default ??? configurator_%s % base_category_id ?
# If we add default here, it should also be used in build
# ...
category_path_dict = dict()
for item in cache[base_category_id]:
category_path_dict[item['path']] = item
for item in cache[base_category_id]:
# the first item in this list is the base category itself, so we skip it.
if item['path'] == base_category_id:
continue
# recreate logical path
path_element_list = []
title_list = []
for path_element in item['path'].split('/'):
path_element_list.append(path_element)
title_list.append(category_path_dict['/'.join(path_element_list)]['title'])
if base:
result.append(('/'.join(title_list[1:]), item['path']))
else:
result.append(('/'.join(title_list[1:]),
'/'.join(item['path'].split('/')[1:])))
return result
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class CategoryConfiguratorItem(ConfiguratorItemMixin, XMLObject):
"""This class is meta build step for customization of ERP5 site."""
meta_type = 'ERP5 Category Configurator Item'
portal_type = 'Category Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore)
def build(self, business_configuration):
portal = self.getPortalObject()
category_root = portal.portal_categories[self.category_root]
object_id = self.object_id
if object_id in category_root.objectIds():
category_root.manage_delObjects(object_id)
category = category_root.newContent(portal_type='Category',
id = object_id,
title = self.getTitle())
## add to customer template
self.install(category, business_configuration)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.Document.Path import Path
class ConfigurationSave(Path):
""" This class is the base class for all template items. """
portal_type = 'Configuration Save'
meta_type = 'ERP5 Configuration Save'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.SortIndex )
def addConfigurationItem(self, configuration_item_class_name, **kw):
""" Add new configuration item. """
## remove manually specified a configration title
if kw.has_key('conf_title'):
self.setTitle(kw['conf_title'])
kw.pop('conf_title')
conf_item = self.newContent(portal_type = configuration_item_class_name, **kw)
return conf_item
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class CurrencyConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" Setup currency. """
meta_type = 'ERP5 Currency Configurator Item'
portal_type = 'Currency Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Price
, PropertySheet.Resource
, PropertySheet.Reference )
def build(self, business_configuration):
portal = self.getPortalObject()
currency_module = portal._getOb('currency_module')
title = self.getTitle()
reference = self.getReference()
base_unit_quantity = self.getBaseUnitQuantity()
# XXX FIXME This is not exactly desired behaviour
currency = self.portal_catalog.getResultValue(id=reference,
portal_type="Currency")
if currency is None:
currency = currency_module.newContent(portal_type = "Currency",
id = reference,
title = title,
reference = reference,
base_unit_quantity = base_unit_quantity)
## add to customer template
self.install(currency, business_configuration)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.CMFCore.utils import getToolByName
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class CustomerBT5ConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" Create a new bt5 for customer configuration.
This business template is not installed locally, only build.
"""
meta_type = 'ERP5 Customer BT5 Configurator Item'
portal_type = 'Customer BT5 Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore )
def build(self, business_configuration):
template_tool = getToolByName(self.getPortalObject(),
'portal_templates')
bt5 = template_tool.newContent(portal_type="Business Template", \
title=self.bt5_id)
## ..and set it as current
business_configuration.setSpecialise(bt5.getRelativeUrl())
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.CMFCore.utils import getToolByName
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class ExportCustomerBT5ConfiguratorItem(XMLObject, ConfiguratorItemMixin):
""" Create a new bt5 for customer configuration. """
meta_type = 'ERP5 Export Customer BT5 Configurator Item'
portal_type = 'Export Customer BT5 Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore )
def build(self, business_configuration):
portal = self.getPortalObject()
template_tool = getToolByName(portal, 'portal_templates')
bt5_obj = business_configuration.getSpecialiseValue()
if bt5_obj.getBuildingState() != 'built':
## build template so it can be exported
bt5_obj.edit()
bt5_obj.build()
bt5_data = template_tool.export(bt5_obj)
business_configuration.newContent(
portal_type='File',
title = bt5_obj.getTitle(),
data = bt5_data)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class OrganisationConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" This class install a Organisation."""
meta_type = 'ERP5 Organisation Configurator Item'
portal_type = 'Organisation Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Organisation )
def build(self, business_configuration):
""" Setup organisation. """
portal = self.getPortalObject()
organisation = portal.organisation_module.newContent(portal_type="Organisation")
org_dict = {'price_currency': 'currency_module/%s' % self.getPriceCurrency(),
'group': self.getGroup(),
'title': self.getTitle(),
'corporate_name': self.getCorporateName(),
'default_address_city': self.getDefaultAddressCity(),
'default_email_text': self.getDefaultEmailText(),
'default_telephone_text': self.getDefaultTelephoneText(),
'default_address_zip_code': self.getDefaultAddressZipCode(),
'default_address_region': self.getDefaultAddressRegion(),
'default_address_street_address': self.getDefaultAddressStreetAddress(),
'site':'main', # First customer's organisation is always main site.
}
organisation.edit(**org_dict)
# store globally organization_id
business_configuration.setGlobalConfigurationAttr(organisation_id=organisation.getId())
## add to customer template
self.install(organisation, business_configuration)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class PermissionConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" Set permission matrix on module."""
meta_type = 'ERP5 Permission Configurator Item'
portal_type = 'Permission Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore )
def build(self, business_configuration):
template_module_id_list = []
module_permissions_map = {}
sheets_dict = business_configuration.ConfigurationTemplate_readOOCalcFile(\
self.filename)
for module_id, permissions in sheets_dict.items():
module_permissions = {}
for permission in permissions:
roles = []
permission_name = permission.pop('permission')
for role, checked in permission.items():
if checked == '1': roles.append(role)
module_permissions[permission_name] = roles
# add to module map
module_permissions_map[module_id] = module_permissions
# set permissions in fake site
portal = self.getPortalObject()
for module_id, permissions_map in module_permissions_map.items():
if permissions_map != {}:
template_module_id_list.append(module_id)
module = portal[module_id]
for permission_name, roles in permissions_map.items():
# we must alway include additionally 'Manager' and 'Owner'
roles.extend(['Manager', 'Owner'])
module.manage_permission(permission_name, tuple(roles), 0)
# add customized module to customer's bt5
if len(template_module_id_list):
bt5_obj = business_configuration.getSpecialiseValue()
bt5_obj.setTemplateModuleIdList(template_module_id_list)
\ No newline at end of file
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Acquisition import aq_base
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from DateTime import DateTime
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class PersonConfiguratorItem(XMLObject, ConfiguratorItemMixin):
""" Setup user. """
meta_type = 'ERP5 Person Configurator Item'
portal_type = 'Person Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Reference
, PropertySheet.Person
, PropertySheet.Login)
def build(self, business_configuration):
portal = self.getPortalObject()
person = portal.person_module.newContent(portal_type="Person")
group_id = getattr(aq_base(self), 'group_id', None)
site_id = getattr(aq_base(self), 'site_id', None)
if getattr(aq_base(self), 'organisation_id', None) is not None:
person.setCareerSubordination('organisation_module/%s' %self.organisation_id)
# save
person_dict = {'default_email_text': self.getDefaultEmailText(),
'default_telephone_text': self.getDefaultTelephoneText(),
'first_name': self.getFirstName(),
'career_function': self.getFunction(),
'last_name': self.getLastName(),
'password': self.getPassword(),
}
person.edit(**person_dict)
# explicitly use direct mutator to avoid uniqueness checks in Person.setReference
# which work in main ERP5 site context (uses catalog and cache)
# this is a problem when customer's entered reference is the same as
# already exisitng one in main ERP5 site one
person._setReference(self.getReference())
assignment = person.newContent(portal_type="Assignment")
assignment.setFunction(self.getFunction())
assignment.setGroup(group_id)
assignment.setSite(site_id)
# Set dates are required to create valid assigments.
now = DateTime()
assignment.setStartDate(now)
# XXX Is it required to set stop date?
# Define valid for 10 years.
assignment.setStopDate(now + (365*10))
## add to customer template
self.install(person, business_configuration)
##############################################################################
#
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
# TAHARA Yusei <yusei@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class PortalTypeConfiguratorItem(ConfiguratorItemMixin, XMLObject):
"""Configure Portal Type."""
meta_type = 'ERP5 Portal Type Configurator Item'
portal_type = 'Portal Type Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore )
def build(self, business_configuration):
portal = self.getPortalObject()
# Support adding new property sheet to portal type information.
# arguments:
# * target_portal_type
# * add_propertysheet_list
type_information = getattr(portal.portal_types, self.target_portal_type)
for name in self.add_propertysheet_list:
if not name in type_information.property_sheet_list:
new_property_sheet_list = list(type_information.property_sheet_list)
new_property_sheet_list.append(name)
type_information.property_sheet_list = tuple(new_property_sheet_list)
bt5_obj = business_configuration.getSpecialiseValue()
old_property_sheet_list = bt5_obj.getTemplatePortalTypePropertySheetList()
new_property_sheet_list = (list(old_property_sheet_list) +
['%s | %s' % (self.target_portal_type, name)
for name in self.add_propertysheet_list]
)
bt5_obj.edit(
template_portal_type_property_sheet_list=new_property_sheet_list)
#
# TODO:This class must support many other features we can use in ZMI.
#
##############################################################################
#
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
# Jerome Perrin <jerome@nexedi.com>
#
##############################################################################
from Acquisition import aq_base
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class PortalTypeRolesSpreadsheetConfiguratorItem(ConfiguratorItemMixin, XMLObject):
"""Import a portal type roles spreadsheet.
"""
meta_type = 'ERP5 Portal Type Roles Spreadsheet Configurator Item'
portal_type = 'Portal Type Roles Spreadsheet Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.PortalTypeRolesSpreadsheetConfiguratorItem
)
def build(self, business_configuration):
portal = self.getPortalObject()
self._readSpreadSheet()
for type_name, role_list in self._spreadsheet_cache.items():
portal_type = portal.portal_types.getTypeInfo(type_name)
for role in role_list:
# rebuild a category from Group / Site & Function
category_list = []
for bc in ('Group', 'Site', 'Function'):
if role.get(bc):
category_list.append(role[bc])
#category = '\n'.join(category_list)
role_dict = {
#'title': 'role',
'description': role.get('Description', ''),
'role_name_list': role.get('Role'),
'role_category_list': category_list,
'role_base_category_list': role.get('Base_Category', ''),
'role_base_category_script_id': role.get('Base_Category_Script',
role.get('Script', ''))}
portal_type.newContent(portal_type='Role Information', \
**role_dict)
## Update BT5
bt5_obj = business_configuration.getSpecialiseValue()
bt5_obj.edit(template_portal_type_roles_list=self._spreadsheet_cache.keys())
def checkSpreadSheetConsistency(self):
"""Check that the spread sheet is consistent with categories spreadsheet.
- all roles have a name ('Name' or 'Role')
- all roles have a portal type ('Name' or 'Role')
- all roles uses valid group & function categories
XXX do we want to use constraint framework here ?
"""
def _readSpreadSheet(self):
"""Read the spreadsheet and prepare internal category cache.
"""
aq_self = aq_base(self)
if getattr(aq_self, '_spreadsheet_cache', None) is None:
role_dict = dict()
info_dict = self.ConfigurationTemplate_readOOCalcFile(
'default_portal_type_roles_spreadsheet')
for sheet_name, table in self.ConfigurationTemplate_readOOCalcFile(
'default_portal_type_roles_spreadsheet').items():
for line in table:
if 'Portal_Type' in line:
ptype_role_list = role_dict.setdefault(line['Portal_Type'], [])
ptype_role_list.append(line)
aq_self._spreadsheet_cache = role_dict
security.declareProtected(Permissions.ModifyPortalContent,
'setDefaultPortalTypeRolesSpreadsheetFile')
def setDefaultPortalTypeRolesSpreadsheetFile(self, *args, **kw):
"""Reset the spreadsheet cache."""
self._setDefaultPortalTypeRolesSpreadsheetFile(*args, **kw)
self._spreadsheet_cache = None
self.reindexObject()
security.declareProtected(Permissions.ModifyPortalContent,
'setPortalTypeRolesSpreadsheetFile')
setPortalTypeRolesSpreadsheetFile = setDefaultPortalTypeRolesSpreadsheetFile
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class PreferenceConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" Setup preference. """
meta_type = 'ERP5 Preference Configurator Item'
portal_type = 'Preference Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore )
def _getPreferenceNameList(self):
"""Returns all existing preference names.
TODO: this should be done by introspecting property sheet.
"""
return ( 'preferred_category_child_item_list_method_id',
'preferred_accounting_transaction_from_date',
'preferred_accounting_transaction_at_date',
'preferred_section_category',
'preferred_section',
'preferred_accounting_transaction_section_category',
'preferred_accounting_transaction_source_section',
'preferred_accounting_transaction_currency',
'preferred_accounting_transaction_gap',
'preferred_accounting_transaction_simulation_state_list',
'preferred_text_format',
'preferred_text_editor',
'preferred_date_order',
'preferred_listbox_view_mode_line_count',
'preferred_listbox_list_mode_line_count',
'preferred_string_field_width',
'preferred_textarea_width',
'preferred_textarea_height',
'preferred_money_quantity_field_width',
'preferred_quantity_field_width',
'preferred_report_style',
'preferred_report_format',
'preferred_html_style_access_tab',
)
def build(self, business_configuration):
portal = self.getPortalObject()
organisation_id = business_configuration.\
getGlobalConfigurationAttr('organisation_id')
organisation_path = 'organisation_module/%s' % organisation_id
preference = portal.portal_preferences._getOb(self.object_id, None)
if preference is None:
preference = portal.portal_preferences.newContent(
portal_type='Preference',
id=self.object_id,
title = self.title,
description = self.description,
priority = 1)
# XXX this have to be translated in user language.
preference_dict = {}
marker = []
for preference_name in self._getPreferenceNameList():
preference_value = getattr(self, preference_name,
preference.getProperty(preference_name, marker))
if preference_value is not marker:
preference_dict[preference_name] = preference_value
preference_dict['preferred_accounting_transaction_source_section'] = \
organisation_path
preference_dict['preferred_section'] = organisation_path
preference.edit(**preference_dict)
bt5_obj = business_configuration.getSpecialiseValue()
current_template_preference_list = list(bt5_obj.getTemplatePreferenceList())
if preference.getId() not in current_template_preference_list:
current_template_preference_list.append(preference.getId())
bt5_obj.edit(template_preference_list=current_template_preference_list,)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Acquisition import aq_base
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
from zLOG import LOG, INFO
class RoleConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" Setup role per module basis. """
meta_type = 'ERP5 Role Configurator Item'
portal_type = 'Role Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore )
def build(self, business_configuration):
object_list = business_configuration.ConfigurationTemplate_readOOCalcFile(self.filename)
portal = self.getPortalObject()
portal_type_dict = {}
# we may pass some override dynamic values from outside
# Example:we post 'group_id' and in column we have it then
# it will be replaced with value if not configuration file matters
dynamic_values = dict(group_id = getattr(aq_base(self), 'group_id', None),
function_id = getattr(aq_base(self), 'function_id', None),
site_id = getattr(aq_base(self), 'site_id', None),)
for oo_module_dict in object_list:
mod_conf_list = []
portal_type = oo_module_dict.pop('portal_type')
for category, role_list_string in oo_module_dict.items():
# passed from outside (it has higher priority than configuratiohn file)
category = dynamic_values.get(category, category)
title = category.replace('/', '_')
role_name_list = [x.strip() for x in role_list_string.split(';')]
role_category_list=[category]
conf_dict = {'title': title,
'description': 'Configured by Nexedi Configurator',
'role_name_list': role_name_list,
'role_category_list': role_category_list}
mod_conf_list.append(conf_dict)
portal_type_dict[portal_type] = mod_conf_list
## Update fake site
# XXX rafael: improve this, the ignore list is quite ugly.
ignore_list = []
portal_type_id_list = portal.portal_types.objectIds()
for portal_type, role_list in portal_type_dict.items():
for role_dict in role_list:
if portal_type in portal_type_id_list:
portal.portal_types[portal_type].newContent(portal_type='Role Information', \
**role_dict)
else:
ignore_list.append(portal_type)
LOG("CONFIGURATOR", INFO, "Fail to define Roles for %s" % portal_type)
## Update BT5
bt5_obj = business_configuration.getSpecialiseValue()
# keep existing roles definition (from previous configuration saves)
for existing_type in bt5_obj.getTemplatePortalTypeRolesList():
portal_type_dict[existing_type] = 1
bt5_obj.edit(template_portal_type_roles_list=[i for i in portal_type_dict.keys() if i not in ignore_list])
##############################################################################
#
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
# Lucas Carvalho <lucas@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Acquisition import aq_base
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
from zLOG import LOG, INFO
class RuleConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" Setup Rules. """
meta_type = 'ERP5 Rule Configurator Item'
portal_type = 'Rule Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore )
def build(self, business_configuration):
portal = self.getPortalObject()
simulation_rule_dict = portal.ERPSite_getConfiguratorSimulationRuleDict()
for key, value in simulation_rule_dict.iteritems():
reference = value.get('default_reference')
result = portal.portal_rules.searchFolder(sort_on='version',
sort_order='descending',
reference=reference)
if len(result):
value['version'] = int(result[0].getVersion()) + 1
rule = portal.portal_rules.newContent(**value)
content_list = value.pop('content_list')
for content_dict in content_list:
sub_object = rule.newContent(**content_dict)
self.install(rule, business_configuration)
##############################################################################
#
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
# TAHARA Yusei <yusei@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class ServiceConfiguratorItem(ConfiguratorItemMixin, XMLObject):
"""Create default service documents."""
meta_type = 'ERP5 Service Configurator Item'
portal_type = 'Service Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.ServiceConfiguratorItem )
def build(self, business_configuration):
portal = self.getPortalObject()
module = portal.service_module
for service_id, service_title in self.getServiceList():
# XXX FIXME We cannot define service_id like this,
# because it cause conflict when configurator is
# used twice.
document = module.newContent(portal_type='Service',
#id=service_id,
title=service_title,
)
## add to customer template
self.install(document, business_configuration)
##############################################################################
#
# Copyright (c) 2008 Nexedi SARL and Contributors. All Rights Reserved.
# Yoshinori Okuji <yo@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class SitePropertyConfiguratorItem(ConfiguratorItemMixin, XMLObject):
"""Set up site properties."""
meta_type = 'ERP5 Site Property Configurator Item'
portal_type = 'Site Property Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.SitePropertyConfiguratorItem )
def build(self, business_configuration):
portal = self.getPortalObject()
id_list = []
for id, value, prop_type in self.getSitePropertyList():
if portal.hasProperty(id):
portal._delProperty(id)
portal._setProperty(id, value, type=prop_type)
id_list.append(id)
bt = business_configuration.getSpecialiseValue()
bt.edit(template_site_property_id_list=id_list)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Products.CMFCore.utils import getToolByName
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
import transaction
class StandardBT5ConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" This class will install standard ERP5 template from a repository to
fake site. """
meta_type = 'ERP5 Standard BT5 Configurator Item'
portal_type = 'Standard BT5 Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.StandardBT5ConfiguratorItem
)
def build(self, business_configuration):
bt5_id = self.getBt5Id()
bt5_copy_id = '%s_copy' % bt5_id
portal = self.getPortalObject()
template_tool = getToolByName(portal, 'portal_templates')
## Is this standard template already gzipped?
filename_bt5_id = '%s.bt5' % bt5_id
if business_configuration.isStandardBT5(filename_bt5_id):
bt_url = business_configuration.getPublicUrlForBT5Id(filename_bt5_id)
business_configuration.newContent(portal_type='Link',
url_string = bt_url, title = filename_bt5_id)
else:
## we need to make a copy of template to be able to export it
if not bt5_copy_id in template_tool.objectIds():
bt5 = template_tool.getInstalledBusinessTemplate(bt5_id)
template_copy = template_tool.manage_copyObjects(ids=(bt5.getId(),))
new_id_list = template_tool.manage_pasteObjects(template_copy)
new_bt5_id = new_id_list[0]['new_id']
template_tool.manage_renameObject(new_bt5_id, bt5_copy_id)
## we are sure that we have this business template
self._current_bt_id = bt5_copy_id
return self.get_it_built(business_configuration)
def get_it_built(self, business_configuration):
portal = self.getPortalObject()
template_tool = getToolByName(portal, 'portal_templates')
bt5_obj = self._getCurrentBT(business_configuration)
if bt5_obj.getBuildingState() != 'built':
## build template so it can be exported
bt5_obj.edit()
bt5_obj.build()
# XXX Due a bug into Business Templates it is not possible build
# the business template and export when this have one
# ActionTemplateItem. This is a TEMPORARY CHANGE and it should be
# removed as soon as Business Template is FIXED.
transaction.savepoint(optimistic=True)
bt5_data = template_tool.export(bt5_obj)
business_configuration.newContent(portal_type='File',
title = '%s.bt5' % bt5_obj.getId(),
data = bt5_data)
def _getCurrentBT(self, business_configuration):
""" Return current bt5 file. """
portal = self.getPortalObject()
template_tool = portal.portal_templates
bt5_id = self._current_bt_id
bt5_obj = portal.portal_templates[bt5_id]
return bt5_obj
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class SystemPreferenceConfiguratorItem(ConfiguratorItemMixin, XMLObject):
"""
Setup system preference.
"""
meta_type = 'ERP5 System Preference Configurator Item'
portal_type = 'System Preference Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore )
def _getPreferenceNameList(self):
"""Returns all existing preference names.
TODO: this should be done by introspecting property sheet.
"""
return ( # CRM
'preferred_campaign_resource_list',
'preferred_event_assessment_form_id_list',
'preferred_event_resource_list',
'preferred_event_sender_email',
'preferred_meeting_resource_list',
'preferred_sale_opportunity_resource_list',
'preferred_support_request_resource_list',
# DMS
'preferred_ooodoc_server_address',
'preferred_ooodoc_server_port_number',
'preferred_conversion_cache_factory',
'preferred_document_email_ingestion_address',
'preferred_document_reference_method_id',
'preferred_document_file_name_regular_expression',
'preferred_document_reference_regular_expression',
'preferred_document_classification',
'preferred_synchronous_metadata_discovery',
'preferred_redirect_to_document',
# PDM
'preferred_product_individual_variation_base_category_list',
'preferred_component_individual_variation_base_category_list',
'preferred_service_individual_variation_base_category_list',
# Trade
'preferred_supplier_role_list',
'preferred_client_role_list',
'preferred_sale_use_list',
'preferred_purchase_use_list',
'preferred_packing_use_list',
# Express
)
def build(self, business_configuration):
portal = self.getPortalObject()
preference = portal.portal_preferences._getOb(self.object_id, None)
if preference is None:
preference = portal.portal_preferences.newContent(
portal_type = 'System Preference',
id = self.object_id,
title = self.title,
description = self.description,
priority = 1)
# XXX this have to be translated in user language.
preference_dict = {}
marker = []
for preference_name in self._getPreferenceNameList():
preference_value = getattr(self, preference_name,
preference.getProperty(preference_name, marker))
if preference_value is not marker:
preference_dict[preference_name] = preference_value
preference.edit(**preference_dict)
bt5_obj = business_configuration.getSpecialiseValue()
current_template_preference_list = list(bt5_obj.getTemplatePreferenceList())
if preference.getId() not in current_template_preference_list:
current_template_preference_list.append(preference.getId())
bt5_obj.edit(template_preference_list=current_template_preference_list,)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Configurator.mixin.configurator_item import ConfiguratorItemMixin
class WorkflowSecurityConfiguratorItem(ConfiguratorItemMixin, XMLObject):
""" Setup workflow for different roles. Use passed OO file. """
meta_type = 'ERP5 Workflow Security Configurator Item'
portal_type = 'Workflow Security Configurator Item'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore )
def build(self, business_configuration):
## NOT TESTED
return
table_dict = business_configuration.ConfigurationTemplate_readOOCalcFile(self.filename)
portal = self.getPortalObject()
suffix = '_security'
suffix_len = len(suffix)
if self.filename[-suffix_len:] == suffix:
workflow_id = self.filename[:-suffix_len]
else:
raise "NoValidName"
# Configure state permission
view_permission_list = ['View']
access_permission_list = ['Access contents information']
modify_permission_list = ['Modify portal content']
add_content_permission_list = ['Add portal content']
# Configure list of variable on the workflow
permission_list = view_permission_list + \
access_permission_list + \
modify_permission_list + \
add_content_permission_list
# Remove permission list
workflow = portal.portal_workflow[workflow_id]
workflow.delManagedPermissions(workflow.permissions)
# Add new permission list
for permission in permission_list:
workflow.addManagedPermission(permission)
# Configure state permission matrix
state_list = table_dict['state']
for state_config in state_list:
state_id = state_config.pop('state')
state = workflow.states[state_id]
# Clean the state matrix
for permission in permission_list:
state.setPermission(permission, 0, [])
# Update state matrix
permission_dict = dict([(x, []) for x in permission_list])
for role, perm_symbol in state_config.items():
managed_permission_list = []
if 'A' in perm_symbol:
managed_permission_list.extend(access_permission_list)
if 'V' in perm_symbol:
managed_permission_list.extend(view_permission_list)
if 'C' in perm_symbol:
managed_permission_list.extend(add_content_permission_list)
if 'M' in perm_symbol:
managed_permission_list.extend(modify_permission_list)
for permission in managed_permission_list:
permission_dict[permission].append(role.capitalize())
for permission, roles in permission_dict.items():
state.setPermission(permission, 0, roles)
# XXX To be deleted
# for permission in permission_list:
# module.manage_permission(permission, ['Manager'], 0)
# Configure transition guard
transition_list = table_dict['transition']
for transition_conf in transition_list:
transition_id = transition_conf.pop('transition')
transition = workflow.transitions[transition_id]
guard = transition.getGuard()
role_list = [x.capitalize() for x in transition_conf.keys()]
role_string = ';'.join(role_list)
guard.changeFromProperties({'guard_roles': role_string})
# Update business template
bt5_obj = business_configuration.getSpecialiseValue()
template_workflow_id_list = list(bt5_obj.getTemplateWorkflowIdList())
if workflow_id not in template_workflow_id_list:
template_workflow_id_list.append(workflow_id)
bt5_obj.edit(template_workflow_id_list=template_workflow_id_list,)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import StringIO
def read(self, filename):
"""
Return a OOCalc as a StringIO
"""
oo_template_file = getattr(self, filename)
fp = StringIO.StringIO(oo_template_file)
fp.filename = filename
return fp
def getIdFromString(string):
"""
This function transform a string to a safe id.
It is used here to create a safe category id from a string.
"""
if string is None:
return None
clean_id = ''
translation_map = { "a": ['\xe0']
, "e": ['\xe9', '\xe8']
}
#string = string.lower()
string = string.strip()
# oocalc inserts some strange chars when you press - key in a text cell.
# Following line is a workaround for this,
# because \u2013 does not exist in latin1
string = string.replace(u'\u2013', '-')
for char in string.encode('utf-8'):#('iso8859_1'):
if char == '_' or char.isalnum():
clean_id += char
elif char.isspace() or char in ('+', '-'):
clean_id += '_'
else:
for (safe_char, char_list) in translation_map.items():
if char in char_list:
clean_id += safe_char
break
return clean_id
def convert(self, filename):
from Products.ERP5OOo.OOoUtils import OOoParser
OOoParser = OOoParser()
import_file = read(self, filename)
# Extract tables from the speadsheet file
OOoParser.openFile(import_file)
filename = OOoParser.getFilename()
spreadsheets = OOoParser.getSpreadsheetsMapping()
table_dict = {}
for table_name, table in spreadsheets.items():
if not table:
continue
# Get the header of the table
columns_header = table[0]
# Get the mapping to help us to know the property according a cell index
property_map = {}
column_index = 0
for column in columns_header:
column_id = getIdFromString(column)
# The column has no header information
# The column has a normal header
property_map[column_index] = column_id
column_index += 1
# Construct categories data (with absolut path) from table lines
object_list = []
for line in table[1:]:
object_property_dict = {}
# Exclude empty lines
if line.count('') + line.count(None) == len(line):
continue
# Analyse every cells of the line
cell_index = 0
for cell in line:
# Ignore empty cells, do the test on the generated id
# because getIdFromString() is more restrictive
cell_id = getIdFromString(cell)
if cell_id not in ('', None):
# Get the property corresponding to the cell data
property_id = property_map[cell_index]
# Convert the value to something like '\xc3\xa9' not '\xc3\xa9'
object_property_dict[property_id] = cell.encode('UTF-8')
cell_index += 1
if len(object_property_dict) > 0:
object_list.append(object_property_dict)
table_dict[table_name.encode('UTF-8')] = object_list
if len(table_dict.keys()) == 1:
return object_list
else:
return table_dict
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class BusinessConfiguration:
"""
Properties of a Business Configuration.
"""
_properties = (
{ 'id' : 'configuration_after_script_id',
'description' : 'Defines the Id of the script to be ran after'
'the configuration.',
'type' : 'string',
'default' : 'BusinessConfiguration_afterConfiguration',
'mode' : 'w' },
)
_categories = ("current_state", "resource", "specialise")
##############################################################################
#
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class CategoriesSpreadsheetConfiguratorItem:
""" Properties of a CategoriesSpreadsheetConfiguratorItem."""
_properties = (
{ 'id' : 'categories_spreadsheet',
'storage_id' : 'default_categories_spreadsheet',
'description' : 'A spreadsheet with categories definition',
'type' : 'content',
# XXX maybe it can just be a File, so that we don't have to depend on DMS
'portal_type' : ('Spreadsheet',),
'acquired_property_id' : ('file', 'content_type', 'data'),
'acquisition_base_category' : (),
'acquisition_portal_type' : (),
'acquisition_copy_value' : 0,
'acquisition_mask_value' : 1,
'acquisition_sync_value' : 0,
'acquisition_accessor_id' : 'getDefaultCategoriesSpreadsheetValue',
'acquisition_depends' : None,
'mode' : 'w' },
)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class ConfigurationItem:
""" Properties of a Configuration Item."""
_properties = ({'id' : 'configuration_class_name',
'description' : 'Configuration class name',
'type' : 'string',
'mode' : 'w',
'default' : '' },
)
##############################################################################
#
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class PortalTypeRolesSpreadsheetConfiguratorItem:
""" Properties of a PortalTypeRolesSpreadsheetConfiguratorItem."""
_properties = (
{ 'id' : 'portal_type_roles_spreadsheet',
'storage_id' : 'default_portal_type_roles_spreadsheet',
'description' : 'The spreadsheet for portal type roles configuration',
'type' : 'content',
'portal_type' : ('Spreadsheet',),
'acquired_property_id' : ('file', 'content_type', 'data'),
'acquisition_base_category' : (),
'acquisition_portal_type' : (),
'acquisition_copy_value' : 0,
'acquisition_mask_value' : 1,
'acquisition_sync_value' : 0,
'acquisition_accessor_id' : 'getDefaultPortalTypeRolesSpreadsheetValue',
'acquisition_depends' : None,
'mode' : 'w' },
)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class ServiceConfiguratorItem:
""" Properties of a ServiceConfiguratorItem."""
_properties = ({'id' : 'service',
'description' : 'Services',
'type' : 'lines',
'mode' : 'w',
'default' : []},
)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class SitePropertyConfiguratorItem:
""" Site Properties Configurator Item."""
_properties = ({'id' : 'site_property_list',
'description' : 'Site Property List',
'type' : 'lines',
'mode' : 'w',
'default' : []},)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class StandardBT5ConfiguratorItem:
""" Properties of a ReturnStandardBT5ConfiguratorItem."""
_properties = ({'id' : 'bt5_id',
'description' : 'Business Template ID',
'type' : 'string',
'mode' : 'w',
'default' : 'erp5_base' },
)
##############################################################################
#
# Copyright (c) 2006-2010 Nexedi SA and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
# Ivan Tyagov <ivan@nexedi.com>
# Rafael Monnerat <rafael@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Globals import DTMLFile
from Products.ERP5Type.Accessor.Constant import PropertyGetter as \
ConstantGetter
from Products.ERP5Type.Tool.BaseTool import BaseTool
from Products.ERP5Type import Permissions
from Products.ERP5Configurator import _dtmldir
from Products.CMFCore.utils import getToolByName
from Products.Formulator.Errors import FormValidationError
import cookielib
from base64 import encodestring
from urllib import quote
from DateTime import DateTime
# global (RAM) cookie storage
cookiejar = cookielib.CookieJar()
last_loggedin_user_and_password = None
referer = None
installation_status = {'bt5': {'current': 0,
'all': 0,},
'activity_list': [],}
# cookie name to store user's preferred language name
LANGUAGE_COOKIE_NAME = 'configurator_user_preferred_language'
BUSINESS_CONFIGURATION_COOKIE_NAME = 'business_configuration_key'
def getAvailableLanguageFromHttpAcceptLanguage(http_accept_language,
available_language_list,
default='en'):
for language_set in http_accept_language.split(','):
language_tag = language_set.split(';')[0]
language = language_tag.split('-')[0]
if language in available_language_list:
return language
return default
def _isUserAcknowledged(cookiejar):
""" Is user authenticated to remote system through a cookie. """
for cookie in cookiejar:
if cookie.name == '__ac' and cookie.value != '':
return 1
return 0
def _validateFormToRequest(form, REQUEST, **kw):
""" Validate form to REQUEST. """
form_kw = {}
REQUEST.form = kw
try:
form.validate_all_to_request(REQUEST)
validation_status = 0
validation_errors = None
except FormValidationError, validation_errors:
## not all fields valid
validation_status = 1
except Exception, validation_errors:
## missing fields
validation_status = 2
## extract form arguments and remove leading prefixes
if validation_status==0:
for field in form.get_fields():
field_id = field.id
value = getattr(REQUEST, field_id, None)
for prefix in ('my_', 'your_',):
if field_id.startswith(prefix):
attr_id = field_id[len(prefix):]
form_kw[attr_id] = value
for del_key in (field.generate_field_key(validation=1), field_id):
try:
REQUEST.other.pop(del_key)
except KeyError:
pass
return validation_status, form_kw, validation_errors
class ConfiguratorTool(BaseTool):
"""
This tool provides a Configurator Tool.
"""
id = 'portal_configurator'
title = 'Configurator Tool'
meta_type = 'ERP5 Configurator Tool'
portal_type = 'Configurator Tool'
isPortalContent = ConstantGetter('isPortalContent', value=True)
security = ClassSecurityInfo()
security.declareProtected(Permissions.ManagePortal, 'manage_overview')
manage_overview = DTMLFile('explainConfiguratorTool', _dtmldir )
def getConfiguratorUserPreferredLanguage(self):
""" Get configuration language as selected by user """
REQUEST = getattr(self, 'REQUEST', None)
configurator_user_preferred_language = None
if REQUEST is not None:
# language value will be in cookie or REQUEST itself.
configurator_user_preferred_language = REQUEST.get(LANGUAGE_COOKIE_NAME,
None)
if configurator_user_preferred_language is None:
# Find a preferred language from HTTP_ACCEPT_LANGUAGE
available_language_list = [i[1] for i in self\
.ConfiguratorTool_getConfigurationLanguageList()]
configurator_user_preferred_language = \
getAvailableLanguageFromHttpAcceptLanguage(
REQUEST.get('HTTP_ACCEPT_LANGUAGE', 'en'),
available_language_list)
if configurator_user_preferred_language is None:
configurator_user_preferred_language = 'en'
return configurator_user_preferred_language
######################################################
## Navigation ##
######################################################
def login(self, REQUEST):
""" Login client and show next form. """
password = REQUEST.get('field_my_ac_key', '')
if self._isCorrectConfigurationKey(password):
# set user preferred configuration language
user_preferred_language = REQUEST.get(
'field_my_user_preferred_language', None)
if user_preferred_language:
# Set language value to request so that next page after login
# can get the value. Because cookie value is available from
# next request.
REQUEST.set(LANGUAGE_COOKIE_NAME, user_preferred_language)
REQUEST.RESPONSE.setCookie(LANGUAGE_COOKIE_NAME,
user_preferred_language,
path='/',
expires=(DateTime()+30).rfc822())
# set encoded __ac_key cookie at client's browser
__ac_key = quote(encodestring(password))
expires = (DateTime() + 1).toZone('GMT').rfc822()
REQUEST.RESPONSE.setCookie('__ac_key',
__ac_key,
expires = expires)
REQUEST.set('__ac_key', __ac_key)
bc = REQUEST.get('field_your_business_configuration')
REQUEST.RESPONSE.setCookie(BUSINESS_CONFIGURATION_COOKIE_NAME,
bc,
expires = expires)
REQUEST.set(BUSINESS_CONFIGURATION_COOKIE_NAME, bc)
return self.next(REQUEST=REQUEST)
else:
REQUEST.set('portal_status_message',
self.Base_translateString('Incorrect Configuration Key'))
return self.view()
def _isCorrectConfigurationKey(self, password=None):
""" Is configuration key correct """
if password is None:
password = self.REQUEST.get('__ac_key', None)
# Not still not finished yet.
return 1
#security.declareProtected(Permissions.ModifyPortalContent, 'next')
def next(self, REQUEST):
""" Validate settings and return a new form to the user. """
# check if user is allowed to access service
portal = self.getPortalObject()
if not self._isCorrectConfigurationKey():
REQUEST.set('portal_status_message',
self.Base_translateString('Incorrect Configuration Key'))
return self.view()
kw = self.REQUEST.form.copy()
business_configuration = REQUEST.get(BUSINESS_CONFIGURATION_COOKIE_NAME)
bc = portal.restrictedTraverse(business_configuration)
if bc is None:
REQUEST.set('portal_status_message',
self.Base_translateString(
'You cannot Continue. Unable to find your Business Configuration.'))
return self.view()
response = self._next(business_configuration=bc,kw=kw)
## Parse server response
command = response["command"]
if command == "show":
return self.ConfiguratorTool_dialogForm(previous=response['previous'],
form_html=response["data"],
next = response['next'])
elif command == "install":
return self.startInstallation(bc, REQUEST=REQUEST)
def _next(self, business_configuration, kw):
""" Return next configuration form and validate previous. """
form_kw = {}
need_validation = 1
validation_errors = None
response = {}
portal = self.getPortalObject()
## initial state no previous form to validate
if business_configuration.isInitialConfigurationState():
need_validation = 0
## client can not go further hist business configuration is already built
if business_configuration.isEndConfigurationState() or \
business_configuration.getNextTransition() == None:
return self._terminateConfigurationProcess(response,
'no_available_transitions')
isMultiEntryTransition = business_configuration._isMultiEntryTransition()
## validate multiple forms
if isMultiEntryTransition:
html_forms = []
failed_forms_counter = 0
transition = business_configuration.getNextTransition()
form = getattr(business_configuration, transition.getTransitionFormId())
for form_key in filter(lambda x: x.startswith('field_'), kw.keys()):
form_kw[form_key] = kw[form_key]
## iterate all forms
for form_counter in range(0, isMultiEntryTransition):
single_form_kw = {}
for key,value in form_kw.items():
if isinstance(value, list) or isinstance(value, tuple):
## we have more than one form shown
single_form_kw[key] = value[form_counter]
# save original value in request in some cases of multiple forms
# we need it for validation
single_form_kw['_original_%s' %key] = value
else:
## even though we have multiple entry transition customer wants
## ONE form!
single_form_kw[key] = value
## update properly REQUEST with current form data
for key,value in single_form_kw.items():
self.REQUEST.set(key, value)
## get validation status
validation_status, dummy, validation_errors = \
business_configuration._validateNextForm(**single_form_kw)
## clean up REQUEST from traces from validate_all_to_request
## otherwise next form will use previous forms details
cleanup_keys = filter(lambda x: x.startswith('my_') or
x.startswith('your_'),
self.REQUEST.other.keys())
for key in cleanup_keys:
self.REQUEST.other.pop(key, None)
## render HTML code
if validation_status != 0:
failed_forms_counter += 1
## XXX: form can fail because a new
## http://localhost:9080/erp5/portal_wizard/next is issued
## without arguments. Improve this
try:
self.REQUEST.set('field_errors',
form.ErrorFields(validation_errors))
except:
pass
single_form_html = form()
self.REQUEST.other.pop('field_errors', None)
self.REQUEST.form = {}
else:
single_form_html = form()
## wrap in form template
single_form_html = self.Base_mainConfiguratorFormTemplate(
current_form_number = form_counter +1,
max_form_numbers = isMultiEntryTransition,
form_html = single_form_html)
## add to list of forms as html code
html_forms.append(single_form_html)
## return if failure
if failed_forms_counter > 0:
next_state = self.restrictedTraverse(business_configuration.getNextTransition()\
.getDestination())
html_data = self.Base_mainConfiguratorTemplate(
form_html = "\n".join(html_forms),
current_state = next_state,
business_configuration = business_configuration)
response.update(command = "show",
previous = self.Base_translateString("Previous"),
next = self.Base_translateString(transition.getTitle()),
data = html_data)
return response
## show next form in transitions
rendered = False
while rendered is False:
if need_validation == 1:
if isMultiEntryTransition:
## multiple forms must be validated before
validation_status = 0
else:
validation_status, form_kw, validation_errors = \
business_configuration._validateNextForm(**kw)
if validation_status==1:
need_validation = 0
elif validation_status==2:
rendered = True
need_validation = 0
if business_configuration.getNextTransition() == None:
### client can not continue at the momen
return self._terminateConfigurationProcess(response,
reason='no_available_transitions')
response["previous"], html, form_title, response["next"], \
response['server_buffer'] = business_configuration._displayNextForm()
else:
## validation passed
need_validation = 0
business_configuration._executeTransition(form_kw=form_kw, request_kw=kw)
elif need_validation == 0:
if business_configuration.getNextTransition() == None:
return self._terminateConfigurationProcess(response,
'no_available_transitions')
## validation failure
rendered = True
response["previous"], html, form_title, response["next"], \
response['server_buffer'] = business_configuration.\
_displayNextForm(validation_errors=validation_errors)
if html is None:
## we have no more forms proceed to build
response.update(command = "install", data = None)
else:
## we have more forms
next_state = self.restrictedTraverse(business_configuration.getNextTransition()\
.getDestination())
html_data = self.Base_mainConfiguratorTemplate(
form_html = html,
current_state = next_state,
business_configuration = business_configuration)
response.update(command = "show", data = html_data)
return response
def _terminateConfigurationProcess(self, response, reason=''):
""" Terminate process and return some explanations to client why
he can no longer continue. """
if reason == 'no_available_transitions':
form_html = self.BusinessConfiguration_viewStopForm()
response.update(command = "show", next = None, \
previous = None, data = form_html)
elif reason == 'authentification_failure':
form_html = self.BusinessConfiguration_viewUnauthenticatedForm()
response.update(command = "show", data = form_html,
next = None, previous = None,)
return response
#security.declareProtected(Permissions.ModifyPortalContent, 'previous')
def previous(self, REQUEST):
""" Display the previous form. """
# check if user is allowed to access service
portal = self.getPortalObject()
if not self._isCorrectConfigurationKey():
REQUEST.set('portal_status_message',
self.Base_translateString('Incorrect Configuration Key'))
return self.view()
kw = self.REQUEST.form.copy()
business_configuration = REQUEST.get(BUSINESS_CONFIGURATION_COOKIE_NAME)
bc = portal.restrictedTraverse(business_configuration)
response = self._previous(business_configuration=bc, kw=kw)
return self.ConfiguratorTool_dialogForm(previous=response['previous'],
form_html=response['data'],
next=response['next'])
def _previous(self, business_configuration, kw):
""" Returns previous form. """
response = {}
## is client is not allowed access ?
if business_configuration is None:
form_html = self.BusinessConfiguration_viewUnauthenticatedForm()
return self.ConfiguratorTool_dialogForm(form_html = form_html)
## client can not go further his business configuration is already built
if business_configuration.isEndConfigurationState():
form_html = self.BusinessConfiguration_viewStopForm()
return self.ConfiguratorTool_dialogForm(form_html = form_html,
next = "Next")
response['previous'], form_html, form_title, response['next'], server_buffer = \
business_configuration._displayPreviousForm()
next_state = self.restrictedTraverse(
business_configuration.getNextTransition().getDestination())
response['data'] = self.Base_mainConfiguratorTemplate(
form_html = form_html,
current_state = next_state,
business_configuration = business_configuration)
return response
security.declarePublic(Permissions.AccessContentsInformation,
'getInstallationStatusReport')
def getInstallationStatusReport(self,
active_process_id=None, REQUEST=None):
""" Query local ERP5 instance for installation status.
If installation is over the installation activities and reindexing
activities should not exists.
"""
global installation_status
portal_activities = getToolByName(self.getPortalObject(),
'portal_activities')
is_bt5_installation_over = (portal_activities.countMessageWithTag(
'initialERP5Setup')==0)
if 0 == len(portal_activities.getMessageList()) and \
is_bt5_installation_over:
html = self.ConfiguratorTool_viewSuccessfulConfigurationMessageRenderer()
else:
if is_bt5_installation_over:
# only if bt5s are installed start tracking number of activities
activity_list = portal_activities.getMessageList()
installation_status['activity_list'].append(len(activity_list))
html = self.ConfiguratorTool_viewRunningInstallationMessage(
installation_status = installation_status)
# set encoding as this is usually called from asynchronous JavaScript call
self.REQUEST.RESPONSE.setHeader('Content-Type',
'text/html; charset=utf-8')
return html
security.declareProtected(Permissions.ModifyPortalContent, 'startInstallation')
def startInstallation(self, business_configuration, REQUEST):
""" Start installation process as an activity which will query generation
server and download/install bt5 template files and meanwhile offer
user a nice GUI to observe what's happening. """
global installation_status
# init installation status
bt5_file_list = len(business_configuration.contentValues(
portal_types=["File", "Link"])) or 1
installation_status['bt5']['all'] = bt5_file_list
installation_status['bt5']['current'] = 0
installation_status['activity_list'] = []
active_process = self.portal_activities.newActiveProcess()
REQUEST.set('active_process_id', active_process.getId())
request_restore_dict = {'__ac_key': REQUEST.get('__ac_key',
None),}
self.activate(active_process=active_process, tag = 'initialERP5Setup'
).initialERP5Setup(business_configuration.getRelativeUrl(), request_restore_dict)
return self.ConfiguratorTool_viewInstallationStatus(REQUEST)
security.declareProtected(Permissions.ModifyPortalContent,
'initialERP5Setup')
def initialERP5Setup(self, business_configuration, request_restore_dict={}):
""" Get from remote generation server customized bt5 template files
and then install them. """
# restore some REQUEST variables as this method is executed in an activity
# and there's no access to real original REQUEST
for key, value in request_restore_dict.items():
self.REQUEST.set(key, value)
bc = self.restrictedTraverse(business_configuration)
# XXX FIXME we just have to build once.
bc.build()
bc.install()
finalize_method = getattr(self, 'ConfiguratorTool_finalizeInstallation', None)
if finalize_method is not None and callable(finalize_method):
finalize_method(business_configuration = bc,
**request_restore_dict)
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
"""
ERP5Configurator is a product containing everything needed to the
configurator.
"""
# Update ERP5 Globals
from Products.ERP5Type.Utils import initializeProduct, updateGlobals
import sys, Permissions
this_module = sys.modules[ __name__ ]
document_classes = updateGlobals(this_module, globals(),
permissions_module=Permissions)
from Tool import ConfiguratorTool
# Define object classes and tools
object_classes = ()
portal_tools = (ConfiguratorTool.ConfiguratorTool,
)
content_classes = ()
content_constructors = ()
# Finish installation
def initialize(context):
import Document
initializeProduct(context, this_module, globals(),
document_module=Document,
document_classes=document_classes,
object_classes=object_classes,
portal_tools=portal_tools,
content_constructors=content_constructors,
content_classes=content_classes)
##############################################################################
#
# Copyright (c) 2010 Nexedi SARL and Contributors. All Rights Reserved.
# Rafael Monnerat <rafael@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from zope.interface import Interface
class IConfiguratorItem(Interface):
"""
Configurator Item interface specification.
Documents which implement the IConfiguratorItem interface
can be used to build an ERP5 Configuration.
"""
def build(business_configuration):
"""
Build new ERP5 Documents based on stored parameters during
the configuraton process.
business_configuration - Business Configuration Document that is
been used to configure.
"""
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class ConfiguratorItemMixin:
""" This is the base class for all configurator item. """
def install(self, object, business_configuration, prefix = ''):
""" Add object to customer customization template. """
bt5_obj = business_configuration.getSpecialiseValue()
if object.getPortalType() in ['Category', 'Base Category']:
prefix = "portal_categories/"
template_path_list = ['%s%s' % (prefix, object.getRelativeUrl()),
'%s%s/**' % (prefix, object.getRelativeUrl())]
current_template_path_list = list(bt5_obj.getTemplatePathList())
current_template_path_list.extend(template_path_list)
bt5_obj.edit(template_path_list=current_template_path_list)
def addToCustomerBT5ByRelativeUrl(self, business_configuration, relative_url_list):
""" Add object to customer customization template object by its relative url. """
bt5_obj = business_configuration.getSpecialiseValue()
current_template_path_list = list(bt5_obj.getTemplatePathList())
current_template_path_list.extend(relative_url_list)
bt5_obj.edit(template_path_list=current_template_path_list)
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