Commit 930d95bf authored by Ivan Tyagov's avatar Ivan Tyagov

Merge branch 'master' into ivan

parents 2bec02b9 b04eeadf
Changes
=======
0.4.5 (2012-07-04)
------------------
* erp5.util.taskdistribution:
- xmlrpclib does not support named parameters, use positional ones
[Vincent Pelletier]
0.4.4 (2012-07-04)
------------------
* erp5.util.taskdistribution:
- New module [Vincent Pelletier]
0.4.3 (2012-04-24)
----------------
......
......@@ -58,7 +58,11 @@ preferred_forum_quote_original_message= portal.ERP5Site_getUserPreferredForumSet
if discussion_post_uid is not None:\n
# set title & text_content\n
discussion_post = getattr(context, discussion_post_uid)\n
title = \'Re: %s\' %discussion_post.getTitle()\n
\n
title = discussion_post.getTitle()\n
if not title.lower().startswith(\'re:\'):\n
# stop exploding "Re: Re: .." to one level\n
title = \'Re: %s\' %title\n
context.REQUEST.set(\'discussion_post_title\', title)\n
if preferred_forum_quote_original_message:\n
author_dict = discussion_post.DiscussionPost_getAuthorDict()\n
......
......@@ -50,7 +50,9 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>"""\n
<value> <string encoding="cdata"><![CDATA[
"""\n
This script allows to create a new Discussion Thread.\n
"""\n
MARKER = [\'\', None, []]\n
......@@ -70,9 +72,9 @@ if site_list in MARKER:\n
membership_criterion_category_list = context.getMembershipCriterionCategoryList()\n
multimembership_criterion_base_category_list = context.getMultimembershipCriterionBaseCategoryList()\n
\n
reference = title.replace(\' \', \'-\')\n
exisiting_document = context.getDocumentValue(reference)\n
if exisiting_document is not None:\n
reference = title.replace(\' \', \'-\').replace(\'?\', \'\').replace(\':\', \'\').replace(\'/\', \'\').replace(\'&\', \'\').replace(\'=\', \'\')\n
existing_document = context.getDocumentValue(reference)\n
if existing_document is not None:\n
# if there are other document which reference duplicates just add some random part\n
# so we can distinguish)\n
reference = \'%s-%s\' %(context.Base_generateRandomString(), reference)\n
......@@ -152,7 +154,9 @@ if send_notification_text not in (\'\', None):\n
\n
return context.Base_redirect(form_id,\n
keep_items = dict(portal_status_message=context.Base_translateString(portal_status_message)))\n
</string> </value>
]]></string> </value>
</item>
<item>
<key> <string>_params</string> </key>
......
110
\ No newline at end of file
115
\ No newline at end of file
......@@ -66,7 +66,7 @@ if address not in MARKER and port not in MARKER:\n
# we need a way to do this by introspection\n
if ((getattr(document, "getData", None) is not None and document.getData() not in MARKER) or \\\n
(getattr(document, "getBaseData", None) is not None and document.getBaseData() not in MARKER)):\n
document.activate(tag="conversion").Base_callPreConvert()\n
document.activate(priority=4, tag="conversion").Base_callPreConvert()\n
</string> </value>
</item>
<item>
......
17
\ No newline at end of file
18
\ No newline at end of file
......@@ -1340,6 +1340,12 @@ button.formbt > span{\n
.full-width{\n
width:100%;\n
}\n
\n
/* discussions */\n
.discussion-post-body-container a{\n
color:#686868;\n
text-decoration: underline;\n
}\n
</tal:block>
]]></unicode> </value>
......
1868
\ No newline at end of file
1869
\ No newline at end of file
......@@ -56,6 +56,7 @@
tal:define="box python: getattr(here, box_id);\n
box_relative_url box/getRelativeUrl;\n
box_dom_id python: \'%s\' %box_relative_url.replace(\'/\', \'_\');\n
box_class python: (\'%s %s\' % (\'block\', box.getGroup() or \'\')).strip;\n
view_form_dom_id python: \'%s_content\' %box_dom_id;\n
edit_form_dom_id python: \'%s_edit_form\' %box_dom_id;\n
gadget_title_dom_id python: \'%s_gadget_title\' %box_dom_id;\n
......@@ -71,13 +72,15 @@
\n
<!-- Render gadget as hidden one -->\n
<div tal:condition="not: is_gadget_visible"\n
tal:attributes="id box_dom_id"\n
tal:attributes="id box_dom_id;\n
class box_class"\n
class="block invisible-gadget"></div>\n
\n
<!-- Show only public gadgets -->\n
<div class="block" \n
tal:condition="is_gadget_visible"\n
tal:attributes="id box_dom_id">\n
tal:attributes="id box_dom_id;\n
class box_class">\n
\n
<h3 class="handle">\n
<span class="handle">\n
......
2012-06-25 Kazuhiko
* add knowledge pad's group in gadget title div class.
2011-09-26 Kazuhiko
* ERP5Site_getKnowledgePadListForUser should handle Unauthorized exception.
......
748
\ No newline at end of file
749
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>10.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>View</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/PaypalService_view</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
# François-Xavier Algrain <fxalgrain@tiolive.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 zope
from urllib import urlencode
from urllib2 import urlopen, Request
from zLOG import LOG, DEBUG
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.Document import newTempDocument
class PaypalService(XMLObject):
"""Paypal Service for payment"""
meta_type = 'Paypal Service'
portal_type = 'Paypal Service'
security = ClassSecurityInfo()
zope.interface.implements(interfaces.IPaymentService)
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = (PropertySheet.Base,
PropertySheet.XMLObject,
PropertySheet.Reference
)
def initialize(self, REQUEST=None, **kw):
"""See Payment Service Interface Documentation"""
def _getFieldList(self, paypal_dict):
field_list = []
for k,v in paypal_dict.iteritems():
field_list.append((k, v))
return field_list
def navigate(self, REQUEST=None, **kw):
"""See Payment Service Interface Documentation"""
self.Base_checkConsistency()
page_template = kw.pop("page_template")
paypal_dict = kw.get("paypal_dict", {})
temp_document = newTempDocument(self, 'id')
temp_document.edit(
link_url_string=self.getLinkUrlString(),
title=self.getTitle(),
field_list=self._getFieldList(paypal_dict),
# append the rest of transmitted parameters page template
**kw
)
return getattr(temp_document, page_template)()
def notifySuccess(self, redirect_path=None, REQUEST=None):
"""See Payment Service Interface Documentation"""
return self._getTypeBasedMethod("acceptPayment")(redirect_path=redirect_path)
def notifyFail(self, redirect_path=None, REQUEST=None):
"""See Payment Service Interface Documentation"""
return self._getTypeBasedMethod("failInPayment")(redirect_path=redirect_path)
def notifyCancel(self, redirect_path=None, REQUEST=None):
"""See Payment Service Interface Documentation"""
return self._getTypeBasedMethod("abortPayment")(redirect_path=redirect_path)
def reportPaymentStatus(self, REQUEST=None):
"""See Payment Service Interface Documentation"""
param_dict = REQUEST.form
LOG("PaypalService", DEBUG, param_dict)
param_dict["cmd"] = "_notify-validate"
if param_dict.has_key("service"):
param_dict.pop("service")
param_list = urlencode(param_dict)
paypal_url = self.getLinkUrlString()
request = Request(paypal_url, param_list)
request.add_header("Content-type", "application/x-www-form-urlencoded")
response = urlopen(request)
status = response.read()
method = self._getTypeBasedMethod("reportPaymentStatus")
LOG("PaypalService status", DEBUG, status)
if method and status == "VERIFIED":
method(REQUEST=REQUEST)
return True
\ No newline at end of file
<allowed_content_type_list>
<portal_type id="Paypal Service">
<item>Link</item>
</portal_type>
<portal_type id="Secure Payment Tool">
<item>Paypal Service</item>
</portal_type>
</allowed_content_type_list>
\ No newline at end of file
<property_sheet_list>
<portal_type id="Paypal Service">
<item>PaymentService</item>
<item>PaypalService</item>
</portal_type>
</property_sheet_list>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Type" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_property_domain_dict</string> </key>
<value>
<dictionary>
<item>
<key> <string>short_title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>content_icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Paypal Service</string> </value>
</item>
<item>
<key> <string>init_script</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>permission</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Base Type</string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>PaypalService</string> </value>
</item>
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>domain_name</string> </key>
<value> <string>erp5_content</string> </value>
</item>
<item>
<key> <string>property_name</string> </key>
<value> <string>short_title</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TranslationInformation" module="Products.ERP5Type.TranslationProviderBase"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>domain_name</string> </key>
<value> <string>erp5_content</string> </value>
</item>
<item>
<key> <string>property_name</string> </key>
<value> <string>title</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Property Sheet" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaypalService</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Property Sheet</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="String Attribute Match Constraint" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>message_property_not_set</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>constraint_property</string> </key>
<value>
<tuple>
<string>link_url_string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>link_url_string_constraint</string> </value>
</item>
<item>
<key> <string>message_attribute_match</string> </key>
<value> <string>Paypal URL have to be set</string> </value>
</item>
<item>
<key> <string>message_no_such_property</string> </key>
<value> <string>Paypal URL have to be set</string> </value>
</item>
<item>
<key> <string>message_property_not_set</string> </key>
<value> <string>Paypal URL have to be set</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>String Attribute Match Constraint</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Signature of account</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>service_signature_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: \'\'</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Folder" module="OFS.Folder"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>erp5_paypal_secure_payment</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>"""Redirect user to the path\n
Parameters:\n
redirect_path -- Specify where redirect user, use \'paypal.payment.aborted\' as default"""\n
\n
context.REQUEST.RESPONSE.redirect("%s/%s" % (context.Base_getWebSiteSecureUrl(), \n
redirect_path))\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>redirect_path=\'paypal.payment.aborted\', **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaypalService_abortPayment</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>"""Redirect user to the path\n
Parameters:\n
redirect_path -- Specify where redirect user, use \'paypal.payment.accepted\' as default"""\n
\n
context.REQUEST.RESPONSE.redirect("%s/%s" % (context.Base_getWebSiteSecureUrl(), \n
redirect_path))\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>redirect_path=\'paypal.payment.accepted\', **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaypalService_acceptPayment</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>"""Redirect user to the path\n
Parameters:\n
redirect_path -- Specify where redirect user, use \'paypal.payment.faild\' as default"""\n
\n
context.REQUEST.RESPONSE.redirect("%s/%s" % (context.Base_getWebSiteSecureUrl(), \n
redirect_path))\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>redirect_path=\'paypal.payment.failed\', **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaypalService_failInPayment</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return {}\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>**kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaypalService_getParameterDict</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>"""Call in server side after payment transaction"""\n
# Do nothing by default\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaypalService_reportPaymentStatus</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5Form" module="Products.ERP5Form.Form"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>Base_edit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>bottom</string> </key>
<value>
<list>
<string>listbox</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list>
<string>listbox_int_index</string>
</list>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list>
<string>my_title</string>
<string>my_reference</string>
<string>my_link_url_string</string>
</list>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list>
<string>my_service_username</string>
<string>my_service_password</string>
<string>my_service_signature</string>
</list>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaypalService_view</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>PaypalService_view</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_view</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>update_action_title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>anchor</string>
<string>columns</string>
<string>editable_columns</string>
<string>portal_types</string>
<string>selection_name</string>
<string>sort</string>
<string>title</string>
<string>url_columns</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>anchor</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>int_index</string>
<string>Index</string>
</tuple>
<tuple>
<string>title</string>
<string>Title</string>
</tuple>
<tuple>
<string>translated_id</string>
<string>Coordinate Function</string>
</tuple>
<tuple>
<string>url_string</string>
<string>URL</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>editable_columns</string> </key>
<value>
<list>
<tuple>
<string>int_index</string>
<string>Index</string>
</tuple>
<tuple>
<string>title</string>
<string>Title</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>portal_types</string> </key>
<value>
<list>
<tuple>
<string>Link</string>
<string>Link</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>selection_name</string> </key>
<value> <string>paypal_service_list_selection</string> </value>
</item>
<item>
<key> <string>sort</string> </key>
<value>
<list>
<tuple>
<string>portal_type</string>
<string>Type</string>
</tuple>
<tuple>
<string>int_index</string>
<string>Index</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Coordinates</string> </value>
</item>
<item>
<key> <string>url_columns</string> </key>
<value>
<list>
<tuple>
<string>url_string</string>
<string>Coordinate_asURL</string>
</tuple>
</list>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_int_index</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_int_index</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<tuple>
<string>Products.Formulator.TALESField</string>
<string>TALESMethod</string>
</tuple>
<none/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>here/portal_categories/activity/getCategoryChildTranslatedLogicalPathItemList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_link_url_string</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_link_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Paypal URL</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_reference</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_dialog_mode_reference</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_service_password</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_password</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_service_signature</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Signature</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_service_username</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Username</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_title</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_title</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
##############################################################################
#
# Copyright (c) 2002-2012 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility 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
# guarantees 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
import random
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
def getMessageList(o):
return [str(q.getMessage()) for q in o.checkConsistency()]
class TestERP5PaypalSecurePaymentMixin(ERP5TypeTestCase):
"""
An ERP5 Paypal Secure Payment test case
"""
def getTitle(self):
return "ERP5 Paypal Secure Payment"
def getBusinessTemplateList(self):
"""
Tuple of Business Templates we need to install
"""
return ('erp5_base',
'erp5_secure_payment',
'erp5_paypal_secure_payment')
def afterSetUp(self):
self.portal = self.getPortalObject()
if not self.portal.hasObject('portal_secure_payments'):
self.portal.manage_addProduct['ERP5SecurePayment'].manage_addTool(
'ERP5 Secure Payment Tool', None)
self.tic()
self.service = self.portal.portal_secure_payments.newContent(
portal_type='Paypal Service',
reference="default")
self.tic()
class TestERP5PaypalSecurePaymenConstraint(TestERP5PaypalSecurePaymentMixin):
def _test(self, message, prop, value='12345'):
self.assertTrue(message in getMessageList(self.service))
self.service.edit(**{prop: value})
self.assertFalse(message in getMessageList(self.service))
def test_link_url_string(self):
self._test('Paypal URL have to be set', 'link_url_string')
class TestERP5PaypalSecurePayment(TestERP5PaypalSecurePaymentMixin):
def test_navigate(self):
self.service.edit(
link_url_string='http://paypal/',
service_username="business@sample.com"
)
pt_id = str(random.random())
page_template_text = """<tal:block tal:repeat="value here/field_list">key=<tal:block tal:replace="python: value[0]"/> value=<tal:block tal:replace="python: value[1]"/>
</tal:block>link=<tal:block tal:replace='here/link_url_string'/>
business=<tal:block tal:replace='here/service_username'/>
"""
self.portal.portal_skins.custom.manage_addProduct['PageTemplates']\
.manage_addPageTemplate(id=pt_id, text=page_template_text)
# flush skin cache
self.portal.changeSkin(None)
paypal_dict = {
"return" : "http://ipn/"
}
try:
result = self.service.navigate(page_template=pt_id, paypal_dict=paypal_dict)
self.assertEquals(result, """key=return value=http://ipn/
link=http://paypal/
business=business@sample.com""")
finally:
self.portal.portal_skins.custom.manage_delObjects([pt_id])
# flush skin cache
self.portal.changeSkin(None)
\ No newline at end of file
2012/07/03 Gabriel Monnerat
* Initial version.
\ No newline at end of file
Nexedi SA 2012
\ No newline at end of file
erp5_secure_payment
\ No newline at end of file
Integrate Paypal payment service in ERP5
\ No newline at end of file
GPL
\ No newline at end of file
gabriel
\ No newline at end of file
Paypal Service | view
\ No newline at end of file
PaypalService
\ No newline at end of file
Paypal Service | Link
Secure Payment Tool | Paypal Service
\ No newline at end of file
Paypal Service | PaymentService
Paypal Service | PaypalService
\ No newline at end of file
erp5_paypal_secure_payment
\ No newline at end of file
testERP5PaypalSecurePayment
\ No newline at end of file
erp5_paypal_secure_payment
\ No newline at end of file
5.4.7
\ No newline at end of file
......@@ -79,9 +79,10 @@ if connected_user is not None:\n
# 1- Metadata discovery will be run by alarms with allowed user to access other documents.\n
# 2- A proxy role can not wrap portal_contributions calls and disallow Anonymous user to create the document.\n
tag = \'incoming_web_message\'\n
edit_kw[\'activate_kw\'] = {\'tag\': tag}\n
module.activate(tag=tag, activity=\'SQLQueue\').EventModule_addWebMessage(**edit_kw)\n
\n
# Trig explicitely alarm which will run discoverMetadata on created event, then \n
# Trigger explicitly the alarm which will run discoverMetadata on created event, then \n
# Fill in discoverable properties (sender, recipient, ...) and change workflow states.\n
# XXX hardcoded id, must be picked up by reference and version API\n
portal.portal_alarms.fetch_incoming_web_message_list.activate(after_tag=tag).activeSense()\n
......
1085
\ No newline at end of file
1088
\ No newline at end of file
erp5.util.taskdistribution
--------------------------
Module to access TaskDistributionTool, used to run test on several machines
and aggregating results.
Use pydoc to get module documentation and usage example.
##############################################################################
#
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility 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
# guarantees and support are strongly advised 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 3
# 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.
#
##############################################################################
"""
Client implementation for portal_task_distribution.
Example use:
import erp5.util.taskdistribution
tool = erp5.util.taskdistribution.TaskDistributionTool(...)
test_result = tool.createTestResult(...)
test_result.addWatch('foo', open('foo'))
while True:
test_line = test_result.start()
if not test_line:
break
# Run the test_line.name test
test_line.stop()
"""
import logging
import select
import socket
import threading
import time
import xmlrpclib
__all__ = ['TaskDistributionTool', 'TestResultProxy', 'TestResultLineProxy', 'patchRPCParser']
# Depending on used xmlrpc backend, different exceptions can be thrown.
SAFE_RPC_EXCEPTION_LIST = [socket.error, xmlrpclib.ProtocolError,
xmlrpclib.Fault]
parser, _ = xmlrpclib.getparser()
if xmlrpclib.ExpatParser and isinstance(parser, xmlrpclib.ExpatParser):
SAFE_RPC_EXCEPTION_LIST.append(xmlrpclib.expat.ExpatError)
else:
import sys
print >> sys.stderr, 'Warning: unhandled xmlrpclib parser %r, some ' \
'exceptions might get through safeRpcCall' % (parser, )
del sys
SAFE_RPC_EXCEPTION_LIST = tuple(SAFE_RPC_EXCEPTION_LIST)
del parser, _
def null_callable(*args, **kw):
pass
class NullLogger(object):
def __getattr__(self, name):
return null_callable
null_logger = NullLogger()
def patchRPCParser(error_handler):
"""
Patch xmlrpcmlib's parser class, so it logs data content in case of errors,
to ease debugging.
Warning: this installs a monkey patch on a generic class, so it's last
comes wins. Must *not* be enabled by default.
error_handler (callable)
Receives the erroneous data as first parameter, and the exception
instance as second parameter.
If it returns a false value (ie, handler did not recover from the error),
exception is re-raised.
"""
parser, _ = xmlrpclib.getparser()
parser_klass = parser.__class__
original_feed = parser_klass.feed
def verbose_feed(self, data):
try:
return original_feed(self, data)
except Exception, exc:
if not error_handler(data, exc):
raise
parser_klass.feed = verbose_feed
class RPCRetry(object):
def __init__(self, proxy, retry_time, logger):
super(RPCRetry, self).__init__()
self._proxy = proxy
self._retry_time = retry_time
self._logger = logger
self.__rpc_lock = threading.Lock()
def _RPC(self, func_id, args=()):
with self.__rpc_lock:
return getattr(self._proxy, func_id)(*args)
def _retryRPC(self, func_id, args=()):
retry_time = self._retry_time
while True:
try:
return self._RPC(func_id, args)
except SAFE_RPC_EXCEPTION_LIST:
self._logger.warning('Got exception, retrying: %s%r '
'in %is', func_id, tuple(args), retry_time, exc_info=1)
time.sleep(retry_time)
retry_time *= 1.5
class TestResultLineProxy(RPCRetry):
"""
Represents a single test in a suite.
Properties:
name (str) (ro)
Test name, as provided to TaskDistributionTool.createTestResult .
"""
def __init__(self, proxy, retry_time, logger, test_result_line_path,
test_name):
super(TestResultLineProxy, self).__init__(proxy, retry_time, logger)
self._test_result_line_path = test_result_line_path
self._name = test_name
def __repr__(self):
return '<%s(%r, %r) at %x>' % (self.__class__.__name__,
self._test_result_line_path, self._name, id(self))
@property
def name(self):
return self._name
def stop(self, test_count=None, error_count=None, failure_count=None,
skip_count=None, duration=None, date=None, command=None,
stdout=None, stderr=None, html_test_result=None):
"""
Notify server of test completion.
Without any parameter, notifies of a test failure which prevents any
precise reading (step count, how many succeeded, etc).
"""
status_dict = {
'test_count': test_count,
'error_count': error_count,
'failure_count': failure_count,
'skip_count': skip_count,
'duration': duration,
'date': date,
}
if command is not None:
status_dict['command'] = command
if stdout is not None:
status_dict['stdout'] = stdout
if stderr is not None:
status_dict['stderr'] = stderr
if html_test_result is not None:
status_dict['html_test_result'] = html_test_result
self._retryRPC('stopUnitTest', (self._test_result_line_path,
status_dict))
class TestResultProxy(RPCRetry):
"""
Represents a test suite run.
Allows fetching work to do (eg a single test in an entire run), monitoring
log files, informing server of problems and monitoring server-side
cancellation.
Properties
watcher_period (float) (rw)
How long log watcher sleeps between successive uploading latest data
chunks.
revision (str) (ro)
Revision to test. Might be different from the revision requested, when a
test batch is running on an older revision.
"""
_watcher_can_run = True
_watcher_thread = None
def __init__(self, proxy, retry_time, logger, test_result_path, node_title,
revision):
super(TestResultProxy, self).__init__(proxy, retry_time, logger)
self._test_result_path = test_result_path
self._node_title = node_title
self._revision = revision
self._watcher_period = 60
self._watcher_dict = {}
self._watcher_condition = threading.Condition()
def __repr__(self):
return '<%s(%r, %r, %r) at %x>' % (self.__class__.__name__,
self._test_result_path, self._node_title, self._revision, id(self))
@property
def revision(self):
return self._revision
def start(self, exclude_list=()):
"""
Ask for a test to run, among the list of tests composing this test
result.
Return an TestResultLineProxy instance, or None if there is nothing to
do.
"""
result = self._retryRPC('startUnitTest', (self._test_result_path,
exclude_list))
if result:
line_url, test_name = result
result = TestResultLineProxy(self._proxy, self._retry_time,
self._logger, line_url, test_name)
return result
def reportFailure(self, date=None, command=None, stdout=None, stderr=None):
"""
Report a test-node-level problem, preventing the test from continuing
on this node.
"""
self._stopWatching()
status_dict = {
'date': date,
}
if command is not None:
status_dict['command'] = command
if stdout is not None:
status_dict['stdout'] = stdout
if stderr is not None:
status_dict['stderr'] = stderr
self._retryRPC('reportTaskFailure', args=(self._test_result_path,
status_dict, self._node_title))
def reportStatus(self, command, stdout, stderr):
"""
Report some progress.
Used internally by file monitoring, you shouldn't have to use this
directly.
"""
try:
self._RPC('reportTaskStatus', (self._test_result_path, {
'command': command,
'stdout': stdout,
'stderr': stderr,
}, self._node_title))
except SAFE_RPC_EXCEPTION_LIST:
self._logger.warning('Got exception in reportTaskStatus, giving up',
exc_info=1)
def isAlive(self):
"""
Tell if test is still alive on site.
Useful to probe for test cancellation by user, so a new test run can
be started without waiting for current one to finish.
"""
try:
return self._RPC('isTaskAlive', (self._test_result_path, ))
except SAFE_RPC_EXCEPTION_LIST:
self._logger.warning('Got exception in isTaskAlive, assuming alive',
exc_info=1)
return 1
@property
def watcher_period(self):
return self._watcher_period
@watcher_period.setter
def watcher_period(self, period):
cond = self._watcher_condition
with cond:
self._watcher_period = period
cond.notify()
def addWatch(self, name, stream, max_history_bytes=None):
"""
Monitor given file, sending a few latest lines to remote server.
name (any)
Arbitrary identifier for stream. Must be usable as a dict key.
stream (file object)
File to monitor from its current offset.
max_history_bytes (int, None)
How many bytes to send to remote server at most for each wakeup.
If None, send all lines.
"""
watcher_dict = self._watcher_dict
if not watcher_dict:
self._startWatching()
elif name in watcher_dict:
raise ValueError('Name already known: %r' % (name, ))
watcher_dict[name] = (stream, max_history_bytes)
def removeWatch(self, name):
"""
Stop monitoring given stream.
"""
watcher_dict = self._watcher_dict
del watcher_dict[name]
if not watcher_dict:
self._stopWatching()
def _startWatching(self):
if self._watcher_thread is not None:
raise ValueError('Thread already started')
self._watcher_thread = thread = threading.Thread(target=self._watcher)
thread.daemon = True
thread.start()
def _watcher(self):
cond = self._watcher_condition
while self._watcher_can_run and self.isAlive():
working = time.time()
caption_list = []
append = caption_list.append
for name, (stream, max_history_bytes) in \
self._watcher_dict.iteritems():
append('==> %s <==' % (name, ))
start = stream.tell()
stream.seek(0, 2)
end = stream.tell()
if start == end:
caption = time.strftime(
'(no new lines at %Y/%m/%d %H:%M:%S)', time.gmtime())
else:
to_read = end - start
if to_read < 0:
# File got truncated, treat the whole content as new.
to_read = end
if max_history_bytes is not None:
to_read = min(to_read, max_history_bytes)
stream.seek(-to_read, 1)
caption = stream.read(to_read)
append(caption)
self.reportStatus('', '\n'.join(caption_list), '')
with cond:
cond.wait(max(self._watcher_period - (working - time.time()),
0))
def _stopWatching(self):
cond = self._watcher_condition
with cond:
self._watcher_can_run = False
cond.notify()
self._watcher_thread.join()
class TaskDistributionTool(RPCRetry):
def __init__(self, portal_url, retry_time=64, logger=None):
"""
portal_url (str, None)
Portal URL of ERP5 site to use as a task distributor.
If None, single node setup is assumed.
"""
if logger is None:
logger = null_logger
if portal_url is None:
proxy = DummyTaskDistributionTool()
else:
proxy = xmlrpclib.ServerProxy(
portal_url,
allow_none=True,
).portal_task_distribution
super(TaskDistributionTool, self).__init__(proxy, retry_time, logger)
protocol_revision = self._retryRPC('getProtocolRevision')
if protocol_revision != 1:
raise ValueError('Unsupported protocol revision: %r',
protocol_revision)
def createTestResult(self, revision, test_name_list, node_title,
allow_restart=False, test_title=None, project_title=None):
"""
(maybe) create a new test run.
revision (str)
An opaque string describing code being tested.
test_name_list (list of str)
List of tests being part of this test run. May be empty.
node_title (str)
Human-readable test node identifier, so an adnmin can know which
node does what.
allow_restart (bool)
When true, a tet result is always created, even if a former finished
one is found for same name and revision pair.
test_title (str)
Human-readable title for test. Must be identical for successive runs.
Allows browsing its result history.
project_title (str)
Existing project title, so test result gets associated to it.
Returns None if no test run is needed (a test run for given name and
revision has already been completed).
Otherwise, returns a TestResultProxy instance.
"""
result = self._retryRPC('createTestResult', ('', revision,
test_name_list, allow_restart, test_title, node_title,
project_title))
if result:
test_result_path, revision = result
result = TestResultProxy(self._proxy, self._retry_time,
self._logger, test_result_path, node_title, revision)
return result
class DummyTaskDistributionTool(object):
"""
Fake remote server.
Useful when willing to locally run all tests without reporting to any
server.
This class should remain internal to this module.
"""
test_name_list = None
def __init__(self):
self._lock = threading.Lock()
def getProtocolRevision(self):
return 1
def createTestResult(self, name, revision, test_name_list, *args):
self.test_name_list = test_name_list[:]
return None, revision
def startUnitTest(self, test_result_path, exclude_list=()):
with self._lock:
for i, test in enumerate(self.test_name_list):
if test not in exclude_list:
del self.test_name_list[i]
return None, test
def stopUnitTest(self, *args):
pass
reportTaskFailure = reportTaskStatus = stopUnitTest
def isTaskAlive(self, *args):
return int(bool(self.test_name_list))
......@@ -777,7 +777,8 @@ class MainForm(Form):
@todo: Use information sent back as headers rather than looking
into the page content?
"""
if 'Logged In as' in self.browser.contents:
check_logged_in_xpath = '//div[@id="logged_in_as"]/*'
if self.etree.xpath(check_logged_in_xpath):
self._logger.debug("Already logged in")
# TODO: Perhaps zope.testbrowser should be patched instead?
self.browser.timer.start_time = self.browser.timer.end_time = 0
......@@ -797,7 +798,7 @@ class MainForm(Form):
self.browser.open('login_form')
login(self.browser.mainForm)
if 'Logged In as' not in self.browser.contents:
if not self.etree.xpath(check_logged_in_xpath):
raise LoginError("%s: Could not log in as '%s:%s'" % \
(self.browser._erp5_base_url,
self.browser._username,
......
......@@ -54,6 +54,7 @@ from zExceptions import ExceptionFormatter
from BTrees.OIBTree import OIBTree
from Zope2 import app
from Products.ERP5Type.UnrestrictedMethod import PrivilegedUser
from zope.site.hooks import setSite
try:
from Products import iHotfix
......@@ -306,6 +307,8 @@ class Message(BaseMessage):
self.setExecutionState(MESSAGE_NOT_EXECUTABLE, exc_info,
context=activity_tool)
else:
# Store site info
setSite(activity_tool.getParentValue())
if activity_tool.activity_timing_log:
result = activity_timing_method(method, self.args, self.kw)
else:
......
......@@ -716,7 +716,7 @@ class SimulationMovement(PropertyRecordableMixin, Movement, ExplainableMixin):
catalog_simulation_movement_list = portal_catalog(
portal_type='Simulation Movement',
causality_uid=[p.getUid() for p in remaining_path_set],
path='%s/%%' % self.getPath())
path='%s/%%' % self.getPath().replace('_', r'\_'))
for movement in catalog_simulation_movement_list:
path = movement.getCausalityValue()
......
......@@ -137,7 +137,7 @@ class ExplanationCache:
if not isinstance(value, dict):
# We have a real root
result.append('%s/%s' % (prefix, key))
result.append('%s/%s/%%' % (prefix, key))
result.append(('%s/%s/%%' % (prefix, key)).replace('_', r'\_'))
# XXX-JPS here we must add all parent movements XXX-JPS
else:
browsePathDict('%s/%s' % (prefix, key), value) # Recursing with string append is slow XXX-JPS
......@@ -262,7 +262,7 @@ class ExplanationCache:
if simulation_path.startswith(path):
# Only keep a path pattern which matches current simulation movement
path_set.add(path)
path_set.add("%s/%%" % path)
path_set.add("%s/%%" % path.replace('_', r'\_'))
# Lookup in cache based on path_tuple
path_tuple = tuple(path_set) # XXX-JPS is the order guaranteed here ?
......
......@@ -58,7 +58,7 @@ follow_up_related_document_list = portal_catalog(\n
portal_type=portal_type,\n
follow_up_uid=context.getUid(), **kw)\n
\n
kw[\'query\'] = Query(relative_url=\'%s/%%\' % context.getRelativeUrl())\n
kw[\'query\'] = Query(relative_url=\'%s/%%\' % context.getRelativeUrl().replace(\'_\', r\'\\_\'))\n
if follow_up_related_document_list:\n
kw[\'query\'] = ComplexQuery(\n
kw[\'query\'],\n
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string># Do not re-index security recursively if contained objects don\'t acquire roles\n
#\n
# After all, recursively re-indexing a module in a production system\n
# with lots of content could mean hours of non-usable overloaded system.\n
type_tool = context.getPortalObject().portal_types \n
for portal_type_name in context.getTypeInfo().getTypeAllowedContentTypeList():\n
portal_type = type_tool[portal_type_name]\n
if portal_type.getTypeAcquireLocalRole():\n
reindex = context.recursiveReindexObject\n
break\n
else:\n
reindex = context.reindexObject\n
\n
return reindex(*args, **kw)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>*args, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_reindexObjectSecurity</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
41040
\ No newline at end of file
41042
\ No newline at end of file
......@@ -1609,6 +1609,7 @@ class TestCRMMailSend(BaseTestCRM):
self.assertEquals(event.getSourceSection(), user.getSubordination())
finally:
# clean up created roles on portal_types
self.login() # admin
for portal_type in portal_type_list:
portal_type_object = getattr(self.portal.portal_types, portal_type)
portal_type_object._delObject('manager_role')
......
......@@ -27,6 +27,7 @@
##############################################################################
import unittest
import transaction
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
......@@ -34,6 +35,7 @@ from Products.ERP5Type.tests.Sequence import SequenceList
from Products.ERP5Type.tests.utils import createZODBPythonScript
from Products.ERP5.tests.testInvoice import TestSaleInvoiceMixin
from Products.ERP5.tests.utils import newSimulationExpectedFailure
from Products.ERP5Type.tests.backportUnittest import expectedFailure
class TestNestedLineMixin(TestSaleInvoiceMixin):
......@@ -323,7 +325,31 @@ class TestNestedLine(TestNestedLineMixin, ERP5TypeTestCase):
self.assertEquals(self.new_invoice_quantity, document.getTotalQuantity())
self.assertEquals(self.new_invoice_quantity, line_line.getQuantity())
def stepPrioritizeInvoiceUpdateCausalityStateTic(self, sequence):
invoice = sequence['invoice']
invoice_path = invoice.getPhysicalPath()
prioritize_uid_list = []
def stop_condition(message_list):
for message in message_list:
if (message.object_path == invoice_path and
message.method_id == 'updateCausalityState'):
prioritize_uid_list.append(message.uid)
return True
return False
self.tic(stop_condition=stop_condition)
update_causality_message_uid, = prioritize_uid_list
# make all other messages have less priority:
for table in 'message', 'message_queue':
self.portal.cmf_activity_sql_connection.manage_test("""
update %s
set priority=200
where uid <> %s
""" % (table, update_causality_message_uid))
transaction.commit()
self.stepTic(sequence)
@newSimulationExpectedFailure
@expectedFailure
def test_04_MergingMultipleSaleOrders(self, quiet=quiet):
sequence_list = SequenceList()
sequence = sequence_list.addSequenceString(self.DEFAULT_SEQUENCE + \
......@@ -355,9 +381,10 @@ class TestNestedLine(TestNestedLineMixin, ERP5TypeTestCase):
stepStartPackingList
stepCheckInvoicingRule
stepTic
stepPrioritizeInvoiceUpdateCausalityStateTic
stepCheckInvoiceIsDivergent
stepCheckInvoiceIsDiverged
stepAdoptPrevisionInvoiceQuantity
stepTic
"""
......
......@@ -28,6 +28,7 @@
##############################################################################
import unittest
import transaction
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase,\
_getConversionServerDict
......@@ -146,7 +147,7 @@ class TestERP5WebWithCRM(ERP5TypeTestCase):
form_kw['source_organisation_title'])
def test_02_Contact_Us_with_Aunthenticated_user(self):
"""Test creation of Web Message with Authenticted User
"""Test creation of Web Message with Authenticated User
"""
web_section = self.setupWebSection()
self.logout()
......@@ -159,6 +160,34 @@ class TestERP5WebWithCRM(ERP5TypeTestCase):
'text_content': 'I want ERP5 for my company',
}
web_section.WebSection_addWebMessage(**form_kw)
transaction.commit()
# here we check a random bug caused by the ordering of activities
should_stop = [None]
event_module_path_prefix = self.portal.event_module.getPath() + '/'
deprioritize_message_list = []
# we'll stop whenever we find the message that reindex the newly created
# event object
def stop_condition(message_list):
for message in message_list:
object_path = '/'.join(message.object_path)
if (message.method_id == 'immediateReindexObject' and
object_path.startswith(event_module_path_prefix)):
deprioritize_message_list.append(message)
return True
return False
self.tic(stop_condition=stop_condition)
web_message_reindex_message, = deprioritize_message_list
web_message_path = web_message_reindex_message.object_path
self.assertTrue(
self.portal.unrestrictedTraverse(web_message_path).getPortalType(),
'Web Message',
)
# we'll deprioritize this message, so it executes last of all
self.portal.cmf_activity_sql_connection.manage_test("""
update message set priority=100
where uid=%s
""" % web_message_reindex_message.uid)
transaction.commit()
self.tic()
self.logout()
......
......@@ -51,7 +51,8 @@ class TestOrderMixin(SubcontentReindexingWrapper):
order_cell_portal_type = 'Sale Order Cell'
applied_rule_portal_type = 'Applied Rule'
simulation_movement_portal_type = 'Simulation Movement'
datetime = DateTime()
# see comment about self.datetime on afterSetUp() below
datetime = DateTime() - 2
packing_list_portal_type = 'Sale Packing List'
packing_list_line_portal_type = 'Sale Packing List Line'
packing_list_cell_portal_type = 'Sale Packing List Cell'
......@@ -94,15 +95,28 @@ class TestOrderMixin(SubcontentReindexingWrapper):
preference.enable()
self.tic()
def afterSetUp(self, quiet=1, run=1):
def afterSetUp(self):
# XXX-Leo: cannot call super here, because other classes call
# SuperClass.afterSetUp(self) directly... this needs to be cleaned
# up, including consolidating all conflicting definitions of
# .createCategories()
#super(TestOrderMixin, self).afterSetUp()
self.login()
portal = self.getPortal()
self.category_tool = self.getCategoryTool()
portal_catalog = self.getCatalogTool()
#portal_catalog.manage_catalogClear()
self.createCategories()
self.validateRules()
self.setUpPreferences()
# pin datetime on the day before yesterday, to make sure that:
#
# 1. All calculations are done relative to the same time
# 2. We don't get random failures when tests run close to midnight
self.pinDateTime(self.datetime)
def beforeTearDown(self):
self.unpinDateTime()
super(TestOrderMixin, self).beforeTearDown()
def createCurrency(self):
currency_module = self.getPortal().currency_module
......
......@@ -32,6 +32,8 @@
import unittest
import transaction
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.utils import createZODBPythonScript
from AccessControl.SecurityManagement import newSecurityManager
......@@ -476,16 +478,21 @@ class TestLocalRoleManagement(ERP5TypeTestCase):
),)
""")
# configure group, site, function categories
category_tool = self.getCategoryTool()
for bc in ['group', 'site', 'function']:
base_cat = self.getCategoryTool()[bc]
base_cat = category_tool[bc]
code = bc[0].upper()
if base_cat.get('subcat', None) is not None:
continue
base_cat.newContent(portal_type='Category',
id='subcat',
codification="%s1" % code)
# add another function subcategory.
self.getCategoryTool()['function'].newContent(portal_type='Category',
id='another_subcat',
codification='F2')
function_category = category_tool['function']
if function_category.get('another_subcat', None) is None:
function_category.newContent(portal_type='Category',
id='another_subcat',
codification='F2')
self.defined_category = "group/subcat\n"\
"site/subcat\n"\
"function/subcat"
......@@ -503,11 +510,13 @@ class TestLocalRoleManagement(ERP5TypeTestCase):
site='subcat',
function='subcat' )
assignment.open()
self.person = pers
self.tic()
def beforeTearDown(self):
"""Called before teardown."""
# clear base categories
self.person.getParentValue().manage_delObjects([self.person.getId()])
for bc in ['group', 'site', 'function']:
base_cat = self.getCategoryTool()[bc]
base_cat.manage_delObjects(list(base_cat.objectIds()))
......@@ -921,6 +930,39 @@ class TestLocalRoleManagement(ERP5TypeTestCase):
(((cloning_owner_id), ('Owner',)),)
)
def _checkMessageMethodIdList(self, expected_method_id_list):
actual_method_id_list = sorted([
message.method_id
for message in self.portal.portal_activities.getMessageList()
])
self.assertEqual(expected_method_id_list, actual_method_id_list)
def test_reindexObjectSecurity_on_modules(self):
person_module = self.portal.person_module
portal_activities = self.portal.portal_activities
check = self._checkMessageMethodIdList
check([])
# We need at least one person for this test.
self.assertTrue(len(person_module.keys()))
# When we update security of a module...
person_module.reindexObjectSecurity()
transaction.commit()
# we don't want all underlying objects to be recursively
# reindexed. After all, its contents do not acquire local roles.
check(['immediateReindexObject'])
self.tic()
check([])
# But non-module objects, with subobjects that acquire local
# roles, should reindex their security recursively:
person, = [rec.getObject()
for rec in person_module.searchFolder(reference=self.username)]
self.assertTrue(len(person.objectIds()))
person.reindexObjectSecurity()
transaction.commit()
check(['recursiveImmediateReindexObject'])
self.tic()
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestUserManagement))
......
......@@ -86,6 +86,7 @@ from Products.ERP5Type.Accessor.TypeDefinition import asDate
from Products.ERP5Type.Message import Message
from Products.ERP5Type.ConsistencyMessage import ConsistencyMessage
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5Type.dynamic.import_lock import ImportLock
from zope.interface import classImplementsOnly, implementedBy
......@@ -710,7 +711,7 @@ class Base( CopyContainer,
isTempDocument = ConstantGetter('isTempDocument', value=False)
# Dynamic method acquisition system (code generation)
aq_method_lock = threading.RLock()
aq_method_lock = ImportLock()
aq_method_generated = set()
aq_method_generating = []
aq_portal_type = {}
......
......@@ -1253,10 +1253,11 @@ class Folder(CopyContainer, CMFBTreeFolder, CMFHBTreeFolder, Base, FolderMixIn):
def reindexObjectSecurity(self, *args, **kw):
"""
Reindex security-related indexes on the object
(and its descendants).
"""
# In ERP5, simply reindex all objects.
self.recursiveReindexObject(*args, **kw)
# In ERP5, simply reindex all objects, recursively by default.
reindex = self._getTypeBasedMethod('reindexObjectSecurity',
'recursiveReindexObject')
reindex(*args, **kw)
security.declarePublic( 'recursiveReindexObject' )
def recursiveReindexObject(self, activate_kw=None, **kw):
......
......@@ -71,6 +71,7 @@ from Products.ERP5Type.patches import ExternalMethod
from Products.ERP5Type.patches import User
from Products.ERP5Type.patches import zopecontenttype
from Products.ERP5Type.patches import OFSImage
from Products.ERP5Type.patches import default_zpublisher_encoding
# These symbols are required for backward compatibility
from Products.ERP5Type.patches.PropertyManager import ERP5PropertyManager
......
......@@ -29,7 +29,7 @@
from types import ModuleType
import sys
import threading
from Products.ERP5Type.dynamic.import_lock import ImportLock
class DynamicModule(ModuleType):
"""This module may generate new objects at runtime."""
......@@ -41,7 +41,7 @@ class DynamicModule(ModuleType):
def __init__(self, name, factory, doc=None):
super(DynamicModule, self).__init__(name, doc=doc)
self._factory = factory
self._lock = threading.RLock()
self._lock = ImportLock()
def __getattr__(self, name):
if name[:2] == '__':
......
# -*- coding: utf-8 -*-
##############################################################################
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility 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
# guarantees and support are strongly advised 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
import imp
class ImportLock(object):
"""
This class provides the interpreter's import lock.
It is intended to use in ERP5Type.dynamic to avoid possible dead lock.
It can be used in two ways :
1) 'with' statement
lock = ImportLock()
with lock:
...
2) traditional 'try' and 'finally'
lock = ImportLock()
lock.acquire()
try:
...
finally:
lock.release()
"""
def __enter__(self):
imp.acquire_lock()
def __exit__(self, type, value, tb):
imp.release_lock()
def acquire(self):
imp.acquire_lock()
def release(self):
imp.release_lock()
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility 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
# guarantees 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
import ZPublisher.HTTPRequest
# Force (do not depend on) the default-zpublisher-encoding setting of zope.conf
ZPublisher.HTTPRequest.default_encoding = 'utf-8'
......@@ -26,6 +26,7 @@ from hashlib import md5
from warnings import warn
from ExtensionClass import pmc_init_of
from ZTUtils import make_query
from DateTime import DateTime
# XXX make sure that get_request works.
import Products.ERP5Type.Utils
......@@ -275,6 +276,21 @@ def profile_if_environ(environment_var_name):
# No profiling, return identity decorator
return lambda self, method: method
# Patch DateTime to allow pinning the notion of "now".
assert getattr(DateTime, '_original_parse_args', None) is None
DateTime._original_parse_args = DateTime._parse_args
_pinned_date_time = None
def _parse_args(self, *args, **kw):
if _pinned_date_time is not None and (not args or args[0] == None):
# simulate fixed "Now"
args = (_pinned_date_time,) + args[1:]
return self._original_parse_args(*args, **kw)
_parse_args._original = DateTime._original_parse_args
DateTime._parse_args = _parse_args
class ERP5TypeTestCaseMixin(ProcessingNodeTestCase, PortalTestCase):
"""Mixin class for ERP5 based tests.
"""
......@@ -354,6 +370,17 @@ class ERP5TypeTestCaseMixin(ProcessingNodeTestCase, PortalTestCase):
cls.__bases__ = cls.__bases__[1:]
pmc_init_of(cls)
def pinDateTime(self, date_time):
# pretend time has stopped at a certain date (i.e. the test runs
# infinitely fast), to avoid errors on tests that are started
# just before midnight.
global _pinned_date_time
assert date_time is None or isinstance(date_time, DateTime)
_pinned_date_time = date_time
def unpinDateTime(self):
self.pinDateTime(None)
def getDefaultSitePreferenceId(self):
"""Default id, usefull method to override
"""
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility 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
# guarantees 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
import unittest
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.utils import createZODBPythonScript
from Persistence import PersistentMapping
from zope.site.hooks import setSite
class TestLocalizer(ERP5TypeTestCase):
def afterSetUp(self):
self.message_catalog = self.portal.Localizer.erp5_ui
if 'fr' not in self.message_catalog.get_available_languages():
self.message_catalog.add_language('fr')
self.message_catalog._messages.clear()
def beforeTearDown(self):
tmp_obj = getattr(self, 'tmp_obj', None)
if tmp_obj is not None:
tmp_obj.aq_parent.manage_delObjects(ids=[tmp_obj.getId(),])
self.tic()
def test_non_ascii_msgid(self):
self.assertEqual(self.portal.Base_translateString('This is 1€.', lang='fr'),
"This is 1€.")
# newly created key should be unicode.
self.assertFalse('This is 1€.' in self.message_catalog._messages)
self.assertTrue(u'This is 1€.' in self.message_catalog._messages)
self.message_catalog.message_edit(u'This is 1€.', 'fr', u"C'est 1€.", '')
self.assertEqual(self.portal.Base_translateString('This is 1€.', lang='fr'),
"C'est 1€.")
self.assertFalse('This is 1€.' in self.message_catalog._messages)
self.assertTrue(u'This is 1€.' in self.message_catalog._messages)
def test_migrated_non_ascii_msgid(self):
# register str key to simulate existing message that was already
# created by old Localizer.
self.message_catalog._messages['This is 1€.'] = PersistentMapping(
{'fr':"C'est 1€.", 'note':'',})
self.assertEqual(self.portal.Base_translateString('This is 1€.', lang='fr'),
"C'est 1€.")
# translate() should not create a unicode key if str key already exists.
self.assertTrue('This is 1€.' in self.message_catalog._messages)
self.assertFalse(u'This is 1€.' in self.message_catalog._messages)
self.message_catalog.message_edit(u'This is 1€.', 'fr', u"Ceci est 1€.", '')
self.assertEqual(self.portal.Base_translateString('This is 1€.', lang='fr'),
"Ceci est 1€.")
# message_edit() should not create a unicode key if str key already exists.
self.assertTrue('This is 1€.' in self.message_catalog._messages)
self.assertFalse(u'This is 1€.' in self.message_catalog._messages)
def test_non_ascii_mapping(self):
self.assertEqual(self.portal.Base_translateString('This is 1${currency}.', lang='fr',
mapping={'currency':'€'}),
"This is 1€.")
self.message_catalog.message_edit(u'This is 1${currency}.', 'fr', u"C'est 1${currency}.", '')
self.assertEqual(self.portal.Base_translateString('This is 1${currency}.', lang='fr',
mapping={'currency':'€'}),
"C'est 1€.")
def test_non_literal_mapping(self):
self.assertEqual(self.portal.Base_translateString('This is ${obj}.', lang='fr',
mapping={'obj':[1,2]}),
"This is [1, 2].")
self.message_catalog.message_edit(u'This is ${obj}.', 'fr', u"C'est ${obj}.", '')
self.assertEqual(self.portal.Base_translateString('This is ${obj}.', lang='fr',
mapping={'obj':[1,2]}),
"C'est [1, 2].")
def test_import_migrated_non_ascii_msgid(self):
# register str key to simulate existing message that was already
# created by old Localizer.
self.message_catalog._messages['This is 1€.'] = PersistentMapping(
{'fr':"C'est 1€.", 'note':'',})
self.message_catalog.po_import(
'fr',
'msgid "This is 1€."\nmsgstr "Ceci est 1€."')
self.assertEqual(self.portal.Base_translateString('This is 1€.', lang='fr'),
"Ceci est 1€.")
# po_import() converts existing str key to unicode key.
self.assertFalse('This is 1€.' in self.message_catalog._messages)
self.assertTrue(u'This is 1€.' in self.message_catalog._messages)
def test_localizer_transle_in_activity(self):
self.assertEqual(self.portal.Base_translateString('This is 1€.', lang='fr'),
"This is 1€.")
self.message_catalog.message_edit(u'This is 1€.', 'fr', u"C'est 1€.", '')
skin = self.portal.portal_skins.custom
createZODBPythonScript(
skin, 'test_activity', '',
"context.setComment(context.Base_translateString('This is 1€.', lang='fr'))",
)
tmp_obj = self.portal.portal_templates.newContent()
self.tic()
tmp_obj.activate().test_activity()
# here we don't call self.tic() that calls self.getPortal() that
# reinvoke setSite(portal).
setSite()
self.commit()
while self.portal.portal_activities.getMessageList():
self.portal.portal_activities.process_timer(None, None)
self.assertEquals(tmp_obj.getComment(), "C'est 1€.")
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestLocalizer))
return suite
......@@ -63,13 +63,13 @@ def md5text(str):
return md5(str.encode('utf-8')).hexdigest()
def to_unicode(x, encoding=HTTPRequest.default_encoding):
def to_unicode(x, encoding=None):
"""In Zope the ISO-8859-1 encoding has an special status, normal strings
are considered to be in this encoding by default.
"""
if isinstance(x, unicode):
return x
return unicode(x, encoding)
if isinstance(x, str):
return unicode(x, encoding or HTTPRequest.default_encoding)
return unicode(x)
def to_str(x):
......@@ -193,6 +193,11 @@ class MessageCatalog(LanguageManager, ObjectManager, SimpleItem):
target_language=None, default=None):
""" """
msgstr = self.gettext(msgid, lang=target_language, default=default)
# BBB support str in mapping by converting to unicode for
# backward compatibility.
if mapping:
mapping = dict([to_unicode(k), to_unicode(v)]
for k, v in mapping.iteritems())
return interpolate(msgstr, mapping)
......@@ -262,7 +267,7 @@ class MessageCatalog(LanguageManager, ObjectManager, SimpleItem):
If a default is provided, use it instead of the message id
as a translation for unknown messages.
"""
if not isinstance(message, (str, unicode)):
if not isinstance(message, basestring):
raise TypeError, 'only strings can be translated.'
message = message.strip()
......@@ -633,9 +638,15 @@ class MessageCatalog(LanguageManager, ObjectManager, SimpleItem):
msgid = to_unicode(entry.msgid, encoding=encoding)
if msgid:
msgstr = to_unicode(entry.msgstr or '', encoding=encoding)
if not messages.has_key(msgid):
messages[msgid] = PersistentMapping()
messages[msgid][lang] = msgstr
translation_map = messages.get(msgid)
if translation_map is None:
# convert old non-unicode translations if they exist:
translation_map = messages.pop(self.get_message_key(msgid),
None)
if translation_map is None:
translation_map = PersistentMapping()
messages[msgid] = translation_map
translation_map[lang] = msgstr
# Set the encoding (the full header should be loaded XXX)
self.update_po_header(lang, charset=encoding)
......
......@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
import glob
import os
version = '0.4.3'
version = '0.4.5'
name = 'erp5.util'
long_description = open("README.erp5.util.txt").read() + "\n"
......
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